[英]Searching for distinct XML structures in a document with Linq to XML in C#
I have written a little C# to parse through a number of elements in an XML document and return only the first of those elements which have a distinct child structure? 我已经编写了一些C#来解析XML文档中的许多元素,并仅返回那些具有不同子结构的元素中的第一个? For example, if I have the following XML doc, then a call to rootElement.DistinctStructures("base")
let's say returns an IEnumerable<XElement>
containing just the base elements with ids 1, 3, and 5. 例如,如果我有以下XML文档,则对rootElement.DistinctStructures("base")
的调用返回一个IEnumerable<XElement>
,该IEnumerable<XElement>
仅包含ID为1、3和5的基本元素。
<root>
<base id="1">
<a>text</a>
</base>
<base id="2">
<a>more text</a>
</base>
<base id="3">
<b>text</b>
</base>
<base id="4">
<a>other text</a>
</base>
<base id="5">
<a>
<c>sub text</c>
</a>
</base>
</root>
The basic code generates a unique key from the element name and text nodes in the structure and compares them to a saved collection of unique elements. 基本代码从结构中的元素名称和文本节点生成唯一键,并将它们与保存的唯一元素集合进行比较。 My question is whether there is a neater way to do this? 我的问题是这样做是否有更整洁的方法?
private Dictionary<string, XElement> uniqueElements = new Dictionary<string, XElement>();
public void Go()
{
foreach (var entry in xmlDoc.Elements("e"))
{
string keyString = AsStructureString(entry).ToString();
if (!uniqueElements.Keys.Contains(keyString))
{
uniqueElements.Add(keyString, entry);
}
}
}
public StringBuilder AsStructureString(this XElement input)
{
StringBuilder sb = new StringBuilder(input.Name.LocalName);
var NodesOfNote = input.Nodes().Where(n => n.NodeType == XmlNodeType.Element || n.NodeType == XmlNodeType.Text).ToList();
if (NodesOfNote.Any())
{
sb.Append(">>");
}
foreach (var childNode in NodesOfNote)
{
if (childNode.NodeType == XmlNodeType.Element)
{
sb.Append((childNode as XElement).AsStructureString());
}
if (childNode.NodeType == XmlNodeType.Text)
{
sb.Append("txt");
}
if (!childNode.IsLastIn(NodesOfNote))
{
sb.Append("|");
}
}
return sb;
}
It might be easier than you think. 这可能比您想象的要容易。 If what determines the structure of a node is its elements and text (regardless of the content), you could do this: 如果决定节点结构的是其元素和文本(与内容无关),则可以执行以下操作:
IEnumerable<XElement> DistinctStructures(XContainer root, XName name)
{
return
from d in root.Descendants(name)
group d by GetKey(d) into g
select g.First();
string GetKey(XElement n) =>
String.Join(",",
n.DescendantNodes().Select(d =>
d is XElement e ? $"{e.Name}^{GetDepth(e)}"
: d is XText t ? $"<text>^{GetDepth(t)}"
: default
)
);
int GetDepth(XObject o)
{
var depth = 0;
for (var c = o; c != null; c = c.Parent)
++depth;
return depth;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.