Xpath:选择节点但不选择特定的子元素

时间:2011-08-19 01:02:12

标签: xpath

我的结构类似于以下内容:

<page id='1'>
  <title>Page 1</title>    
  <page id='2'>
    <title>Sub Page 1</title>
  </page>
  <page id='3'>
    <title>Sub Page 2</title>
  </page>    
</page>
<page id='4'>
  <title>Page 2</title>
</page>

我需要按Id选择页面,但如果该页面有后代页面,我不想返回这些元素,但我确实想要该页面的其他元素。如果我选择Page 1我想要返回标题而不是子页面...

//page[@id=1]

以上是第1页,但如何排除子页面?此外,页面中可以有任意数量的元素。

//page[@id=1]/*[not(self::page)]

我发现这可以获得我想要的数据。但是,该数据作为一个对象数组返回,每个元素有一个对象,显然不包括元素名称???我正在使用PHP SimpleXML来实现它的价值。

3 个答案:

答案 0 :(得分:8)

使用

//page[@id=$yourId]/node()[not(self::page)]

这将选择文档中不是page且属于任何page的子节点的所有节点,其id属性的字符串值等于{{{}}中包含的字符串1}}(很可能你会用上面的$yourId替换特定的所需字符串,例如$yourId)。

以下是一个简单的基于XSLT的验证

'1'

将此转换应用于提供的XML文档(包装在单个顶级节点中以使其格式正确):

<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:param name="pId" select="3"/>

 <xsl:template match="/">
     <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/>
 </xsl:template>
</xsl:stylesheet>

产生了想要的正确结果

<pages>
    <page id='1'>
        <title>Page 1</title>
        <page id='2'>
            <title>Sub Page 1</title>
        </page>
        <page id='3'>
            <title>Sub Page 2</title>
        </page>
    </page>
    <page id='4'>
        <title>Page 2</title>
    </page>
</pages>

请注意:一个假设是<title>Sub Page 2</title> 值唯一标识id。如果不是这样,建议的XPath表达式将选择所有 page元素,其page属性的字符串值为id

如果是这种情况,并且只能选择一个$yourId元素,则OP必须指定应选择具有此page的多个page元素中的哪一个。

例如,它可能是第一个

id

或最后

(//page[@id=$yourId]/node()[not(self::page)])[1]

或......

答案 1 :(得分:1)

如果你只对title元素感兴趣,那就可以了:

//page[@id=1]/title

如果您需要页面的其他子元素,我不确定XPath是否适合您。 听起来更像XSLT适合的东西,因为你真正在做的是改变你的数据。

答案 2 :(得分:0)

如果页面总是有标题:

//page[@id='1']/*[not(boolean(./title))]