【问题标题】:How to transform attributes into tags using XSLT and avoid duplicates?如何使用 XSLT 将属性转换为标签并避免重复?
【发布时间】:2013-08-15 13:33:06
【问题描述】:

首先,我在这里花了很多时间,并且经常在此处已经给出的答案中获得帮助。 但现在我面临一个新的话题 - XSLT - 我现在真的需要帮助。

好的,我遇到的问题是将我从 Excel 收到的 XML 文件转换为在 XFA 表单中重用它。 Excel 仅支持平面数据,但这与我的 XFA 表单的日期层次结构不匹配。

这是我从 Excel 收到的数据:

<Accounts>
    <Account Category="001" Region="AAA" Name="dolor" Value="123" Type="A" Rating="1,25"/>
    <Account Category="001" Region="AAA" Name="sit amet" Value="134" Type="A" Rating="1,25"/>
    <Account Category="004" Region="BBB" Name="consetetur" Value="434" Type="A" Rating="1,25"/>
    <Account Category="002" Region="AAA" Name="sadipscing" Value="84" Type="A" Rating="1,25"/>
    <Account Category="007" Region="ZZZ" Name="elitr" Value="33" Type="A" Rating="1,25"/>
    <Account Category="004" Region="CCC" Name="aliquyam" Value="6" Type="A" Rating="1,25"/>
    <Account Category="001" Region="BBB" Name="ipsum" Value="34" Type="A" Rating="1,25"/>
    <Account Category="003" Region="ZZZ" Name="lorem" Value="75" Type="A" Rating="2.87"/>
</Accounts>

这就是我想要改造它的方式:

<Accounts>
    <Category name="001">
        <Region name="AAA">
            <Account Name="dolor" Value="123" Type="A" Rating="1,25"/>
            <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/>
        </Region>   
        <Region name="BBB">
            <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/>
        </Region>
    </Category>
    <Category name="002">
        <Region name="BBB">
            <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/>
        </Region>
    </Category>
    <Category name="003">
        <Region name="ZZZ">
            <Account Name="lorem" Value="75" Type="A" Rating="2.87"/>
        </Region>
    </Category>
    ...
</Accounts>

我已经花了几天时间,但我唯一能做的就是为类别创建没有重复的新标签。 这是我当前的 XSLT 文件。

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

<xsl:variable name="Root" select="Accounts" />
<xsl:variable name="CategoryList" select="$Root/Account[not(@Category=following::Account/@Category)]" />

<xsl:template match="/">
    <Accounts>
        <xsl:for-each select="$CategoryList">
            <xsl:variable name="varCategory" select="./@Category" />
            <Category>
                <xsl:value-of select="$varCategory"/>
            </Category>
        </xsl:for-each>
    </Accounts>
</xsl:template>
</xsl:stylesheet>

欢迎任何帮助。

