是否可以截断给定节点上的XPath轴?
我一直在写一些代码,从网页中提取主要的文本内容。一个有用的策略是找到第一段内容,然后选择所有以下兄弟元素,但不包括第一个不是p
,ul
,ol
或元素的兄弟元素。在Perl,代码看起来是这样的:是否可以截断给定节点上的XPath轴?
my ($firstpara) = $document->findnodes('//p[whatever]');
my @content = ($firstpara);
for my $sibling ($firstpara->findnodes('following-sibling::*')) {
last if $sibling->tag !~ /^(?:p|ol|ul|blockquote)\z/;
push @content, $sibling;
}
这是不是太糟糕,但它会很酷,能够得到我想要只使用XPath的节点,所以我可以写这样的事情,而不是:
my ($firstpara) = $document->findnodes('//p[whatever]');
my @content = ($firstpara, $firstpara->findnodes('<query>'));
我已经做了很多实验,但一直未能弄清楚如何编写最后一个查询。最近的一个有效的寻找的解决方案,我已经能够找到的是一样的东西:
$firstpara->findnodes('following-sibling::*[position() < $EXPR]');
...其中$EXPR
是一些表达式返回一个同级的其标记为不p
,ul
的位置, ol
或,但是我一直无法弄清楚如果这样的表达式在XPath中是可以表达的。
有什么办法可以做到我在XPath中描述的内容?
例子:
假设我的文件看起来是这样的:
<h1>Header</h1>
<p>Paragraph 1</p>
<p id="first">Paragraph 2</p>
<p>Paragraph 3</p>
<ul><li>Item 1</li><li>Item 2</li></ul>
<p>Paragraph 4</p>
<hr>
<p>Paragraph 5</p>
<blockquote>Blockquote 1</blockquote>
...
我有ID first
一个参考<p>
元素。我在XPath表达式之后,使用该元素作为内容节点,这将给我以下兄弟姐妹Paragraph 3
,无序列表和Paragraph 4
。 <hr>
元素不在我想要的那些元素之中(<p>
,<ul>
,<ol>
和<blockquote>
),以便元素及其后的所有同级元素不应该成为返回节点集的一部分。
由于OP解释,他想:
以下所有兄弟元素最多,但不包括,这不是AP,UL,OL,或BLOCKQUOTE元素
的 第一个
I.的XPath 1.0溶液:
所希望的节点是两个节点集的交集:
被继
p
与id
的兄弟姐妹值'first'
所有元素。所有在
hr
之前的兄弟姐妹的元素。
要使用XPath 1.0找到此我们使用Kayessian公式节点集相交:
$ns1[count(.|$ns2) = count($ns2)]
以上的XPath表达式选择属于同时向节点集的所有节点$ns1
和到节点集$ns2
。
让$vP1
定义为/*/p[@id='first']
。
让$vFirstNotInRange
是:
$vP1/following-sibling::*
[not(self::p or self::ul
or self::ol or self::blockquote)
] [1]
此选择第一不需要的节点(在此情况下hr
),或更精确地:那就是$vP1
一个下列同属和这不是一个p
第一元件,一个ul
,ol
或。
然后,我们要交两个节点集都是下面的$vP1
兄弟姐妹的$vFirstNotInRange
所有前面的兄弟姐妹:
让我们$vFollowingP1
表示第一个节点集合 - 这就是:
$vP1/following-sibling::*
让我们与$vPreceedingNotInRange
表示第二节点集合 - 这就是:
$vFirstNotInRange/preceding-sibling::*
最后,我们在Kayessina公式$ns1
中用$vPreceedingNotInRange
和$ns2
替换为$vFollowingP1
。这些替代的reult准确选择想要的节点:
$vPreceedingNotInRange
[count(.|$vFollowingP1)
=
count($vFollowingP1)
]
如果我们替换所有的变量,直到我们得到一个不包含任何变量的表达式,我们得到:
/*/p[@id='first']/following-sibling::*
[not(self::p or self::ul
or self::ol or self::blockquote
)
] [1]
/preceding-sibling::*
[count(.| /*/p[@id='first']/following-sibling::*)
=
count(/*/p[@id='first']/following-sibling::*)
]
这种表达准确选择想要的节点。
下面是一个XSLT - 基于验证:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vP1" select="/*/p[@id='first']"/>
<xsl:variable name="vFirstNotInRange" select=
"$vP1/following-sibling::*
[not(self::p or self::ul
or self::ol or self::blockquote)
] [1]"/>
<xsl:variable name="vFollowingP1"
select="$vP1/following-sibling::*"/>
<xsl:variable name="vPreceedingNotInRange"
select="$vFirstNotInRange/preceding-sibling::*"/>
<xsl:template match="/">
<xsl:copy-of select=
"$vPreceedingNotInRange
[count(.|$vFollowingP1)
=
count($vFollowingP1)
]"/>
================
<xsl:copy-of select=
"/*/p[@id='first']/following-sibling::*
[not(self::p or self::ul
or self::ol or self::blockquote
)
] [1]
/preceding-sibling::*
[count(.| /*/p[@id='first']/following-sibling::*)
=
count(/*/p[@id='first']/following-sibling::*)
]
"/>
</xsl:template>
</xsl:stylesheet>
当施加这种转变在下面的XML文档(所提供的非简洁(wellformed)XML片段 - 校正,并且包裹在为了造简洁(wellformed)):
<html>
<h1>Header</h1>
<p>Paragraph 1</p>
<p id="first">Paragraph 2</p>
<p>Paragraph 3</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<p>Paragraph 4</p>
<hr/>
<p>Paragraph 5</p>
<blockquote>Blockquote 1</blockquote>
</html>
两个XPath表达式(一个变量和一个与取代的所有变量)是EV aluated和想要的,正确的选择的节点输出:
<p>Paragraph 3</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<p>Paragraph 4</p>
================
<p>Paragraph 3</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<p>Paragraph 4</p>
II。 XPath 2。0溶液:
$vFirstNotInRange/preceding-sibling::*
[. >> $vP1]
这将选择的$vFirstNotInRange
前述任一兄弟,其也下列$vP1
和选择相同的通缉节点:
<p>Paragraph 3</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<p>Paragraph 4</p>
说明:在这里,我们使用XPath 2.0 “跟随”运营商>>
。
冗长而混乱。请提供一个简单的XML作为示例,并指出您要选择哪些节点 - 解释每个节点必须满足的规则。 “ – 2012-02-10 14:12:29
”以下所有的兄弟元素,但不包括第一个不是p,ul,ol或blockquote元素的兄弟元素“是冗长而混乱的? – Sean 2012-02-11 21:00:54
请编辑问题 - 没有多少人会阅读评论。 – 2012-02-12 00:06:33