【问题标题】:Joining data from different xpath with xslt使用 xslt 连接来自不同 xpath 的数据
【发布时间】:2012-06-11 12:23:42
【问题描述】:

我正在尝试使用 XSLT 进行 xml 转换。我有以下 xml:

<myxml>
<dataType1>
    <value1>
        A1
    </value1>
    <value2>
        A2
    </value2>
</dataType1>
<dataType1>
    <value1>
        B1
    </value1>
    <value2>
        B2
    </value2>
</dataType1>
<dataType2>
    <value1>
        A1
    </value1>
    <value3>
        A3
    </value3>
</dataType2>
<dataType2>
    <value1>
        B1
    </value1>
    <value3>
        B3
    </value3>
</dataType2>

每个 datatype2 都有一个元素 value1,它是 datatype2 中的一个外键,所以我必须根据 value1 映射这个数据。

如果存在 value1=A1 的 dataType1 和 value1=A1 的 dataType2,那么我必须使用 value2 和 value3 创建一个 xml,因此结果如下:

<resultxml>
<data>
    <value2>
        A2
    </value2>
    <value3>
        A3
    </value3>
</data>
<data>
    <value2>
        B2
    </value2>
    <value3>
        B3
    </value3>
</data>

我考虑过在读取 dataType1 时动态创建变量,然后在读取 datatype2 时调用它们,但正如我在某些论坛上所读到的那样,这是不可能的,所以我的问题是:可以按照我的解释进行吗?如果是,这是我必须遵循的方法(欢迎举例)

提前致谢

【问题讨论】:

  • 这是 1:1 的关系吗?如果有多个dataType2对应value1,会发生什么?

标签: xslt


【解决方案1】:

这种转变

<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:key name="kType1" match="dataType1" use="normalize-space(value1)"/>

 <xsl:template match="dataType2[key('kType1', normalize-space(value1))]">
     <data>
       <value2>
         <xsl:value-of select="key('kType1', normalize-space(value1))/value2"/>
       </value2>
       <xsl:copy-of select="value3"/>
     </data>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的 XML 文档时

<myxml>
    <dataType1>
        <value1>
        A1
        </value1>
        <value2>
        A2
        </value2>
    </dataType1>
    <dataType1>
        <value1>
        B1
        </value1>
        <value2>
        B2
        </value2>
    </dataType1>
    <dataType2>
        <value1>
        A1
        </value1>
        <value3>
        A3
        </value3>
    </dataType2>
    <dataType2>
        <value1>
        B1
        </value1>
        <value3>
        B3
        </value3>
    </dataType2>
</myxml>

产生想要的正确结果

<data>
   <value2>
        A2
   </value2>
   <value3>
        A3
   </value3>
</data>
<data>
   <value2>
        B2
   </value2>
   <value3>
        B3
   </value3>
</data>

【讨论】:

    【解决方案2】:

    我的建议

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="xml" encoding="UTF-8" indent="no" />
        <xsl:template match="/">
            <resultxml>
                <xsl:for-each select="/myxml/dataType1">
                    <xsl:variable name="fk" select="value1" />
                    <data>
                        <xsl:copy-of select="value2" />
                        <xsl:copy-of select="/myxml/dataType2[value1 = $fk]/value3" />
                    </data>
                </xsl:for-each>
            </resultxml>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      【解决方案3】:

      这是一个 XSLT 2.0 样式表:

      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">
      
        <xsl:key name="k1" match="dataType2" use="normalize-space(value1)"/>
      
        <xsl:template match="@* | node()">
          <xsl:copy>
            <xsl:apply-templates select="@* , node()"/>
          </xsl:copy>
        </xsl:template>
      
        <xsl:template match="dataType1[key('k1', value1)]">
          <data>
            <xsl:apply-templates select="node() except value1, key('k1', normalize-space(value1))/*[not(self::value1)]"/>
          </data>
        </xsl:template>
      
        <xsl:template match="dataType1[not(key('k1', normalize-space(value1)))] | dataType2"/>
      
      </xsl:stylesheet>
      

      当上述样式表应用于输入时

      <myxml>
      <dataType1>
          <value1>
              A1
          </value1>
          <value2>
              A2
          </value2>
      </dataType1>
      <dataType1>
          <value1>
              B1
          </value1>
          <value2>
              B2
          </value2>
      </dataType1>
      <dataType2>
          <value1>
              A1
          </value1>
          <value3>
              A3
          </value3>
      </dataType2>
      <dataType2>
          <value1>
              B1
          </value1>
          <value3>
              B3
          </value3>
      </dataType2>
      </myxml>
      

      使用 Saxon 9.4 那么结果是

      <?xml version="1.0" encoding="UTF-8"?><myxml>
      <dataType1>
          <value1>
              A1
          </value1>
          <value2>
              A2
          </value2>
      </dataType1>
      <dataType1>
          <value1>
              B1
          </value1>
          <value2>
              B2
          </value2>
      </dataType1>
      
      
      </myxml>
      

      在 XSLT 1.0 中,您不能在匹配模式中使用键,因此需要更多代码,稍后我将添加示例。

      [编辑] 这是一个 XSLT 1.0 样式表:

      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
      
        <xsl:key name="k1" match="dataType2" use="normalize-space(value1)"/>
      
        <xsl:template match="@* | node()">
          <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
          </xsl:copy>
        </xsl:template>
      
        <xsl:template match="dataType1">
          <xsl:variable name="refs" select="key('k1', normalize-space(value1))"/>
          <xsl:if test="$refs">
            <data>
              <xsl:apply-templates select="node()[not(self::value1)] | $refs/*[not(self::value1)]"/>
            </data>
          </xsl:if>
        </xsl:template>
      
        <xsl:template match="dataType2"/>
      
      </xsl:stylesheet>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-21
        • 2013-09-24
        • 2021-12-03
        • 2018-02-06
        • 2014-07-10
        • 1970-01-01
        • 1970-01-01
        • 2022-10-07
        相关资源
        最近更新 更多