【问题讨论】:

    标签: xml excel xslt xfa


    【解决方案1】:

    您没有说您使用的是 XSLT 1.0 还是 XSLT 2.0。

    这是一个多级排序,对于 XSLT 1.0,我告诉我的学生使用基于变量的分组方法更容易编写。

    对于 XSLT 2.0,使用可用的构造很容易完成。

    两种解决方案都在这里:

    T:\ftemp>type mxps.xml 
    <Accounts>
        <Account Category="001" Region="AAA" Name="dolor" Value="123" Type="A" Rating="1,25"/>
        <Account Category="001" Region="AAA" Name="sit amet" Value="134" Type="A" Rating="1,25"/>
        <Account Category="004" Region="BBB" Name="consetetur" Value="434" Type="A" Rating="1,25"/>
        <Account Category="002" Region="AAA" Name="sadipscing" Value="84" Type="A" Rating="1,25"/>
        <Account Category="007" Region="ZZZ" Name="elitr" Value="33" Type="A" Rating="1,25"/>
        <Account Category="004" Region="CCC" Name="aliquyam" Value="6" Type="A" Rating="1,25"/>
        <Account Category="001" Region="BBB" Name="ipsum" Value="34" Type="A" Rating="1,25"/>
        <Account Category="003" Region="ZZZ" Name="lorem" Value="75" Type="A" Rating="2.87"/>
    </Accounts>
    T:\ftemp>call xslt mxps.xml mxps.xsl 
    <?xml version="1.0" encoding="utf-8"?>
    <Accounts>
       <Category name="001">
          <Region name="AAA">
             <Account Name="dolor" Value="123" Type="A" Rating="1,25"/>
             <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/>
          </Region>
          <Region name="BBB">
             <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="002">
          <Region name="AAA">
             <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="003">
          <Region name="ZZZ">
             <Account Name="lorem" Value="75" Type="A" Rating="2.87"/>
          </Region>
       </Category>
       <Category name="004">
          <Region name="BBB">
             <Account Name="consetetur" Value="434" Type="A" Rating="1,25"/>
          </Region>
          <Region name="CCC">
             <Account Name="aliquyam" Value="6" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="007">
          <Region name="ZZZ">
             <Account Name="elitr" Value="33" Type="A" Rating="1,25"/>
          </Region>
       </Category>
    </Accounts>
    T:\ftemp>type mxps.xsl 
    <?xml version="1.0" encoding="US-ASCII"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    version="1.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:template match="Accounts">
      <Accounts>
        <xsl:variable name="accounts" select="Account"/>
        <xsl:for-each select="$accounts">
          <xsl:sort select="@Category"/>
          <xsl:if test="generate-id(.)=
                        generate-id($accounts[@Category=current()/@Category][1])">
            <Category name="{@Category}">
              <xsl:variable name="categories"
                            select="$accounts[@Category=current()/@Category]"/>
              <xsl:for-each select="$categories">
                <xsl:sort select="@Region"/>
                <xsl:if test="generate-id(.)=
                           generate-id($categories[@Region=current()/@Region][1])">
                  <Region name="{@Region}">
                    <xsl:for-each select="$categories[@Region=current()/@Region]">
                      <xsl:sort select="@Name"/>
                      <Account>
                        <xsl:copy-of select="@Name"/>
                        <xsl:copy-of select="@Value"/>
                        <xsl:copy-of select="@Type"/>
                        <xsl:copy-of select="@Rating"/>
                      </Account>
                    </xsl:for-each>
                  </Region>
                </xsl:if>
              </xsl:for-each>
            </Category>
          </xsl:if>
        </xsl:for-each>
      </Accounts>
    </xsl:template>
    
    </xsl:stylesheet>
    T:\ftemp>call xslt2 mxps.xml mxps2.xsl 
    <?xml version="1.0" encoding="UTF-8"?>
    <Accounts>
       <Category name="001">
          <Region name="AAA">
             <Account Name="dolor" Value="123" Type="A" Rating="1,25"/>
             <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/>
          </Region>
          <Region name="BBB">
             <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="002">
          <Region name="AAA">
             <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="003">
          <Region name="ZZZ">
             <Account Name="lorem" Value="75" Type="A" Rating="2.87"/>
          </Region>
       </Category>
       <Category name="004">
          <Region name="BBB">
             <Account Name="consetetur" Value="434" Type="A" Rating="1,25"/>
          </Region>
          <Region name="CCC">
             <Account Name="aliquyam" Value="6" Type="A" Rating="1,25"/>
          </Region>
       </Category>
       <Category name="007">
          <Region name="ZZZ">
             <Account Name="elitr" Value="33" Type="A" Rating="1,25"/>
          </Region>
       </Category>
    </Accounts>
    
    T:\ftemp>type mxps2.xsl 
    <?xml version="1.0" encoding="US-ASCII"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    version="2.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:template match="Accounts">
      <Accounts>
        <xsl:for-each-group select="Account" group-by="@Category">
          <xsl:sort select="@Category"/>
            <Category name="{@Category}">
              <xsl:for-each-group select="current-group()" group-by="@Region">
                <xsl:sort select="@Region"/>
                  <Region name="{@Region}">
                    <xsl:for-each select="current-group()">
                      <xsl:sort select="@Name"/>
                      <Account>
                        <xsl:copy-of select="@Name,@Value,@Type,@Rating"/>
                      </Account>
                    </xsl:for-each>
                  </Region>
              </xsl:for-each-group>
            </Category>
        </xsl:for-each-group>
      </Accounts>
    </xsl:template>
    
    </xsl:stylesheet>
    T:\ftemp>rem Done! 
    

    【讨论】:

    • 抱歉,我忘了说我使用的是 XSLT 1.0。无论如何,您的解决方案都非常出色。非常感谢!
    猜你喜欢
    • 2021-08-13
    • 2011-05-26
    • 2022-01-02
    • 2017-05-12
    • 2018-10-12
    • 2017-12-25
    • 2015-07-31
    • 1970-01-01
    • 2014-11-11
    相关资源
    最近更新 更多