我的结构类似于以下内容:
<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来实现它的价值。
答案 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))]