XPath 通过嵌套选择节点(大多数嵌套节点减一)
Posted
技术标签:
【中文标题】XPath 通过嵌套选择节点(大多数嵌套节点减一)【英文标题】:XPath select nodes by nesting (most nested nodes minus one) 【发布时间】:2016-03-19 17:56:15 【问题描述】:这是给定的xml:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Root>
<WorkItem>
<Id>716</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>0</TreeLevel>
<Children>
<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>
</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>
</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>
<Id>747</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>4</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
</Children>
</WorkItem>
<WorkItem>
<Id>748</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>2</TreeLevel>
<Children />
</WorkItem>
<WorkItem>
<Id>752</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>2</TreeLevel>
<Children>
<WorkItem>
<Id>753</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>3</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
</Children>
</WorkItem>
<WorkItem>
<Id>718</Id>
<WorkItemType>Task</WorkItemType>
<TreeLevel>1</TreeLevel>
<Children />
</WorkItem>
</Children>
</WorkItem>
</Root>
简化的xml是这样的
716 (PBI) Root
- 717 (PBI)
- 719 (PBI)
- 721 (Task)
- 720 (PBI)
- 724 (Task)
- 723 (Task)
- 744 (Task)
- 747 (Task)
- 748 (Task)
- 752 (PBI)
- 753 (PBI)
- 718 (Task)
我想检索 WorkItemType "Product Backlog Item" 的所有第二个内部节点。 我也可以说我想要“Product Backlog Items”,其中包含“Product Backlog Item”类型的子元素,但没有“Product Backlog Item”的子元素。
在给定的示例中,这将是
我尝试用这个 xpath 命令接收它(我在 C# 中使用 System.Xml.XmlDocument):
//WorkItem[WorkItemType[text()='Product Backlog Item'] and ./Children/WorkItem/WorkItemType[text() = 'Product Backlog Item'] and not(./Children//WorkItem/WorkItemType[text() = 'Product Backlog Item']/Children/WorkItem/WorkItemType[text() = 'Product Backlog Item'])]
为了更好的可读性
//WorkItem[WorkItemType[text()='Product Backlog Item']
and ./Children/WorkItem/WorkItemType[text() = 'Product Backlog Item']
and not(./Children//WorkItem/WorkItemType[text() = 'Product Backlog Item']/Children/WorkItem/WorkItemType[text() = 'Product Backlog Item'])]
通过这个 XPath 表达式,我得到了 ID 为 716、717 和 752 的项目。
但我只想要 752 项。
【问题讨论】:
你为什么不使用LINQ TO XML
呢?
@Sybren 感谢您的评论。我使用 xpath 是因为我将 xpath 表达式存储在配置文件中。以后需要扩展这个文件。据我所知LINQ TO XML
这是不可能的。
能否详细说明“第二个内部节点”?
@YacoubMassad 感谢您的评论。我试图描述它。如果您检查简化的 xml 结构,我想选择 752。这是 PBI(产品待办事项)类型的第二个最内层节点。
我想我找到了解决这个查询问题的方法: //WorkItem[WorkItemType[text()='Product Backlog Item'] and Children/WorkItem/WorkItemType[text() = 'Product Backlog Item'] 而不是(Children/WorkItem/WorkItemType[text() != 'Product Backlog Item'])]
【参考方案1】:
我们不确切知道您的 XML 文档的结构有多少变化,但请尝试从完全不同的角度来看待它。
从最里面的WorkItem
开始,它有一个元素WorkItemType = 'Product Backlog Item'
,但没有任何子元素WorkItem
。然后,使用parent::
轴向后移动。
完整的 XPath 表达式如下所示
//WorkItem[WorkItemType = 'Product Backlog Item' and not(Children/WorkItem)]/parent::Children/parent::WorkItem
唯一的结果是
<WorkItem>
<Id>752</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>2</TreeLevel>
<Children>
<WorkItem>
<Id>753</Id>
<WorkItemType>Product Backlog Item</WorkItemType>
<TreeLevel>3</TreeLevel>
<Children/>
</WorkItem>
</Children>
</WorkItem>
请注意,上面的表达式要求内部 WorkItem
不包含任何其他 WorkItem
元素 - 这并不是您所要求的。如果我要非常仔细地遵循您的描述,这将导致我
//WorkItem[WorkItemType = 'Product Backlog Item' and not(Children/WorkItem[WorkItemType = 'Product Backlog Item'])]/parent::Children/parent::WorkItem
其中还包括 ID 为 717
的 WorkItem
。
【讨论】:
以上是关于XPath 通过嵌套选择节点(大多数嵌套节点减一)的主要内容,如果未能解决你的问题,请参考以下文章
Python爬虫编程思想(58): 用Beautiful Soup CSS选择器嵌套选择节点
Python中Scrapy框架元素选择器XPath的简单实例
Python爬虫:想听榜单歌曲?使用BeautifulSoup库只需要14行代码即可搞定
Python爬虫:想听榜单歌曲?使用BeautifulSoup库只需要14行代码即可搞定