我正在使用C#
开发一个应用,并尝试完成XML
中的JSON
。为了使XML
对我的应用程序有效,我需要在父元素下对具有相同名称的元素进行分组。
例如,我得到了这个XML
<root>
<row>
<id>0001</id>
<type>credit</type>
<investment>1000</investment>
<ppr>0.83</ppr>
<candidate>
<id>5001</id>
<name>Hugo</name>
</candidate>
<candidate>
<id>5002</id>
<name>Jack</name>
</candidate>
<candidate>
<id>5005</id>
<name>Kate</name>
</candidate>
</row>
我需要将所有元素与候选名称分组,在父节点候选下,如此
<root>
<row>
<id>0001</id>
<type>credit</type>
<investment>1000</investment>
<ppr>0.83</ppr>
<candidates>
<candidate>
<id>5001</id>
<name>Hugo</name>
</candidate>
<candidate>
<id>5002</id>
<name>Jack</name>
</candidate>
<candidate>
<id>5005</id>
<name>Kate</name>
</candidate>
</candidates>
</row>
但这是我的问题:我不知道我可以从JSON
收到的姓名。所以我需要做这个比较并完成XML而不知道&#34;候选人&#34;节点名称。我需要这个可以接收的任何名字。
同样在这个例子中,XML
只有2个级别,但它可以有任意数量的级别。我可以使用此函数迭代XML
:
public void findAllNodes(XmlNode node)
{
Console.WriteLine(node.Name);
foreach (XmlNode n in node.ChildNodes)
findAllNodes(n);
}
如何进行比较并对节点进行分组?
答案 0 :(得分:2)
一个相当天真的实现可以使用LINQ按名称对元素进行分组,并为组中包含多个项目的元素添加父元素。这将是递归的,因此元素的子元素被分组,直到树用完为止。
天真的是,如果存在混合内容元素,这样的解决方案会破坏,并且它会对不是兄弟姐妹的元素进行分组(基本上,这两个问题都会导致事情以错误的顺序结束)。它应该给你一个良好的开端,并且可以满足你的目的。
private static IEnumerable<XElement> GroupElements(IEnumerable<XElement> elements)
{
var elementsByName = elements.GroupBy(x => x.Name);
foreach (var grouping in elementsByName)
{
var transformed = grouping.Select(e =>
new XElement(e.Name,
GroupElements(e.Elements()),
e.Attributes(),
e.Nodes().OfType<XText>()));
if (grouping.Count() == 1)
{
yield return transformed.Single();
}
else
{
var groupName = grouping.Key + "s";
yield return new XElement(groupName, transformed);
}
}
}
您可以通过解析/加载现有XML然后转换根元素并从中创建新文档来使用它:
var original = XDocument.Parse(xml);
var grouped = new XDocument(GroupElements(original.Elements()));
有关正常工作的演示,请参阅this fiddle。
答案 1 :(得分:0)
这是一个XSLT 2.0解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="*[*]">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="node-name(.)">
<xsl:choose>
<xsl:when test="count(current-group()) > 1">
<xsl:element name="{name()}s" namespace="{namespace-uri()}">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
<强>输出:强>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<id>0001</id>
<type>credit</type>
<investment>1000</investment>
<ppr>0.83</ppr>
<candidates>
<candidate>
<id>5001</id>
<name>Hugo</name>
</candidate>
<candidate>
<id>5002</id>
<name>Jack</name>
</candidate>
<candidate>
<id>5005</id>
<name>Kate</name>
</candidate>
</candidates>
</row>
</root>
<强>限制强>
它不会处理混合内容(带有子项和文字内容的元素)
删除属性(容易修复)