XSLT使用某些级别标准从平面结构创建层次结构

时间:2016-01-12 23:40:13

标签: xml xslt xsd xslt-2.0

我想使用XSLT从Excel输出创建XSD结构。但是我的XSLT没有正确生成层次结构。如果具有相同匹配参数的这些节点在稍后的组中定义,并且在层次结构中具有相同级别,则它在元素组中具有一些额外节点。

Excel XML输出如下所示:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <nodes>
    <node typeTag="Test" nodeTag="GGG" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>40</ID><Level>1</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="BBB" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>60</ID><Level>2</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="XXX" minOccurs="0" segmentMaxOccurs="1000000" groupMaxOccurs="">
        <metaInfo><ID>80</ID><Level>2</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="AAA" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>90</ID><Level>1</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="WWW" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>110</ID><Level>1</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="OOO" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>130</ID><Level>1</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="AAA" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>140</ID><Level>2</Level></metaInfo>
    </node>
    <node typeTag="Test" nodeTag="WWW" minOccurs="0" segmentMaxOccurs="1" groupMaxOccurs="1000000">
        <metaInfo><ID>160</ID><Level>2</Level></metaInfo>
    </node>
 </nodes>

每个节点都应该是一个元素,其中@segmentMaxOccurs!= 0将生成叶元素,而@groupMaxOccurs将生成组元素。元素&#34;等级&#34;定义结构的层次结构(它应该是嵌套结构)和元素&#34; ID&#34;是有序的唯一标识符。

基于此输入,我想获得以下XSD结构。为了专注于我的问题,我删除了所有不相关的项目,例如&#34; xs:sequence&#34;或&#34; xs:complexType&#34;:

<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name="Test">
    <xs:element name="GGG" minOccurs="0" maxOccurs="1000000" id="40">
        <xs:element name="GGG" minOccurs="0" maxOccurs="1" id="40"/>
        <xs:element name="BBB" minOccurs="0" maxOccurs="1000000" id="60">
            <xs:element name="BBB" minOccurs="0" maxOccurs="1" id="60"/>
            <xs:element name="XXX" minOccurs="0" maxOccurs="1000000" id="80"/>
        </xs:element>
    </xs:element>
    <xs:element name="AAA" minOccurs="0" maxOccurs="1000000" id="90">
        <xs:element name="AAA" minOccurs="0" maxOccurs="1" id="90"/>
    </xs:element>
    <xs:element name="WWW" minOccurs="0" maxOccurs="1000000" id="110">
        <xs:element name="WWW" minOccurs="0" maxOccurs="1" id="110"/>
    </xs:element>
    <xs:element name="OOO" minOccurs="0" maxOccurs="1000000" id="130">
        <xs:element name="OOO" minOccurs="0" maxOccurs="1" id="130"/>
        <xs:element name="AAA" minOccurs="0" maxOccurs="1000000" id="140">
            <xs:element name="AAA" minOccurs="0" maxOccurs="1" id="140"/>
        </xs:element>
        <xs:element name="WWW" minOccurs="0" maxOccurs="1000000" id="160">
            <xs:element name="WWW" minOccurs="0" maxOccurs="1" id="160"/>
        </xs:element>
    </xs:element>
</xs:element>

但我得到以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name="Test">
    <xs:element name="GGG" minOccurs="0" maxOccurs="1000000" id="40">
        <xs:element name="GGG" minOccurs="0" maxOccurs="1" id="40"/>
        <xs:element name="BBB" minOccurs="0" maxOccurs="1000000" id="60">
            <xs:element name="BBB" minOccurs="0" maxOccurs="1" id="60"/>
            <xs:element name="XXX" minOccurs="0" maxOccurs="1000000" id="80"/>
        </xs:element>
        <xs:element name="AAA" minOccurs="0" maxOccurs="1000000" id="140">
            <xs:element name="AAA" minOccurs="0" maxOccurs="1" id="140"/>
        </xs:element>
        <xs:element name="WWW" minOccurs="0" maxOccurs="1000000" id="160">
            <xs:element name="WWW" minOccurs="0" maxOccurs="1" id="160"/>
        </xs:element>
    </xs:element>
    <xs:element name="AAA" minOccurs="0" maxOccurs="1000000" id="90">
        <xs:element name="AAA" minOccurs="0" maxOccurs="1" id="90"/>
    </xs:element>
    <xs:element name="WWW" minOccurs="0" maxOccurs="1000000" id="110">
        <xs:element name="WWW" minOccurs="0" maxOccurs="1" id="110"/>
    </xs:element>
    <xs:element name="OOO" minOccurs="0" maxOccurs="1000000" id="130">
        <xs:element name="OOO" minOccurs="0" maxOccurs="1" id="130"/>
        <xs:element name="AAA" minOccurs="0" maxOccurs="1000000" id="140">
            <xs:element name="AAA" minOccurs="0" maxOccurs="1" id="140"/>
        </xs:element>
        <xs:element name="WWW" minOccurs="0" maxOccurs="1000000" id="160">
            <xs:element name="WWW" minOccurs="0" maxOccurs="1" id="160"/>
        </xs:element>
    </xs:element>
