XSLT 2.0 - 如何将平面 XML 结构转换为嵌套/分层 XML 结构

问题描述 投票:0回答:1

我想使用 XSLT 2.0 将以下平面 XML 结构转换为嵌套/分层 XML 结构。

<?xml version="1.0" encoding="UTF-8"?>
<products>
    <productlist>
        <product id="prod_lmo" parent-id="product_family"><prodname>LMO</prodname></product>
        <product id="prod_sdf" parent-id="product_family"><prodname>SDF</prodname></product>
        <product id="prod_sdfg" parent-id="prod_sdf"><prodname>SDFg</prodname></product>
        <product id="prod_abc123" parent-id="prod_abc"><prodname>ABC-123</prodname></product>
        <product id="prod_sdfh" parent-id="prod_sdfg"><prodname>SDF-h</prodname></product>
        <product id="prod_family" parent-id="root"><prodname>Product Family</prodname></product>
        <product id="prod_sdfj" parent-id="prod_sdfh"><prodname>SDF-j</prodname></product>
        <product id="prod_lmao" parent-id="prod_lmo"><prodname>LMAO</prodname></product>
        <product id="prod_elo" parent-id="product_family"><prodname>ELO</prodname></product>
        <product id="prod_lmfao" parent-id="prod_lmo"><prodname>LMFAO</prodname></product>
        <product id="prod_abc" parent-id="product_family"><prodname>ABC</prodname></product>
    </productlist>
</products>

使用每个元素的parent-id 属性我想创建一个嵌套层次结构。如果一个元素的parent-id属性值与另一个元素的id属性匹配 - 那么它就成为该元素的子元素。

这是我想要实现的目标:

<?xml version="1.0" encoding="UTF-8"?>
<products>
    <productlist>
        <product id="product_family" parent-id="root"><prodname>Product Family</prodname>
            <product id="prod_elo" parent-id="product_family"><prodname>ELO</prodname></product>
            <product id="prod_lmo" parent-id="product_family"><prodname>LMO</prodname>
                <product id="prod_lmao" parent-id="prod_lmo"><prodname>LMAO</prodname></product>
                <product id="prod_lmfao" parent-id="prod_lmo"><prodname>LMFAO</prodname></product>
            </product>
            <product id="prod_sdf" parent-id="product_family"><prodname>SDF</prodname>
                <product id="prod_sdfg" parent-id="prod_sdf"><prodname>SDFg</prodname>
                    <product id="prod_sdfh" parent-id="prod_sdfg"><prodname>SDF-h</prodname>
                        <product id="prod_sdfj" parent-id="prod_sdfh"><prodname>SDF-j</prodname></product>
                    </product>
                </product>
            </product>        
            <product id="prod_abc" parent-id="product_family"><prodname>ABC</prodname>
                <product id="prod_abc123" parent-id="prod_abc"><prodname>ABC-123</prodname></product>
            </product>
        </product>
    </productlist>
</products>

我已经研究过使用键和for-each-group,但我不知道如何应用它们以及必要的递归。任何帮助将不胜感激。

我有以下内容:

<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:key name="children" match="product" use="@parentid"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="products/productlist">
    <products>
      <productlist>
        <xsl:for-each select="product[@parentid='root']">
          <product>
            <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
            <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
            <xsl:copy-of select="prodname"/>
            
            <xsl:for-each select="key('children', @id)">              
              <product>
                <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                <xsl:copy-of select="prodname"/>
                
                <xsl:for-each select="key('children', @id)">
                  <product>
                    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                    <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                    <xsl:copy-of select="prodname"/>
                    
                    <xsl:for-each select="key('children', @id)">
                      <product>
                        <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                        <xsl:copy-of select="prodname"/>    
                      </product>             
                    </xsl:for-each>
                    
                  </product>             
                </xsl:for-each>
              </product>             
            </xsl:for-each>
                
          </product>
        </xsl:for-each>
      </productlist>
    </products>
  </xsl:template>
</xsl:stylesheet>

经过 Martin Honnen 的敏锐观察,现在可以使用了! - 将 id 属性值从

prod_family
更正为
product_family

xml xslt xslt-2.0
1个回答
0
投票

正如我在评论中所说,递归是通过 apply-templates 完成的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">
  
  <xsl:key name="child" match="product" use="@parent-id"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="productlist">
    <xsl:copy>
      <xsl:apply-templates select="key('child', 'root')"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="product">
    <xsl:copy>
      <xsl:apply-templates select="@*, node(), key('child', @id)"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
© www.soinside.com 2019 - 2024. All rights reserved.