XSLT 使用特定级别条件从平面结构创建层次结构 [英] XSLT Create a hierarchical structure from a flat structure by using certain level criteria

查看:28
本文介绍了XSLT 使用特定级别条件从平面结构创建层次结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 group, if these nodes with same matching parameters are defined in a later group, which has the same level in the hierarchy.

Excel XML 输出如下所示:

The Excel XML output looks like following:

 <?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 将生成组元素.元素Level"定义了结构的层次结构(它应该是一个嵌套结构),元素ID"是一个有序的唯一标识符.

Each node should be an element, whereby @segmentMaxOccurs != 0 will generate leaf elementa and @groupMaxOccurs will generate group elements. The element "Level" defines the hierarchy of the structure (it should be a nested structure) and the element "ID" is an ordered unique identifier.

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

Based on this input, I would like to get the following XSD structure. In order to just focus on my issue, I stripped out all not relevant items such as "xs:sequence" or "xs:complexType":

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

GGG"组有两个附加组 AAA (id = 140) 和 WWW (id = 160),它们应该就在组 OOO 的下面.你有什么想法,如何只处理GGG的正确节点,直到组AAA(id = 90),它与元素组GGG"处于同一级别.我不知道,这些只属于元素组GGG"的节点将如何被消耗.

The group "GGG" has the two addtional groups AAA (id = 140) and WWW (id = 160), which should be just underneath the group OOO. Do you have any idea, how just the correct nodes of GGG will be processed until the group AAA (id = 90), which is at the same level like element group "GGG". I don't have idea, how these nodes will be consumed that just belong to element group "GGG".

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

This is the part of the XSLT, which is relevant for generating the hierarchical structure:

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

非常感谢任何支持.非常感谢.

Any support is really appreciated. Many thanks in advance.

推荐答案

这是使用递归函数的建议:

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.

这篇关于XSLT 使用特定级别条件从平面结构创建层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