我们有一个长期存在的应用程序,它使用一些曾经是 xml 的提要,但已转换为 json... 当然,我们“懒”地将解析器从读取 XmlDocument 更改为读取 JObject 或其他,因此我们使用“DeserializeXmlNode”从 json txt 转换为 XmlDocument。 很长一段时间一切都很好...直到我们从 Newtonsoft.Json 版本 4.5 和 6.0 更新到版本 12.0.x,突然我们开始遇到一些问题...
假设 json 看起来像这样:
{"version":"2.0","result":[{"mainobid":"123","typeId":"2","subobjects":{"1":{"data":"data"},"2":{"data":"data"}}}]}
我们过去得到的是 xml
<1><data>data</data></1><2><data>data</data></2>
标签
现在...而不是 <1> 标签,我们得到类似 <x0031> 的内容 不是 10,而是 _x0031_0 不是 45,而是 0x0034_5 而不是 100 _x0031_00
我可以把它关掉吗?或者我现在被迫改变解析来解码那个病态的x003....东西?
INB4 1:我意识到拥有 1: 和 <1> 并不是任何理智的人都希望拥有的东西,但我无法改变这一点,它是外部提要
INB4 2:我知道我们应该将解析从 xml 更改为 json,但如上所述 - 一些懒惰和重新使用 100% 正常工作的旧代码。
编辑:
private static void TestOldNewton()
{
var jsonstr = "{\"version\":\"2.0\",\"result\":[{\"mainobid\":\"123\",\"typeId\":\"2\",\"subobjects\":{\"1\":{\"data\":\"data\"},\"2\":{\"data\":\"data\"}}}]}";
var doc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonstr, "data");
Console.WriteLine(doc.OuterXml);
Console.ReadKey();
}
使用packages.config,例如:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.1" targetFramework="net48" />
</packages>
并接收输出:
<data><version>2.0</version><result><mainobid>123</mainobid><typeId>2</typeId><subobjects><1><data>data</data></1><2><data>data</data></2></subobjects></result></data>
新编译并在新的测试项目上运行。
最佳答案
更改的原因是以下 checkin : Fixed converting JSON to XML with invalid XML name characters 到 Json.NET 8.0.1 。此 checkin 添加了(除其他更改外)对 XmlConvert.EncodeName()
的调用里面 XmlNodeConverter.CreateElement()
:
private IXmlElement CreateElement(string elementName, IXmlDocument document, string? elementPrefix, XmlNamespaceManager manager) { string encodeName = EncodeSpecialCharacters ? XmlConvert.EncodeLocalName(elementName) : XmlConvert.EncodeName(elementName); string ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); IXmlElement element = (!StringUtils.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName); return element; }
这是对 [add] support for converting JSON to XML with invalid XML name characters 进行的。这在这里适用,因为元素名称以数字开头,例如 <1>
不是格式良好的 XML 元素名称,如 XML tagname starting with number is not working 中所述。 。事实上,严格来说,您之前生成的 XML 并不是格式良好的 XML。
正如您从上面的代码摘录中看到的,似乎没有办法禁用此更改并创建元素名称而不对其进行编码。
作为解决方法,因为您想要创建具有数字名称的元素,如 <1>
无论如何,你可以子类 XmlTextWriter
并通过调用 XmlConvert.DecodeName()
解码名称。
This method does the reverse of the EncodeName(String) and EncodeLocalName(String) methods.
首先定义以下类:
public class NameEditingXmlTextWriter : XmlTextWriter
{
readonly Func<string, string, string> nameEditor;
public NameEditingXmlTextWriter(TextWriter writer, Func<string, string, string> nameEditor)
: base(writer)
{
this.nameEditor = nameEditor;
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
var newLocalName = nameEditor(localName, ns);
base.WriteStartElement(prefix, newLocalName, ns);
}
}
然后按如下方式使用:
var doc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonstr, "root");
var sb = new StringBuilder();
using (var textWriter = new StringWriter(sb))
using (var writer = new NameEditingXmlTextWriter(textWriter, (n, ns) => XmlConvert.DecodeName(n)))
{
doc.WriteTo(writer);
}
var outerXml = sb.ToString();
注释:
您必须对已弃用的
XmlTextWriter
进行子类化而不是其替代品XmlWriter
因为XmlWriter
尝试写入格式错误的 XML 元素名称(如<1>
)时将引发异常.作为替代方案,因为 Json.NET 目前已根据 MIT License 获得许可。 ,您可以 fork 自己的
XmlNodeConverter
版本并删除对XmlConvert.EncodeName()
的调用来自CreateElement()
。然而,这个解决方案似乎不太理想,因为它创建了维护要求,以使您的 fork 版本与 Newtonsoft 的版本保持同步。
演示 fiddle here .
关于c# - Newtonsoft.Json DeserializeXmlNode 将标签名称从数字更改为 "something",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64016941/