使用xpath选择第一个结果的子项

时间:2012-10-26 18:42:53

标签: php xml xpath simplexml

我有一段XML,其中相同的信息可以显示为不同节点的子节点。如:

<root>
<category id=1>
        <product id="ABC123" >

              <sizes>
                    <size name="S"/>
                <size name="M"/>
                <size name="L"/>
                <size name="XL"/>
                <size name="2XL"/>
                <size name="3XL"/>
              </sizes>
            </product>

                 </products>
           </category>
<category id=2>
        <products>
        <product id="ABC123" >

              <sizes>
                    <size name="S"/>
                <size name="M"/>
                <size name="L"/>
                <size name="XL"/>
                <size name="2XL"/>
                <size name="3XL"/>
              </sizes>
            </product>

          <product id="PPP543" >

              <sizes>
                    <size name="S"/>
                <size name="M"/>
                <size name="L"/>
                <size name="XL"/>
              </sizes>
            </product>

                 </products>
           </category>

我的目标是选择产品ID ABC123的大小并将它们存储为数组。我当前的代码是:

$arrTest=array();


    foreach($xml->xpath('//root/category/products/product[@id= "'.$productCall.'" ]/sizes/size') as $size){

              array_push($arrTest, $size["name"]);
      }

$ productCall是我要找的id。在这种情况下,它是ABC123。

输出为S,M,L,XL,2XL,3XL,S,M,L,XL,2XL,3XL。这意味着它正在读取找到的两个条目。我期待这个foreach循环,但我似乎无法找到一种方法来获得第一个结果的输出。我试过添加[0]和[1]:

$y=$xml->xpath('//root/category/products/product[@id= "'.$productCall.'" ][1]/sizes/size');

[0]什么都不返回,[1]返回我已经得到的相同结果。

我希望这是一个简单的问题,我错过了一些基本或过度思考的东西,因为我之前没有使用过xpath。

1 个答案:

答案 0 :(得分:0)

使用

(/*/*//product[@id='ABC123']/sizes)[1]/size

或使用

((/*/*/product | /*/*/products/product)/sizes)[1]/size

基于XSLT的验证

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
    "(/*/*//product[@id='ABC123']/sizes)[1]/size"/>
========
  <xsl:copy-of select=
    "((/*/*/product | /*/*/products/product)/sizes)[1]/size"/>

 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档(在将其更正为格式良好的文档后):

<root>
    <category id="1">
        <product id="ABC123" >
            <sizes>
                <size name="S"/>
                <size name="M"/>
                <size name="L"/>
                <size name="XL"/>
                <size name="2XL"/>
                <size name="3XL"/>
            </sizes>
        </product>
    </category>
    <category id="2">
        <products>
            <product id="ABC123" >
                <sizes>
                    <size name="S"/>
                    <size name="M"/>
                    <size name="L"/>
                    <size name="XL"/>
                    <size name="2XL"/>
                    <size name="3XL"/>
                </sizes>
            </product>
            <product id="PPP543" >
                <sizes>
                    <size name="S"/>
                    <size name="M"/>
                    <size name="L"/>
                    <size name="XL"/>
                </sizes>
            </product>
        </products>
    </category>
</root>

评估两个XPath表达式,并将每个选定节点(视觉上分隔的边界)复制到输出中 - 两者都正确

<size name="S"/>
<size name="M"/>
<size name="L"/>
<size name="XL"/>
<size name="2XL"/>
<size name="3XL"/>
========
  <size name="S"/>
<size name="M"/>
<size name="L"/>
<size name="XL"/>
<size name="2XL"/>
<size name="3XL"/>

请注意:我希望第二个XPath表达式更有效(在足够大的文档上),因为它不使用//伪运算符。