如何使用XElement/XDocument及LINQ-to-XML查找重复属性值节点并获取行号?
使用LINQ-to-XML查找重复axs属性的myNode节点并获取行号
要解决这个问题,我们需要分两步走:首先识别出哪些axs属性值是重复的,然后结合XmlReader来获取每个节点的行号(因为LINQ-to-XML的XElement本身不存储行号信息,得借助XmlReader的位置跟踪能力)。
先来看你的示例XML:
<parentNode> <c-node> <myNode axs="p1">Anything goes</myNode> <myNode axs="p2">Nothing <aa>is</aa> here</myNode> <myNode axs="p1">Whatever it may be</myNode> <myNode axs="p3">...</myNode> </c-node> </parentNode>
步骤1:找出重复的axs属性值
先加载XML文档,通过LINQ统计每个axs值的出现次数,筛选出出现次数大于1的值:
// 加载XML文档 var doc = XDocument.Load("yourXmlFilePath.xml"); // 获取所有myNode节点的axs属性值,筛选出重复的那些 var duplicateAxsValues = doc.Descendants("myNode") .Select(node => node.Attribute("axs")?.Value) .Where(val => !string.IsNullOrEmpty(val)) .GroupBy(val => val) .Where(group => group.Count() > 1) .Select(group => group.Key) .ToHashSet();
步骤2:获取带行号的myNode节点
由于XElement不记录行号,我们需要用XmlReader来读取XML——它实现了IXmlLineInfo接口,可以获取节点的行号。我们可以定义一个简单的类来存储节点和对应的行号:
// 用于存储节点和行号的辅助类 public class NodeWithLineNumber { public XElement Node { get; set; } public int LineNumber { get; set; } } // 读取XML并收集每个myNode的行号信息 var nodesWithLineNumbers = new List<NodeWithLineNumber>(); using (var reader = XmlReader.Create("yourXmlFilePath.xml", new XmlReaderSettings { IgnoreWhitespace = false })) { while (reader.Read()) { // 只处理myNode元素节点 if (reader.NodeType == XmlNodeType.Element && reader.Name == "myNode") { // 将当前节点转换为XElement var element = XElement.ReadFrom(reader) as XElement; // 获取行号(XmlReader实现了IXmlLineInfo) var lineNumber = ((IXmlLineInfo)reader).LineNumber; nodesWithLineNumbers.Add(new NodeWithLineNumber { Node = element, LineNumber = lineNumber }); } } }
注意:这里把
XmlReaderSettings.IgnoreWhitespace设为false,是为了确保行号对应XML文件中的实际行位置,避免因忽略空白节点导致行号偏移。
步骤3:筛选出重复axs值的节点
最后,结合第一步得到的重复axs值列表,筛选出目标节点:
// 筛选出axs值属于重复列表的节点 var duplicateNodes = nodesWithLineNumbers .Where(item => duplicateAxsValues.Contains(item.Node.Attribute("axs")?.Value)) .ToList(); // 输出结果示例 foreach (var item in duplicateNodes) { Console.WriteLine($"行号: {item.LineNumber}, axs值: {item.Node.Attribute("axs").Value}, 节点内容: {item.Node.Value.Trim()}"); }
运行这段代码后,你会得到所有axs="p1"的myNode节点及其对应的行号,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Bumba
相关产品推荐
相关产品推荐

