2017-12-28 21 views
3

私はJsonConvert SerializeXmlNodeを使用してxmlをjsonに変換しています。文字列でC#のオブジェクトにJSONをデシリアライズしようとしたとき、私は例外を取得しています - 私が直面してる問題は、私は時々価値を持って、時にはC#JsonConvert SerializeXmlNode属性が空です

<AustrittDatum>2018-01-31+01:00</AustrittDatum> 
... 
<AustrittDatum xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> 

、結果としてnullをすることができ、タグを持っているということですプロパティ "AustrittDatum" - "Newtonsoft.Json.JsonReaderException: '文字列の読み込み中にエラーが発生しました。予期しないトークン:StartObject。Path' AustrittDatum '。' 」、

<AustrittDatum xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:nil="true"/> 

は、どのように私はこの"AustrittDatum": ""または多分THERのようなものにするためにそれを強制することができ

"AustrittDatum": { 
    "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", 
    "@xsi:nil": "true" 
}, 

にシリアル化されるので、それを解決するためにいくつかの適切な方法は何ですか?

答えて

1

xsi:nil="true"というXML要素に遭遇した場合、Json.NETのXmlNodeConverterは、null JTokenではなく、表示する属性を持つJSONオブジェクトを作成しているようです。

  • Elementsは変わらない

    Converstionルール:これはNewtonsoftのドキュメントページConverting between JSON and XMLと一致しています。

  • アトリビュートの先頭には@が付いていて、オブジェクトの先頭にある必要があります。
  • 単一の子テキストノードは、要素に対して直接的な値です。そうでない場合は#textでアクセスされます。
  • XML宣言および処理命令の先頭に?が付いています。
  • 文字データ、コメント、空白および重要な空白ノードは、それぞれ#cdata-section、#comment、#whitespaceおよび#significant-whitespaceでアクセスされます。
  • 同じレベルに同じ名前の複数のノードがグループ化され、アレイにまとめられます。
  • 空の要素はnullです。

JSONから作成されたXMLは、あなたが望むものと一致しない場合、あなたはそれを手動で変換する必要があります...

それにもかかわらず、xsi:nil="true"を持つ要素が変換されるだろうと考えるのは合理的ですxsi:nilpredefined w3c attributeであるため、nullのJSON値に変更してください。おそらくNewtonsoftは、そのような要素が追加の属性を持ち、その要素がnullに変換されると失われる可能性があるため、これを実行しませんでした。

あなたが好きな場合は、XmlNodeConverterためenhancement requestを提出できましたが、その間に次の拡張メソッドがJToken階層形式の後処理やJSON値をゼロにするために、以前nil要素だったのオブジェクトに変換します:

public static class JTokenExtensions 
{ 
    const string XsiNamespace = @"http://www.w3.org/2001/XMLSchema-instance"; 
    readonly static string XmlNullValue = System.Xml.XmlConvert.ToString(true); 

    public static JToken ReplaceXmlNilObjectsWithNull(this JToken root) 
    { 
     return root.ReplaceXmlNilObjects(t => JValue.CreateNull()); 
    } 

    public static JToken ReplaceXmlNilObjects(this JToken root, Func<JToken, JToken> getReplacement) 
    { 
     var query = from obj in root.DescendantsAndSelf().OfType<JObject>() 
        where obj.Properties().Any(p => p.IsNilXmlTrueProperty()) 
        select obj; 
     foreach (var obj in query.ToList()) 
     { 
      var replacement = getReplacement(obj); 
      if (obj == root) 
       root = replacement; 
      if (obj.Parent != null) 
       obj.Replace(replacement); 
     } 
     return root; 
    } 

    static IEnumerable<JToken> DescendantsAndSelf(this JToken node) 
    { 
     // Small wrapper adding this method to all JToken types. 
     if (node == null) 
      return Enumerable.Empty<JToken>(); 
     var container = node as JContainer; 
     if (container != null) 
      return container.DescendantsAndSelf(); 
     else 
      return new[] { node }; 
    } 

    static string GetXmlNamespace(this JProperty prop) 
    { 
     if (!prop.Name.StartsWith("@")) 
      return null; 
     var index = prop.Name.IndexOf(":"); 
     if (index < 0 || prop.Name.IndexOf(":", index+1) >= 0) 
      return null; 
     var ns = prop.Name.Substring(1, index - 1); 
     if (string.IsNullOrEmpty(ns)) 
      return null; 
     var nsPropertyName = "@xmlns:" + ns; 
     foreach (var obj in prop.AncestorsAndSelf().OfType<JObject>()) 
     { 
      var nsProperty = obj[nsPropertyName]; 
      if (nsProperty != null && nsProperty.Type == JTokenType.String) 
       return (string)nsProperty; 
     } 
     return null; 
    } 

    static bool IsNilXmlTrueProperty(this JProperty prop) 
    { 
     if (prop == null) 
      return false; 
     if (!(prop.Value.Type == JTokenType.String && (string)prop.Value == "true")) 
      return false; 
     if (!(prop.Name.StartsWith("@") && prop.Name.EndsWith(":nil"))) 
      return false; 
     var ns = prop.GetXmlNamespace(); 
     return ns == XsiNamespace; 
    } 
} 

をそして、それが好きで使用します。

生成
// Parse XML to XDocument 
var xDoc = XDocument.Parse(xmlString); 

// Convert the XDocument to an intermediate JToken hierarchy. 
var converter = new Newtonsoft.Json.Converters.XmlNodeConverter { OmitRootObject = true }; 
var rootToken = JObject.FromObject(xDoc, JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = { converter } })) 
    // And replace xsi:nil objects will null JSON values 
    .ReplaceXmlNilObjectsWithNull(); 

// Deserialize to the final RootObject. 
var rootObject = rootToken.ToObject<RootObject>(); 

"AustrittDatum": [ 
    "2018-01-31+01:00", 
    null 
], 
0を

ここで私は当初、XDocumentに解析していますが、あなたはまた、.Net fiddle作業古いXmlDocument

サンプルを使用することができます。

+0

ご回答ありがとうございました。私はそれが箱からサポートされていないことに非常に驚いています。あなたのソリューションは動作していますが、目標は達成されていますが、私の場合は操作が難しいので、xsi:nil属性でマークされたノードを削除してストリングプロパティーに解析され、しかし、私はあなたの答えを適切に受け入れることができると思います –