【问题标题】:How to get nodes with same name and same attribute name to collection?如何获取具有相同名称和相同属性名称的节点进行集合?
【发布时间】:2018-03-05 00:40:49
【问题描述】:

我的 xml 文件看起来像这样

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="101">3.1256
    <auth-name>Idris Polk</auth-name>
    <auth id="a1">The author is a Professor of Physics at MIT</auth>
    <ph ll="p1">336451234</ph> <ph ll="p2">336051294</ph> <mail>IP.00@yandex.com</mail> <ph ll="p3">336133291</ph>
    </book>
    <book id="105">4.2250
    <auth-name>Andre Olo</auth-name>
    <auth id="a2">The research fellow at NSF</auth>
    <ph ll="p101">336200316</ph>, <ph ll="p102">336151093</ph>, <ph ll="p103">336151094</ph>, <mail>An.olo@yandex.com</mail> <ph ll="p111">336900336</ph>, <ph ll="p112">336154094</ph>, <ph ll="p113">336151098</ph>, <mail>ano_ano@yandex.com</mail>
    </book>
    <ebook id="1">4.2350
    <auth-name>John Bart</auth-name>
    <auth id="ae1">The research fellow at Caltech</auth>
    <ph ll="p50">336200313</ph>, <ph ll="p51">336151090</ph>, <ph ll="p52">336851091</ph>, <ph ll="p53">336151097</ph>, <mail>bart.j@yandex.com</mail> <ph ll="p111">336000311</ph>, <ph ll="p112">336224094</ph>
    </ebook>
...
</books>

当有两个以上的节点 ph 以空格分隔或以逗号分隔时,如何将具有特定父节点属性 ll 的节点 ph 获取到集合中一个空格?如果任何其他字符/节点(或任何类型的字符串)位于一个 ph 节点和下一个 ph 节点之间,则不会将其纳入集合。前任。如果&lt;book id="..."&gt; 节点以&lt;ph ll="1"&gt;...&lt;/ph&gt; &lt;ph ll="2"&gt;...&lt;/ph&gt; &lt;mail&gt;...&lt;mail&gt; &lt;ph ll="3"&gt;...&lt;/ph&gt; 的方式包含ph 节点,则不会将其添加到集合中,但是如果它们按&lt;ph ll="1"&gt;...&lt;/ph&gt; &lt;ph ll="2"&gt;...&lt;/ph&gt; &lt;ph ll="3"&gt;...&lt;/ph&gt; &lt;mail&gt;...&lt;mail&gt; 的顺序排列,则应将&lt;ph ll="1"&gt;...&lt;/ph&gt; &lt;ph ll="2"&gt;...&lt;/ph&gt; &lt;ph ll="3"&gt;...&lt;/ph&gt; 作为单个元素添加到集合,因为在给定的父节点中有超过 2 个 ph 节点仅由空格分隔..

很简单

var cls=doc.Descendants("ph")
                .Where(Attribute("ll"));

不会。有人可以帮忙吗?

【问题讨论】:

  • 你不能像这样在 xml 中使用逗号。我不希望您甚至能够将其解析为XDocument
  • @Crowcoder ok..这只是一个例子......如果没有逗号..那么呢?
  • 我无法理解您的要求,但空格与 xml 无关。您可以有数百个空格或没有,xml 将解析相同。
  • @Crowcoder 我的要求是找到节点&lt;ph ll="..."&gt;,当父节点中有两个以上的节点时,将它们放在一个集合中......
  • 您必须将其解析为文本,因为也没有 xml 解析器关心元素的顺序。该示例格式不正确,xml 意味着机器可读和分层。我帮不了你,这将是一个非常复杂和脆弱的解决方案。

标签: c# linq-to-xml


【解决方案1】:

试试下面的代码。我使用了 xml linq 和帮助方法。 :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            var books = doc.Descendants("books").Elements().Select(x => new { book = x, sequence = TestChildren(x) }).Where(x => x.sequence != null).ToList();

            string results = string.Join("\n", books.SelectMany(x => x.sequence).Select((x, i) => (i + 1).ToString() + ") " + string.Join("", x.Select(y => y.ToString()))));

            Console.WriteLine(results);
            Console.ReadLine();

        }
        static List<List<XElement>> TestChildren(XElement book)
        {
            List<List<XElement>> results = null;
            List<XElement> children = book.Elements().ToList();
            // get lls, make -1 if not ph
            List<int> lls = children.Select(x => x.Name.LocalName != "ph" ? -1 : int.Parse(((string)x.Attribute("ll")).Substring(1))).ToList();
            //check for 3 in a row incrementing
            int startIndex = -1;
            int numberInSequence = 0;
            for (int i = 0; i < lls.Count() - 3; i++)
            {
                //test for 3 in a row
                if ((lls[i] + 1 == lls[i + 1]) && (lls[i] + 2 == lls[i + 2]))
                {
                    //if first sequency found set start index and lenght to 3
                    if (startIndex == -1)
                    {
                        startIndex = i;
                        numberInSequence = 3;
                    }
                    else
                    {
                        //increase length if more than 3
                        numberInSequence++;
                    }

                }
                else
                {
                    //if a sequence has been found add to results
                    if (numberInSequence >= 3)
                    {
                        List<XElement> sequence = new List<XElement>(children.Skip(startIndex).Take(numberInSequence).ToList());
                        if (results == null) results = new List<List<XElement>>();
                        results.Add(sequence);
                        startIndex = -1;
                        numberInSequence = 0;
                    }
                }
            }
            if (numberInSequence >= 3)
            {
                List<XElement> sequence = new List<XElement>(children.Skip(startIndex).Take(numberInSequence).ToList());
                if (results == null) results = new List<List<XElement>>();
                results.Add(sequence);
            }
            return results;
        }
    }
}

【讨论】:

  • 我想要 3 个或更多 &lt;ph l=".."l&gt; 节点作为输出..上面的 xml 应该给出输出,即集合 books 的元素应该是 1)&lt;ph ll="p101"&gt;336200316&lt;/ph&gt;, &lt;ph ll="p102"&gt;336151093&lt;/ph&gt;, &lt;ph ll="p103"&gt;336151094&lt;/ph&gt; 2) @987654325 @ 3) &lt;ph ll="p50"&gt;336200313&lt;/ph&gt;, &lt;ph ll="p51"&gt;336151090&lt;/ph&gt;, &lt;ph ll="p52"&gt;336851091&lt;/ph&gt;, &lt;ph ll="p53"&gt;336151097&lt;/ph&gt;
  • 再次更新代码以从每本书中获取多个序列。
  • 如何从收藏簿中提取匹配的连续&lt;ph&gt; 节点?
最近更新 更多