XSLT Create a hierarchical structure from a flat structure by using certain level criteria

后端 未结 2 1254
被撕碎了的回忆
被撕碎了的回忆 2021-01-26 08:18

I want to create a XSD structure from an Excel output using XSLT. But my XSLT does not generate the hierarchical structure, correctly. It has some additional nodes in an element

相关标签:
2条回答
  • 2021-01-26 08:44

    Here is a suggestion using a recursive function:

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:mf="http://example.com/mf"
      exclude-result-prefixes="mf">
    
      <xsl:output indent="yes"/>
    
      <xsl:function name="mf:group" as="element()*">
          <xsl:param name="nodes" as="element(node)*"/>
          <xsl:param name="level" as="xs:integer"/>
          <xsl:for-each-group select="$nodes" group-starting-with="node[metaInfo/Level = $level and @groupMaxOccurs != '']">
            <xs:element name="{@nodeTag}" minOccurs="{@minOccurs}" maxOccurs="{@groupMaxOccurs}" id="{metaInfo/ID}">
                <xs:element name="{@nodeTag}" minOccurs="0" maxOccurs="1" id="{metaInfo/ID}"/>
                <xsl:choose>
                    <xsl:when test="(current-group() except .)/metaInfo/Level = $level + 1">
                        <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group() except ."/>
                    </xsl:otherwise>
                </xsl:choose>
            </xs:element>
          </xsl:for-each-group>
      </xsl:function>
    
      <xsl:template match="nodes">
          <xs:schema>
              <xsl:sequence select="mf:group(node, 1)"/>
          </xs:schema>
      </xsl:template>
    
      <xsl:template match="node">
          <xs:element name="{@nodeTag}" minOccurs="0" maxOccurs="{@segmentMaxOccurs}" id="{metaInfo/ID}"/>
      </xsl:template>
    
    </xsl:transform>
    

    You will have to test yourself with more levels or provide some input samples with deeper nesting to allow us to test.

    0 讨论(0)
  • 2021-01-26 08:55

    Let me suggest a different approach to creating the nested hierarchy. To demonstrate, I will use the following minimized input:

    XML

    <nodes>
       <node nodeTag="A">
          <metaInfo>
             <Level>1</Level>
          </metaInfo>
       </node>
       <node nodeTag="Ab">
          <metaInfo>
             <Level>2</Level>
          </metaInfo>
       </node>
       <node nodeTag="Ab1">
          <metaInfo>
             <Level>3</Level>
          </metaInfo>
       </node>
       <node nodeTag="Ab2">
          <metaInfo>
             <Level>3</Level>
          </metaInfo>
       </node>
       <node nodeTag="Ac">
          <metaInfo>
             <Level>2</Level>
          </metaInfo>
       </node>
       <node nodeTag="B">
          <metaInfo>
             <Level>1</Level>
          </metaInfo>
       </node>
       <node nodeTag="C">
          <metaInfo>
             <Level>1</Level>
          </metaInfo>
       </node>
       <node nodeTag="D">
          <metaInfo>
             <Level>1</Level>
          </metaInfo>
       </node>
       <node nodeTag="Da">
          <metaInfo>
             <Level>2</Level>
          </metaInfo>
       </node>
       <node nodeTag="Db">
          <metaInfo>
             <Level>2</Level>
          </metaInfo>
       </node>
    </nodes>
    

    Applying the following stylesheet:

    XSLT

    <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="child-by-parent" 
             match="node" 
             use="generate-id(preceding-sibling::node[metaInfo/Level=current()/metaInfo/Level - 1][1])" />
    
    <xsl:template match="nodes">
        <root>
            <xsl:apply-templates select="node[metaInfo/Level=1]"/>
        </root>
    </xsl:template>
    
    <xsl:template match="node">
        <element name="{@nodeTag}">
            <xsl:apply-templates select="key('child-by-parent', generate-id())"/>
        </element>
    </xsl:template>
    
    </xsl:stylesheet>
    

    will return:

    Result

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <element name="A">
          <element name="Ab">
             <element name="Ab1"/>
             <element name="Ab2"/>
          </element>
          <element name="Ac"/>
       </element>
       <element name="B"/>
       <element name="C"/>
       <element name="D">
          <element name="Da"/>
          <element name="Db"/>
       </element>
    </root>
    

    This works recursively with any number of levels.

    0 讨论(0)
提交回复
热议问题