XPath select 逐节点、子节点和子子节点条件

XPath select node by node, subnode and subsubnode condition

我想检索应用了节点、子节点和子子节点条件的所有节点

我试图用这个 xpath 命令接收它:

xmlDoc.SelectNodes("//WorkItem[WorkItemType[text()='Product Backlog Item'] and ./Childern/WorkItem/WorkItemType[text() = 'Task'] and /Childern/WorkItem/WorkItemType[text() != 'Product Backlog Item'] and ./Childern/WorkItem/WorkItemType[text() = 'Task']]");

这没有提供任何节点。但我希望 WorkItem 节点的 ID 为:719 和 720 但不是 717

如何在 XPath 中表达它?

给定的 xml 看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <id>716</id>
    <WorkItemType>Product Backlog Item</WorkItemType>
    <Children>
        <WorkItem>
            <id>717</id>
            <WorkItemType>Product Backlog Item</WorkItemType>
            <Children>
                <WorkItem>
                    <id>719</id>
                    <WorkItemType>Product Backlog Item</WorkItemType>
                    <Children>
                        <WorkItem>
                            <id>721</id>
                            <WorkItemType>Task</WorkItemType>
                            <Children>
                                <WorkItem>
                                    <id>722</id>
                                    <WorkItemType>Task</WorkItemType>
                                    <Children/>
                                </WorkItem>
                            </Children>
                        </WorkItem>
                    </Children>
                </WorkItem>
                <WorkItem>
                    <id>720</id>
                    <WorkItemType>Product Backlog Item</WorkItemType>
                    <TreeLevel>2</TreeLevel>
                    <Children>
                        <WorkItem>
                            <id>724</id>
                            <WorkItemType>Task</WorkItemType>
                            <Children>
                                <WorkItem>
                                    <id>726</id>
                                    <WorkItemType>Task</WorkItemType>
                                    <Children/>
                                </WorkItem>
                            </Children>
                        </WorkItem>
                    </Children>
                </WorkItem>
                <WorkItem>
                    <id>723</id>
                    <WorkItemType>Task</WorkItemType>
                    <Children>
                        <WorkItem>
                            <id>744</id>
                            <WorkItemType>Task</WorkItemType>
                            <Children/>
                        </WorkItem>
                    </Children>
                </WorkItem>
            </Children>
        </WorkItem>
    </Children>
</root>

更新

由于 Rolf Rander 的意见,我添加了更多解释:

children 封装的级别在设计时尚不清楚。我已经更新了我的问题。 (我在 xml 文件中更正了我的拼写错误 Childern -> Children)。

尚不完全清楚您要实现的目标,但重新格式化您的代码似乎有几个冗余测试:

//WorkItem[
WorkItemType[text()='Product Backlog Item'] and
./Childern/WorkItem/WorkItemType[text() = 'Task'] and
/Childern/WorkItem/WorkItemType[text() != 'Product Backlog Item'] and
./Childern/WorkItem/WorkItemType[text() = 'Task']
]

您对 "equal to 'Task'" 进行了两次测试,不必同时检查它是否等于 'Task' 和是否不同于 'Product Backlog Item'。

您可以使用 // 检查 "any children or grandchildren",因此:

  • 任何工作项
  • WorkItemType = 'Product Backlog Item',并且
  • 名称为 WorkItemType 且内容为 'Task'
  • 的子项下没有节点

可以翻译成:

//WorkItem[
     WorkItemType[text()='Product Backlog Item'] and
     not(Children//WorkItemType[text() != 'Task'])
]

而不是这个..

./Childern/WorkItem/WorkItemType[text() != 'Product Backlog Item']

使用这个:

not(./Childern/WorkItem/WorkItemType[text() = 'Product Backlog Item'])

如果至少有一个 WorkItemType 符合条件(第一个文本节点子 不等于 'Product Backlog Item').将它与后者进行对比,后者仅在没有 WorkItemType 符合条件时才评估为 true (第一个文本节点子节点 等于 'Product Backlog Item' ).

所以完整的 XPath 看起来像这样(为了便于阅读而格式化):

//WorkItem[
    WorkItemType[text()='Product Backlog Item'] 
        and 
    ./Childern/WorkItem/WorkItemType[text() = 'Task'] 
        and 
    not(./Childern/WorkItem/WorkItemType[text() = 'Product Backlog Item']) 
        and 
    ./Childern/WorkItem/WorkItemType[text() = 'Task']
]

更新:

为了回应更新后的问题,我会做这样的事情:

//WorkItem[WorkItemType[text()='Product Backlog Item']]
          [not(.//WorkItem/WorkItemType/text() != 'Task')]