XSLT如何通过其属性匹配两个XML节点?

时间:2012-08-21 16:18:47

标签: xslt

我有一个我正在尝试转换的XML,其中包含不同节点之间的关系,通过ID相关,但我无法弄清楚如何将它们“粘合”在一起。

XML示例:

<order>
 <products>     
  <product id="1234">
   <item quantity="5" colour="red">
   <item quantity="2" colour="blue">
  </product> 
  <product id="9876">
   <item quantity="10" colour="teal">
  </product>
 </products>

 <prices>
  <productprice>
   <refProduct id="1234" />
   <price gross="9.99" />
  </productprice>
  <productprice>
   <refProduct id="9876" />
   <price gross="6.89" />
  </productprice>
 </prices>
</order>

我希望的结果是能够通过for-each显示产品,并在它们旁边列出各自的价格。

感激地收到了任何线索。

编辑:固定叛徒产品元素,例子应该是格式良好的

3 个答案:

答案 0 :(得分:1)

以下是进行所需连接的简单概念验证。输入XML没有很好地形成,所以我假设只有一个产品元素,有多个产品子元素。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <products>
            <xsl:for-each select="order/products/product">
                <product>
                    <xsl:variable name="productid" select="@id"/>
                    <xsl:attribute name="id">
                        <xsl:value-of select="$productid"/>
                    </xsl:attribute>
                    <xsl:attribute name="price">
                        <xsl:value-of
                            select="/order/prices/productprice[refProduct[@id = $productid]]/price/@gross"/>
                    </xsl:attribute>
                </product>
            </xsl:for-each>
        </products>
    </xsl:template>
</xsl:stylesheet>

它产生以下输出:

<?xml version="1.0" encoding="utf-8"?>
<products>
    <product id="1234" price="9.99"/>
    <product id="9876" price="6.89"/>
</products>

答案 1 :(得分:0)

您的XML格式不正确,这使得很难准确回答这个问题。但是有些事情可能就是这样吗?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <out>
      <xsl:apply-templates/>
    </out>
  </xsl:template>
  <xsl:template match="/root/order/products/product">
    <xsl:variable name="id" select="string(@id)" />
    <prod id="{@id}">
      <xsl:value-of select="/root/prices/productprice[refProduct/@id=$id]/price/@gross" />
    </prod>
  </xsl:template>
</xsl:stylesheet>

显然,根据XML的结构,确切的XPath会有所不同,但是这样的东西会匹配产品与价格。如果您需要迭代产品,可以将其移动到函数中。

答案 2 :(得分:0)

在查找元素方面,这是使用 xsl:key 的理想情况。因此,对于您的样本,您可能希望查找产品的价格,因此您可以像这样定义密钥

<xsl:key name="prices" match="productprice" use="refProduct/@id" />

因此,这将允许您使用产品ID的值访问 productprice 元素。具体来说,如果您定位在产品元素上,则可以访问该密钥以获得总价格,如下所示:

<xsl:value-of select="key('prices', @id)/price/@gross" />

至于展示产品,一般来说,通常最好使用 xsl:apply-templates 而不是 xsl:for-each ,因为它更像是在'精神'中XSLT。

<xsl:apply-templates select="products/product" />

可以在多个地方调用模板以减少代码重复,并且可以使代码更具可读性,尤其是通过减少代码缩进。

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="prices" match="productprice" use="refProduct/@id" />

   <xsl:template match="/order">
      <table>
      <xsl:apply-templates select="products/product" />
      </table>
   </xsl:template>

   <xsl:template match="product">
      <tr>
         <td><xsl:value-of select="@id" /></td>
         <td><xsl:value-of select="key('prices', @id)/price/@gross" /></td>
      </tr>
   </xsl:template>
</xsl:stylesheet>

应用于以下格式良好的XML

<order>
   <products>
      <product id="1234">
         <item quantity="5" colour="red"/>
         <item quantity="2" colour="blue"/>
      </product>
      <product id="9876">
         <item quantity="10" colour="teal"/>
      </product>
   </products>
   <prices>
      <productprice>
         <refProduct id="1234"/>
         <price gross="9.99"/>
      </productprice>
      <productprice>
         <refProduct id="9876"/>
         <price gross="6.89"/>
      </productprice>
   </prices>
</order>

以下是输出

<table>
  <tr>
    <td>1234</td>
    <td>9.99</td>
  </tr>
  <tr>
    <td>9876</td>
    <td>6.89</td>
  </tr>
</table>