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

3

我有一段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

使用方法:

(/*/*//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表达式在足够大的文档上更有效率(因为它不使用//伪操作符)。


感谢您详细的回复!这正是我所需要的。只是为了澄清,第二个表达式以“((”开头,我可以看到调用中有一个闭合的“)”。显然,它们都需要才能正常工作。您能解释一下为什么吗?或者能否指点我一些相关资源?再次感谢! - Sarah Chen
哎呀,我看到另一个关闭了。现在有意义多了! - Sarah Chen
@SarahChen,不用谢。这些括号是为了覆盖“ []”运算符的优先级高于“//”伪运算符的优先级。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接