【问题标题】:XSL: sorting the document in first transform and then transform based on keyXSL:在第一次转换中对文档进行排序,然后根据键进行转换
【发布时间】:2022-09-28 20:42:22
【问题描述】:

转换原始文档时无法达到预期效果:

<fact>
    <id>84f4ab12-64e5-4905-9a4f-8935addf7b31</id>
    <decisionDate>2021-12-01</decisionDate>
    <receiver>
        <surname>Kim</surname>
        <firstname>Alla</firstname>
        <addressInfo>
            <type>
                <code>03</code>
                <title>Actual residence</title>
            </type>
            <country>
                <code>033</code>
                <title>Actual residence country</title>
            </country>
            <postIndex>333333</postIndex>
            <region>Region3</region>
        </addressInfo>
        <addressInfo>
            <type>
                <code>01</code>
                <title>Permanent residence</title>
            </type>
            <country>
                <code>011</code>
                <title>Permanent residence country</title>
            </country>
            <postIndex>111111</postIndex>
            <region>Region1</region>
        </addressInfo>  
        <addressInfo>
            <type>
                <code>02</code>
                <title>Temporary residence</title>
            </type>
            <country>
                <code>022</code>
                <title>Temporary residence country</title>
            </country>
            <postIndex>222222</postIndex>
            <region>Region2</region>
        </addressInfo>  
    </receiver>
</fact> 

要求:

  1. 将每个地址块转换为名称对应地址类型的块
  2. 将转换后的地址块包装成一个“地址”
  3. 确保块按照 xsd 的特定顺序(PermanentResidence -> TemporaryResidence -> ActualResidence)

    可以实现地址块的单独转换并包装成一个公共标签(基于 xsl:key):

    <xsl:stylesheet version=\"2.0\"
                    xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
        <xsl:strip-space elements=\"*\"/>
    
        <xsl:template match=\"node()|@*\">
            <xsl:copy>
                <xsl:apply-templates select=\"node()|@*\"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:key name=\"addressFollowing\" match=\"addressInfo[preceding-sibling::*[1][self::addressInfo]]\"
                use=\"generate-id(preceding-sibling::addressInfo
             [not(preceding-sibling::*[1][self::addressInfo])][1])\"/>
    
        <xsl:template match=\"addressInfo[not(preceding-sibling::*[1][self::addressInfo])]\">
            <xsl:element name=\"Address\">
                <xsl:call-template name=\"address\"/>
                <xsl:apply-templates mode=\"copy\" select=\"key(\'addressFollowing\', generate-id())\">
                    <xsl:sort select=\"type/code\" />
                </xsl:apply-templates>
            </xsl:element>
        </xsl:template>
    
        <xsl:template match=\"addressInfo[preceding-sibling::*[1][self::addressInfo]]\"/>
    
        <xsl:template match=\"addressInfo\" mode=\"copy\" name=\"address\">
            <xsl:variable name=\"addressType\">
                <xsl:if test=\"(.//type//code)=01\">
                    <xsl:value-of select=\"\'PermanentResidence\"/>
                </xsl:if>
                <xsl:if test=\"(.//type//code)=02\">
                    <xsl:value-of select=\"\'TemporaryResidence\"/>
                </xsl:if>
                <xsl:if test=\"(.//type//code)=03\">
                    <xsl:value-of select=\"\'ActualResidence\"/>
                </xsl:if>
            </xsl:variable>
            <xsl:element name=\"{$addressType}\">
                <xsl:element name=\"country\">
                    <xsl:value-of select=\".//country//code\"/>
                </xsl:element>
                <xsl:element name=\"postIndex\">
                    <xsl:value-of select=\".//postIndex\"/>
                </xsl:element>
                <xsl:element name=\"region\">
                    <xsl:value-of select=\".//region\"/>
                </xsl:element>
            </xsl:element>
        </xsl:template>
    
    </xsl:stylesheet>
    

    以及源文档中地址块的排序:

    <xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
    
      <xsl:strip-space elements=\"*\"/>
    
      <xsl:template match=\"@*|node()\">
        <xsl:copy>
          <xsl:apply-templates select=\"@*|node()\">
                <xsl:sort select=\"type/code\" />                
            </xsl:apply-templates>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    组合转换忽略地址块的排序。

    请帮助在一个 xsl 中实现组合结果。 我试图实现基于变量和模式的双重转换,但没有。 主要思想:在第一次转换中对文档进行排序,然后根据键进行转换。

    对不起我的英语不好

    更新:期望的结果:

    <fact>
       <id>84f4ab12-64e5-4905-9a4f-8935addf7b31</id>
       <decisionDate>2021-12-01</decisionDate>
       <receiver>
          <surname>Kim</surname>
          <firstname>Alla</firstname>
          <Address>
             <PermanentResidence>
                <country>011</country>
                <postIndex>111111</postIndex>
                <region>Region1</region>
             </PermanentResidence>
             <TemporaryResidence>
                <country>022</country>
                <postIndex>222222</postIndex>
                <region>Region2</region>
             </TemporaryResidence>
             <ActualResidence>
                <country>033</country>
                <postIndex>333333</postIndex>
                <region>Region3</region>
             </ActualResidence>      
          </Address>
       </receiver>
    </fact>
    
  • 您使用的是 XSLT 2 处理器吗?您可以将预期结果添加到问题中吗?

标签: xslt xslt-2.0


【解决方案1】:

假设 XSLT 2,我认为你可以使用

<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="receiver">
      <xsl:copy>
        <xsl:for-each-group select="*" group-adjacent="boolean(self::addressInfo)">
          <xsl:choose>
            <xsl:when test="current-grouping-key()">
              <Address>
                <xsl:apply-templates select="current-group()">
                  <xsl:sort select="type/code"/>
                </xsl:apply-templates>
              </Address>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="addressInfo">
        <xsl:variable name="addressType">
            <xsl:if test="(.//type//code)=01">
                <xsl:value-of select="'PermanentResidence'"/>
            </xsl:if>
            <xsl:if test="(.//type//code)=02">
                <xsl:value-of select="'TemporaryResidence'"/>
            </xsl:if>
            <xsl:if test="(.//type//code)=03">
                <xsl:value-of select="'ActualResidence'"/>
            </xsl:if>
        </xsl:variable>
        <xsl:element name="{$addressType}">
            <xsl:apply-templates select="country/code, postIndex, region"/>
        </xsl:element>
    </xsl:template>
    
    <xsl:output indent="yes"/>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-22
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    • 2014-12-02
    相关资源
    最近更新 更多