我尝试使用Json.net
(JsonConvert.SerializeXNode)将xml转换为json。
如果您不使用某种模式(xsd),尝试在xml和json之间进行转换时会出现问题,因为您无法真正识别xml集合与xml集合之间的区别常规对象的单个元素。
示例:
<Drivers>
<Driver>
<Name>MyName</Name>
</Driver>
</Drivers>
将转换为:
"Drivers":{ "Driver": { "Name": "MyName" } }
因为没有人告诉序列化程序,驱动程序是一个包含单个对象的集合,并且它认为它只是一个常规对象。
Json.net
可以使用json:Array='true'标记解决此问题。
标记数组时,一切都很有效,但它会创建一个额外的中间对象(驱动程序):
"Drivers": [{"Driver":{"Name": "MyName"}}]
现在我明白了为什么要创建这个节点,但是我试图找到一种绕过创建的方法。我想得到这个结果:
"Drivers": [{"Name": "MyName"}]
有没有人知道如何做这样的事情?
答案 0 :(得分:1)
Json.NET不会自动将使用outer container element序列化的集合(例如,附加[XmlArray]
生成的集合)转换为单个JSON数组。相反,您需要通过使用LINQ-to-XML预处理XML或使用LINQ-to-JSON进行后处理来手动压缩不需要的嵌套级别。
由于您已经预处理XML以添加json:Array='true'
属性,因此添加一些额外的预处理似乎是最直接的。首先,介绍以下扩展方法:
public static class XNodeExtensions
{
/// <summary>
/// Flatten a two-level collection with an outer container element to a one-level collection
/// in preparation for conversion to JSON using Json.NET
/// </summary>
/// <param name="parents">The outer container elements.</param>
/// <param name="childName">The inner element name. If null, flatten all children.</param>
/// <param name="newChildName">The new element name. If null, use the parent name.</param>
public static void FlattenCollection(this IEnumerable<XElement> parents, XName childName = null, XName newChildName = null)
{
if (parents == null)
throw new ArgumentNullException();
XNamespace json = @"http://james.newtonking.com/projects/json";
XName isArray = json + "Array";
foreach (var parent in parents.ToList())
{
if (parent.Parent == null)
continue; // Removed or root
foreach (var child in (childName == null ? parent.Elements() : parent.Elements(childName)).ToList())
{
child.Remove();
child.Name = newChildName ?? parent.Name;
child.Add(new XAttribute(isArray, true));
parent.Parent.Add(child);
}
if (!parent.HasElements)
parent.Remove();
}
}
}
您现在可以:
var xnode = XDocument.Parse(xml);
xnode.Descendants("Drivers").FlattenCollection();
var json = JsonConvert.SerializeXNode(xnode, Formatting.Indented, true);
获取您想要的JSON。样本fiddle。
请注意<Drivers>
不能成为root element,因为XML文档必须只有一个根节点。
答案 1 :(得分:0)
运行以下示例并将标志omitRootObject
设置为true将执行此操作。如果你把它变成假,你确实得到了上面的驱动程序节点 - 你正试图摆脱它。
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(@"<Drivers>
<Driver>
<Name>MyName</Name>
</Driver>
</Drivers>");
var result = JsonConvert.SerializeXmlNode(xmlDoc.FirstChild, Newtonsoft.Json.Formatting.Indented, true);
Console.WriteLine(result);
输出:
将omitRootNode
设置为false,您将获得正在尝试删除的根节点。
答案 2 :(得分:0)
我实施的扁平化有点不同。我已经接受了dbc的回答,因为它确实回答了这个问题,但这是我的实现,以防万一将来遇到这个并需要它:
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
<source src="movie.webm" type="video/webm">
Your browser does not support the video tag.
</video>