【问题标题】:How to check values of child elements of specific parent element?如何检查特定父元素的子元素的值?
【发布时间】:2018-11-15 14:36:49
【问题描述】:

我有一些 xml 文件,其中可能有一些名为 list 的元素,其属性 list-type 具有 3 个可能的值,分别为 ordered、bulletsimple。 现在

1) 对于list-type="ordered",每个元素list-item后面必须跟元素labellabel的值不能开头>

2) 对于list-type="bullet",每个元素list-item后面必须跟元素labellabel的值必须开头

3) 对于list-type="simple",每个元素list-item不得后跟元素label(简单列表没有标签)

我正在尝试根据其直接父元素list检查文件中是否有不遵循上述规则的list-item

我试过了

string path=@"C:\temp\list.xml";
XDocument doc=XDocument.Load(path,LoadOptions.SetLineInfo);
var simplelists=doc.Descendants("list").Where(x=>x.Attribute("list-type").Value=="simple");
if (simplelists!=null)
{
    foreach (var list in simplelists)
    {
        var x=list.Descendants("list-item").Where(a=>a.Elements("label").Any()).Select(a=>((IXmlLineInfo)a).LineNumber);
        if (x!=null)
        {
            foreach (var element in x)
            {
                Console.WriteLine("Check line: "+element+", <label> not supported in SIMPLE list");
            }

        }
    }
}

var orderedlists=doc.Descendants("list").Where(x=>x.Attribute("list-type").Value=="ordered");
if (orderedlists!=null)
{
    foreach (var list in orderedlists)
    {
        var x=list.Descendants("list-item").Where(a=>!a.Elements("label").Any() || a.Element("label").Value.StartsWith(@"&#x")).Select(a=>((IXmlLineInfo)a).LineNumber);
        if (x!=null)
        {
            foreach (var element in x)
            {
                Console.WriteLine("Check line: "+element+", <label> is either missing or has unsuppoted value for list-item (ORDERED list)");
            }

        }
    }
}

var bulletlists=doc.Descendants("list").Where(x=>x.Attribute("list-type").Value=="bullet");
if (bulletlists!=null)
{
    foreach (var list in bulletlists)
    {
        var x=list.Descendants("list-item").Where(a=>!a.Elements("label").Any() || !a.Element("label").Value.EndsWith(@"&#x")).Select(a=>((IXmlLineInfo)a).LineNumber);
        if (x!=null)
        {
            foreach (var element in x)
            {
                Console.WriteLine("Check line: "+element+", <label> is either missing or has unsuppoted value for list-item (BULLET list)");
            }

        }
    }
}

Console.ReadLine();

但这并没有达到我的预期,这是sample file

示例文件的期望输出是

Check line: 6, <label> is either missing or has unsuppoted value for list-item (ORDERED list)
Check line: 13, <label> not supported in SIMPLE list
Check line: 23, <label> is either missing or has unsuppoted value for list-item (ORDERED list)

我收到

谁能帮我解决这个问题?

注意:list 元素可能嵌套在另一个 list 元素中,具有相同或不同的 list-type 值。

【问题讨论】:

  • 如果列表可以嵌套,则使用 Elements 而不是 Descendants 获取列表项。
  • @juharr 但问题是我必须提供完整的元素树直到list 这会有所不同..示例文件只是一个简短的示例,可能还有其他元素也可能包含元素list 的文件
  • 你是说列表项可以嵌套在其他不是列表的节点中,比如&lt;list&gt;&lt;somethingelse&gt;&lt;list-item&gt;&lt;/list-item&gt;&lt;/somethingelse&gt;&lt;/list&gt;?因为我只是在谈论一个列表和它的列表项之间的关系。您仍然可以使用 Descendants 来获取所有列表。
  • @juharr 不,您检查过示例文件吗?也是所需的输出和我得到的输出
  • 是的,您获得简单列表的所有额外输出的原因是因为您在获取列表项时使用Descendants 而不是Elements。您可能对项目符号有另一个问题。

标签: c# xml-parsing linq-to-xml


【解决方案1】:

您似乎有 2 个问题。首先,您要为每个列表提取所有 Descendant 列表项,其中将包括嵌套列表的列表项。第二个问题是 xml 中的 "&amp;#x####;" 表示一个编码字符,所以像 "&amp;#x2022;" 这样的东西被它代表的字符 "•" (项目符号字符)替换。因此,您需要确定哪些确切的字符或某个范围对于有序列表无效并且对于项目符号是必需的,因为任何字符都可以以这种方式编码。下面的代码将提供您想要的结果并简化您当前代码中的大量重复。

需要注意的是,这些字符不必编码。您可以将编码替换为 xml 中的实际 unicode 字符。需要对其进行编码的唯一原因是文件本身是否需要以不支持 unicode 字符的编码保存。

XDocument doc = XDocument.Load(path, LoadOptions.SetLineInfo);
char[] invalidOrderedCharacter = new[] {'\u2022', '\u25CB' };
char[] requiredBulletCharacters = new[] {'\u2022'};
foreach (var list in doc.Descendants("list"))
{
    var listType = list.Attribute("list-type")?.Value;
    foreach (var item in list.Elements("list-item"))
    {
        var lineNumber = ((IXmlLineInfo) item).LineNumber;
        var label = item.Element("label")?.Value;
        switch (listType)
        {
            case "simple":
                if (label != null)
                {
                    Console.WriteLine(
                        "Check line: " + lineNumber + 
                        ", <label> not supported in SIMPLE list");
                }
                break;
            case "ordered":
                if (label == null || invalidOrderedCharacter.Contains(label[0]))
                {
                    Console.WriteLine(
                        "Check line: " + lineNumber + 
                        ", <label> is either missing or has unsupported value for list-item (ORDERED list)");
                }
                break;
            case "bullet":
                if (label == null || !requiredBulletCharacters.Contains(label[0]))
                {
                    Console.WriteLine(
                        "Check line: " + lineNumber + 
                        ", <label> is either missing or has unsupported value for list-item (BULLET list)");
                }
                break;
        }
    }
}

【讨论】:

  • 还是不能正常工作,你自己跑代码了吗?
  • 另一个问题是 &amp;#x 表示您正在处理编码字符,因此实际值不是这 3 个字符,而是类似于 "•"替换为它代表“•”的字符,一个非常粗体的点。因此,您需要定义要检查的实际字符,因为您可以通过这种方式对任何字符进行编码。
  • 如何在较旧的 .net(如 .net 4.5)中编写 var listType = list.Attribute("list-type")?.Value;var label = item.Element("label")?.Value;?谢谢
  • var listType = list.Attribute("list-type) == null ? null : list.Attribute("list-type").Value; 或者您可以删除?.Value,然后更改它在空检查后使用的位置,例如swithc(listType.Value)label.Value[0]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2023-03-12
  • 2014-06-16
  • 1970-01-01
相关资源
最近更新 更多