</xs:element>

小组&#34; GGG&#34;有两个附加组AAA(id = 140)和WWW(id = 160),它们应该在组OOO下面。您是否有任何想法,如何处理GGG的正确节点,直到组AAA(id = 90),它与元素组#34; GGG&#34;处于同一级别。我不知道如何消耗这些节点,这些节点只属于元素组&#34; GGG&#34;。

这是XSLT的一部分,它与生成层次结构相关:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nestor="http://sap.com/ia" xmlns:ns1="http://www.sap.com/ia" xmlns:functx="http://sap.com/xslt/functions">
    <xsl:output method="xml" indent="yes"/>
    <xsl:param name="pRootNode" select="'Test'"/>
    <xsl:template match="nodes">
        <xsl:variable name="vRootNode" select="$pRootNode"/>
        <xsl:element name="xs:element">
            <xsl:attribute name="name" select="$vRootNode"/>
            <xsl:variable name="vLevel" select="0"/>
            <xsl:variable name="vNextLevel" select="1"/>
            <xsl:variable name="vGroupCounter" select="node[@typeTag = $vRootNode and @groupMaxOccurs != '']"/>
            <xsl:apply-templates select="node[@typeTag = $vRootNode and ((@groupMaxOccurs != '' and ./metaInfo/Level = $vNextLevel) or (@groupMaxOccurs = '' and ./metaInfo/Level = $vLevel))]" mode="MessageStructure">
                <xsl:with-param name="pRootNode" select="$vRootNode"/>
                <xsl:with-param name="pLevel" select="$vLevel"/>
                <xsl:with-param name="pGroupCounter" select="$vGroupCounter"/>
            </xsl:apply-templates>
        </xsl:element>
    </xsl:template>
    <xsl:template match="node[@groupMaxOccurs = '']" mode="MessageStructure">
        <xsl:param name="pRootNode"/>
        <xsl:param name="pLevel"/>
        <xsl:param name="pGroupCounter"/>
        <xsl:variable name="vActGroupCounter" select="count(following-sibling::node[@typeTag = $pRootNode and @groupMaxOccurs != ''])"/>
        <xsl:if test="./metaInfo/Level = $pLevel and ($vActGroupCounter = $pGroupCounter or $pLevel = 0)">
            <xsl:element name="xs:element">
                <xsl:attribute name="name" select="@nodeTag"/>
                <xsl:attribute name="minOccurs" select="@minOccurs"/>
                <xsl:attribute name="maxOccurs" select="@segmentMaxOccurs"/>
                <xsl:attribute name="id" select="./metaInfo/ID"/>
            </xsl:element>
        </xsl:if>
    </xsl:template>
    <xsl:template match="node[@groupMaxOccurs != '']" mode="MessageStructure">
        <xsl:param name="pRootNode"/>
        <xsl:param name="pLevel"/>
        <xsl:param name="pGroupCounter"/>
        <xsl:variable name="vNextLevel" select="$pLevel + 1"/>
        <xsl:variable name="vActGroupCounter" select="count(following-sibling::node[@typeTag = $pRootNode and @groupMaxOccurs != ''])"/>
        <xsl:variable name="vNextGroupLevel" select="following-sibling::node[@typeTag = $pRootNode and @groupMaxOccurs != ''][1]/metaInfo/Level"/>
        <xsl:element name="xs:element">
            <xsl:attribute name="name" select="@nodeTag"/>
            <xsl:attribute name="minOccurs" select="@minOccurs"/>
            <xsl:attribute name="maxOccurs" select="@groupMaxOccurs"/>
            <xsl:attribute name="id" select="./metaInfo/ID"/>
            <xsl:element name="xs:element">
                <xsl:attribute name="name" select="@nodeTag"/>
                <xsl:attribute name="minOccurs" select="@minOccurs"/>
                <xsl:attribute name="maxOccurs" select="@segmentMaxOccurs"/>
                <xsl:attribute name="id" select="./metaInfo/ID"/>
            </xsl:element>
            <xsl:apply-templates select="following-sibling::node[@typeTag = $pRootNode and ((@groupMaxOccurs != '' and ./metaInfo/Level = $vNextLevel + 1 and ./metaInfo/Level = $vNextGroupLevel) or (@groupMaxOccurs = '' and ./metaInfo/Level = $vNextLevel))]" mode="MessageStructure">
                <xsl:with-param name="pRootNode" select="$pRootNode"/>
                <xsl:with-param name="pLevel" select="$vNextLevel"/>
                <xsl:with-param name="pGroupCounter" select="$vActGroupCounter"/>
            </xsl:apply-templates>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

非常感谢任何支持。非常感谢提前。

2 个答案:

答案 0 :(得分:0)

以下是使用递归函数的建议:

<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>

您必须使用更多级别测试自己,或者提供一些具有更深嵌套的输入样本,以便我们进行测试。

答案 1 :(得分:0)

让我建议一种创建嵌套层次结构的不同方法。为了演示,我将使用以下最小化输入:

<强> 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>

应用以下样式表:

<强> 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>

将返回:

<强>结果

<?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>

这可以递归地使用任何级别。