XPath根据类型条件选择子节点,对于特定类型,选择其所有子节点
本文关键字:选择 类型 子节点 于特定 XPath 条件 | 更新日期: 2023-09-27 18:26:22
这是我给定的XML:
<WorkItem>
<Id>717</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>1</TreeLevel>
<Children>
<WorkItem>
<Id>719</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>2</TreeLevel>
<Children>
<WorkItem>
<Id>721</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>3</TreeLevel>
<Children>
<WorkItem>
<Id>722</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<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>
<TreeLevel>3</TreeLevel>
<Children>
<WorkItem>
<Id>726</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
<WorkItem>
<Id>725</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>3</TreeLevel>
<Children>
<WorkItem>
<Id>727</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<Children />
</WorkItem>
<WorkItem>
<Id>728</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<Children />
</WorkItem>
<WorkItem>
<Id>729</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<Children>
<WorkItem>
<Id>745</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>5</TreeLevel>
<Children />
</WorkItem>
<WorkItem>
<Id>746</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>5</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
</Children>
</WorkItem>
</Children>
</WorkItem>
<WorkItem>
<Id>723</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>2</TreeLevel>
<Children>
<WorkItem>
<Id>744</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>3</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
</Children>
</WorkItem>
我想检索具有两个特定类型的子节点的节点的所有节点。如果这种类型是一种,我想得到所有的后代。
我试图用这个xpath命令接收它(我在C#中使用System.Xml.XmlDocument):
xmlDoc.SelectNodes("Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]/following::WorkItem[WorkItemType[text()='Task']]");
// splitted for better readability
Children/WorkItem[
WorkItemType[
text()='Product Backlog Item']
]|
Children/WorkItem[
WorkItemType[
text()='Task']
]/following::WorkItem[WorkItemType[text()='Task']]
这只为我提供了ID为719和720的节点。但是我期望具有Id的WorkItem节点:719和720(xpath表达式的第一部分)以及723和744(来自第二个xpath表达式)。
- 我的目标是拥有WorkItemType"Product Backlog Item"的WorkItem元素,该元素具有WorkItemType的"Product Backlog Item"answers"Task"的子WorkItem元素。
- 如果是"Task"类型的WorkItem元素,我希望下面有所有子WorkItem元素
我如何用XPath表达这一点?
在给定的XML中,我期望ID为719720723744 的WorkItem元素
目前还不清楚您想要实现什么,但我将尝试向您展示一个处理此任务的可能解决方案。
在我看来,创建一个巨大的XPath表达式并不重要,因为几年后它可能真的很难理解。对于您的情况,不可能在一个XPath表达式中获得您想要的所有内容。你可以把它分开:
foreach (var element in xmlDoc.SelectNodes("WorkItem/Children").OfType<XmlElement>())
{
var elements = element.SelectNodes("WorkItem[WorkItemType[text()='Product Backlog Item' or text()='Task']]");
foreach(var child in elements.OfType<XmlElement>())
Process(child);
}
public void Process(XmlElement rootElement)
{
// Print some info about the work item
// ...
foreach (var element in rootElement.SelectNodes("Children").OfType<XmlElement>())
{
// I'm not sure whether it's exactly what you want but you can
// easily change this expression.
var children = element.SelectNodes("WorkItem[WorkItemType[text()='Task']]");
// continue the processing of children
foreach (var child in children.OfType<XmlElement>())
Process(child);
}
}
首先,检查根子级的WorkItems的所有节点,然后将它们发送到Process
方法,该方法也称为内部(递归)。它将帮助您处理更深层的层次结构。
我找到了一个适用于我想做的事情的xpath:
Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]/descendant-or-self::WorkItem[WorkItemType[text()='Task']]
更好的可读性
Children/WorkItem[WorkItemType[
text()='Product Backlog Item']
]|
Children/WorkItem[WorkItemType[
text()='Task']
]/descendant-or-self::WorkItem[WorkItemType[
text()='Task']]