gpt4 book ai didi

C# JsonConvert SerializeXmlNode 空属性

转载 作者:数据小太阳 更新时间:2023-10-29 02:11:52 25 4
gpt4 key购买 nike

我正在使用 JsonConvert SerializeXmlNode 将 xml 转换为 json。我面临的问题是我有一个标签,它有时可以有值(value),有时可以为空

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

结果 - 当我尝试将 json 反序列化为具有字符串属性“AustrittDatum”的 C# 对象时出现异常 - “Newtonsoft.Json.JsonReaderException:‘读取字符串时出错。意外的标记:StartObject。路径‘AustrittDatum’。”", 因为

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

被序列化为

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

我怎样才能强制它像这样 "AustrittDatum": "" 或者也许有一些正确的方法来解决它?

最佳答案

似乎,当遇到带有 xsi:nil="true" 的 XML 元素时, Json.NET 的 XmlNodeConverter使用您看到的属性创建一个 JSON 对象,而不是 null JToken .这与 Newtonsoft 文档页面 Converting between JSON and XML 一致:

Converstion Rules

  • Elements remain unchanged.
  • Attributes are prefixed with an @ and should be at the start of the object.
  • Single child text nodes are a value directly against an element, otherwise they are accessed via #text.
  • The XML declaration and processing instructions are prefixed with ?.
  • Character data, comments, whitespace and significant whitespace nodes are accessed via #cdata-section, #comment, #whitespace and #significant-whitespace respectively.
  • Multiple nodes with the same name at the same level are grouped together into an array.
  • Empty elements are null.

If the XML created from JSON doesn't match what you want, then you will need to convert it manually...

尽管如此,认为具有 xsi:nil="true" 的元素将被转换为 null JSON 值是合理的,因为 xsi:nilpredefined w3c attribute .可能 Newtonsoft 没有这样做,因为这样的元素可以携带额外的属性,如果元素被转换为 null,这些属性将会丢失。

您可以提交 enhancement request对于 XmlNodeConverter 如果您愿意,但与此同时,以下扩展方法将对 JToken 层次结构进行后处理并转换以前为 nil 元素的对象为空 JSON 值:

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
],

这里我最初解析为 XDocument但你也可以使用旧的 XmlDocument

sample 加工 .Net fiddle .

关于C# JsonConvert SerializeXmlNode 空属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48009358/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com