XSLT:从另一个表中的一个表中获取for循环中的row元素

时间:2014-07-08 14:06:01

标签: xslt xslt-2.0

我的XML文件中有三个表:tableXtableAtableB

这是我的算法:

  • 浏览tableX的每个行元素并检查Xelement1是否为NULL(空)。
  • 如果匹配:
    • 浏览tableA中的每一行,并将行元素Aelement2的值与Xelement2的另一行元素tableX进行比较。
    • 如果匹配:
      • 浏览tableB的每个行元素,并将Belement1的行元素tableB的值与Aelement1的行元素tableA的值进行比较
      • 如果匹配:
        • 打印Belement2
        • 的另一个行元素tableB的值

目前我正在这样做并且正在运作:

<xsl:for-each select="/root/table[@name='tableX']/row">
  <xsl:variable name="rec" select="."/>
  <xsl:choose>
    <xsl:when test="Xelement1=''">
      <xsl:for-each select="/root/table[@name='tableA']/row">
        <xsl:variable name="member" select="."/>
        <xsl:if test="Aelement2=$rec/Xelement2">
          <xsl:for-each select="/root/table[@name='tableB']/row">
            <xsl:if test="Belement1=$member/Aelement1">
              <xsl:value-of select="Belement2"/>&#160
            </xsl:if>
          </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
      <!-- Xelement1 is not null -->
    </xsl:otherwise>
  </xsl:choose>
</xsl:for-each>

但是,我希望我可以访问,例如第三个Aelement1循环中的for-each,无需将其保存到变量member

另外,为什么这不起作用?

    [...]
      <xsl:for-each select="/root/table[@name='tableA']/row">
        <xsl:variable name="member" select="Aelement1"/>
        <xsl:if test="Aelement2=$rec/Xelement2">
          <xsl:for-each select="/root/table[@name='tableB']/row">
            <xsl:if test="Belement1=$member">
              <xsl:value-of select="Belement2"/>&#160
            </xsl:if>
          </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    [...]

最小但完整的XML示例:

<root>
    <table name="tableX">
      <row>
        <Xelement1>11</Xelement1>
        <Xelement2>3</Xelement2>
        <Xother>failure</Xother>
      </row>
      <row>
        <Xelement1>NULL</Xelement1>
        <Xelement2>9</Xelement2>
        <Xother>success</Xother>
      </row>
  </table>
  <table name="tableA">
    <row>
      <Aelement1>10</Aelement1>
      <Aelement2>16</Aelement2>
      <Aother>failure</Aother>
    </row>
    <row>
      <Aelement1>12</Aelement1>
      <Aelement2>9</Aelement2>
      <Aother>success</Aother>
    </row>
    <row>
      <Aelement1>12</Aelement1>
      <Aelement2>16</Aelement2>
      <Aother>failure</Aother>
    </row>
    <row>
      <Aelement1>14</Aelement1>
      <Aelement2>9</Aelement2>
      <Aother>success</Aother>
    </row>
  </table>
  <table name="tableB">
    <row>
      <Belement1>10</Belement1>
      <Belement2>failure</Belement2>
      <Bother>random</Bother>
    </row>
    <row>
      <Belement1>12</Belement1>
      <Belement2>success</Belement2>
      <Bother>random</Bother>
    </row>
    <row>
      <Belement1>14</Belement1>
      <Belement2>success</Belement2>
      <Bother>random</Bother>
    </row>
  </table>
</root>

3 个答案:

答案 0 :(得分:1)

我会定义一个键

<xsl:key name="row" match="table[@name = 'tableB']/row" use="Belement"/>

然后你可以缩短

<xsl:for-each select="/root/table[@name='tableA']/row">
  <xsl:variable name="member" select="."/>
  <xsl:for-each select="/root/table[@name='tableB']/row">
    <xsl:if test="Belement=$member/Aelement">
      <!--Do something-->
    </xsl:if>
  </xsl:for-each>
</xsl:for-each>

<xsl:for-each select="/root/table[@name='tableA']/row/key('row', Aelement)">
      <!--Do something-->
</xsl:for-each>

关于术语,您的代码会处理row elementsrow element nodes

对于不起作用的样本,您需要向我们展示最少但完整的XML输入样本,XSLT代码,您想要的结果,以及我们可以轻松重现问题的结果。

答案 1 :(得分:1)

您应该能够使用单个XPath表达式从表B中选择相应的行:

<xsl:for-each select="/root/table[@name = 'tableB']/row[
  Belement = /root/table[@name = 'tableA']/row/Aelement
]">
  <!-- Do something -->
</xsl:for-each>

这是因为XPath的=在节点集上运行时,将左侧的所有节点与右侧的所有节点进行比较(就像SQL中的INNER JOIN一样) )。

它将在您的示例中选择一个节点(即具有<row>的{​​{1}}),但如果有更多匹配则会选择更多节点。


在对问题进行实质性编辑之后,XPath表达式变得更加复杂。同样的原则也适用。

<Belement>5</Belement>

将从您的样本中选择包含//table[@name = 'tableB']/row[ Belement1 = //table[@name = 'tableA']/row[ Aelement2 = //table[@name = 'tableX']/row[ Xelement1 = 'NULL' ]/Xelement2 ]/Aelement1 ]/Belement2 的元素。

从里到外阅读:

  • 来自"success"tableX,您需要Xelement1 = 'NULL'
  • 来自Xelement2tableA对应您想要的Aelement2
  • 来自Aelement1tableB对应您想要的Belement1

答案 2 :(得分:1)

  

另外,为什么这不起作用?

> <xsl:for-each select="/root/table[@name='tableA']/row">  
>   <xsl:variable name="member" select="Aelement"/>   
>   <xsl:for-each select="/root/table[@name='tableB']/row">
>     <xsl:if test="Belement=$member">
>       <!--Do something-->
>     </xsl:if>
>   </xsl:for-each>
> </xsl:for-each>

实际上,确实有效。如果您尝试使用tableB中的匹配行实际执行某些操作,例如:

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

<xsl:template match="/">
    <output>
        <xsl:for-each select="/root/table[@name='tableA']/row">
            <xsl:variable name="member" select="Aelement"/>
            <xsl:for-each select="/root/table[@name='tableB']/row">
                <xsl:if test="Belement=$member">
                    <!--Do something-->
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

您将收到:

<?xml version="1.0" encoding="UTF-8"?>
<output>
  <row>
      <Belement>5</Belement>
    </row>
</output>