XSLT,使用基于属性值

时间:2017-10-27 12:10:43

标签: xml xslt

基于以下问题:XSLT, Renaming Elements using mapping table based on Attribute's value

如何将未在映射表中定义的元素(此处为示例99和100)收集到名为“customRecords”的元素中?

源XML:

<transaction>
  <records type="1" >
      <record type="1" >
        <field number="1" >
            <item>223</item>
        </field>
      </record>
  </records>

  <records type="14" >
      <record type="14" >
        <field number="1" >
            <item>777</item>
        </field>
      </record>
  </records>

  <records type="99" >
      <record type="99" >
        <field number="1" >
            <item>123</item>
        </field>
      </record>
      <record type="99" >
        <field number="1" >
            <item>765</item>
        </field>
      </record>
  </records>
  <records type="100" >
      <record type="100" >
        <field number="1" >
            <item>456</item>
        </field>
      </record>
      <record type="100" >
        <field number="1" >
            <item>121</item>
        </field>
      </record>
  </records>

</transaction>

映射表:

<xsl:stylesheet>
  <mapping type="1" from="record" to="first-record">
      <map number="1" from="field" to="great-field"/>
  </mapping>

  <mapping type="14" from="record" to="real-record">
      <map number="1" from="field" to="my-field"/>
  </mapping>     
</xsl:stylesheet>

目标XML:

<transaction>
  <records type="1" >
      <first-record type="1" >
        <great-field number="1" >
            <item >223</item>
        </great-field>
      </first-record>
  </records>

  <records type="14">
      <real-record type="14" >
        <my-field number="1" >
            <item >777</item>
        </my-field>
      </real-record>
  </records>

  <customRecords>
      <record type="99" >
        <field number="1" >
            <item>123</item>
        </field>
      </record>
      <record type="99" >
        <field number="1" >
            <item>765</item>
        </field>
      </record>
      <record type="100" >
        <field number="1" >
            <item>456</item>
        </field>
      </record>
      <record type="100" >
        <field number="1" >
            <item>121</item>
        </field>
      </record>
  </customRecords>

</transaction>

我们非常感谢任何建议。 在此先感谢您的努力。

1 个答案:

答案 0 :(得分:1)

我已经尝试调整该代码,我认为它目前为您的示例数据和映射提供了所需的XML输出,尽管Saxon在生成的代码中发出了关于ambigious模板的警告,我认为它们暂时可以被忽略。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
    exclude-result-prefixes="xs math axsl"
    version="3.0">

    <xsl:param name="mapping">      
        <mapping type="1" from="record" to="first-record">
            <map number="1" from="field" to="great-field"/>
        </mapping>

        <mapping type="14" from="record" to="real-record">
            <map number="1" from="field" to="my-field"/>
        </mapping>     
    </xsl:param>

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

    <xsl:variable name="stylesheet">
        <axsl:stylesheet version="3.0">
            <axsl:variable name="mapping">
                <xsl:copy-of select="$mapping/mapping"/>
            </axsl:variable>

            <axsl:key name="mapping" match="mapping" composite="yes" use="@from, @type"/>

            <axsl:mode name="copy" on-no-match="shallow-copy"/>

            <axsl:mode name="transform" on-no-match="shallow-copy"/>

            <axsl:template match="/*" mode="transform">
                <axsl:copy>
                    <axsl:apply-templates select="@*" mode="#current"/>
                    <axsl:apply-templates mode="#current"/>
                    <customElements>
                        <axsl:apply-templates select="*/*[not(key('mapping', (local-name(), @type), $mapping))]" mode="copy"/>
                    </customElements>
                </axsl:copy>
            </axsl:template>

            <xsl:apply-templates select="$mapping/mapping" mode="xslt-modes"/>

            <xsl:apply-templates select="$mapping/mapping" mode="xslt-code"/>
        </axsl:stylesheet>
    </xsl:variable>

    <xsl:template match="mapping" mode="xslt-modes">
        <axsl:mode name="transform-{position()}" on-no-match="shallow-copy"/>
    </xsl:template>

    <xsl:template match="mapping" mode="xslt-code">
        <axsl:template match="/*/*[not(*[key('mapping', (local-name(), @type), $mapping)])]" mode="transform"/>
        <axsl:template match="{@from}[@type = '{@type}']" mode="transform">
            <axsl:element name="{@to}">
                <axsl:apply-templates select="@* | node()" mode="transform-{position()}"/>
            </axsl:element>
        </axsl:template>
        <xsl:apply-templates mode="xslt-code">
            <xsl:with-param name="pos" select="position()"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="map" mode="xslt-code">
        <xsl:param name="pos"/>
        <axsl:template match="{@from}[@number = '{@number}']" mode="transform-{$pos}">
            <axsl:element name="{@to}">
                <axsl:apply-templates select="@* | node()" mode="#current"/>
            </axsl:element>
        </axsl:template>
    </xsl:template> 

    <xsl:template match="/">
        <xsl:message select="serialize($stylesheet, map { 'indent' : true() })"/>
        <xsl:sequence select="transform(map { 'source-node' : ., 'stylesheet-node' : $stylesheet , 'initial-mode' : xs:QName('transform') })?output"/>
    </xsl:template>

</xsl:stylesheet>

我目前还不确定如果有records的情况,你想要或者上面会产生什么样的输出,其中至少有一个孩子有一个映射但是对其他孩子没有。