当层次结构可用作属性时,使用xslt创建复杂的xml?

时间:2017-02-20 06:41:50

标签: xml xslt xslt-2.0

我的xml如下:

key属性包含元素的层次结构,我需要找到并创建 一个xml,基于从moduleName开始的。

<data moduleName='mainModule'>
<entry key='mainElem1'/>
<entry key='mainElem1/subElem1' />
<entry key='mainElem1/subElem1/@languageCode'/>
<entry key='mainElem1/subElem2'/>
<entry key='mainElem1/subElem3'/>
<entry key='mainElem1/subElem4'/>
<entry key='mainElem1/subElem4/TypeCode'/>
<entry key='mainElem1/subElem4/ContainmentCode'/>
<entry key='mainElem1/subElem4/List'/>
<entry key='mainElem1/subElem4/List/strVP'/>
<entry key='mainElem1/subElem4/List/List/strVP/@name'/>
<entry key='mainElem1/List'/>
<entry key='mainElem1/List/strVP'/>
<entry key='mainElem1/List/strVP/@name'/>
<entry key='mainElem2'/>
<entry key='List' />
<entry key='List/strVP'/>
<entry key='List/strVP/@name'/>
</data>

我需要以下输出:

<mainModule>
    <mainElem1>
        <subElem1 languageCode="dummyData">dummyData</subElem1>
        <subElem2>dummyData</subElem2>
        <subElem3>dummyData</subElem3>
        <subElem4>
            <TypeCode>dummyData</TypeCode>
            <ContainmentCode>dummyData</ContainmentCode>
            <List>
                <strVP name="dummyData">dummyData</strVP>
            </List>
        </subElem4>
        <List>
                <strVP name="dummyData">dummyData</strVP>
        </List>
    </mainElem1>
    <mainElem2>dummyData</mainElem2>
    <List>
        <strVP name="dummyData">dummyData</strVP>
    </List>
</mainModule>

如何使用xslt代码实现这一目标?

2 个答案:

答案 0 :(得分:1)

<强> XSLT-2.0 : 下面是我尝试使用XSLT-2.0代码,该代码使用函数接受字符串(@key)值,并通过对输入字符串进行标记和分组来创建层次结构。

<xsl:stylesheet
    version="2.0"
    xmlns:fn="http://myFunction.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
    <!-- Function to create elements hierarchy -->
    <xsl:function name="fn:createNodes" as="item()*">
        <!-- parameter to accept the strings to create the hierarchy -->
        <xsl:param name="items" as="xs:string*"/>
        <!-- the path separator -->
        <xsl:param name="separator" as="xs:string"/>

        <!-- group the elements by their first token (tokenized by "/") -->
        <xsl:for-each-group select="$items" group-by="tokenize(., $separator)[1]">
            <xsl:choose>
                <!-- when it is an attribute -->
                <xsl:when test="starts-with(current-grouping-key(), '@')">
                    <xsl:attribute name="{substring-after(current-grouping-key(),'@')}" select="'dummyData'"/>
                </xsl:when>
                <!-- otherwise, create an element -->
                <xsl:otherwise>
                    <xsl:element name="{current-grouping-key()}">
                        <!-- get the next group of non-empty tokens -->
                        <xsl:variable name="nextBatch" select="for $var in current-group() return substring-after($var, concat(current-grouping-key(),'/'))[.!='']"/>
                        <xsl:choose>
                            <!-- if there are more elements/attributes to be created -->
                            <xsl:when test="count($nextBatch)">
                                <!-- call the createNodes functions with $nextBatch -->
                                <xsl:sequence select="fn:createNodes($nextBatch, $separator)"/>
                            </xsl:when>
                            <!-- otherwise, add dummyData as the text node -->
                            <xsl:otherwise>dummyData</xsl:otherwise>
                        </xsl:choose>
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>

    </xsl:function>

    <xsl:template match="/data">
        <xsl:element name="{@moduleName}">
            <!-- call createNodes with entry/@key to create the hierarchy -->
            <xsl:sequence select="fn:createNodes((entry/@key), '/')"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

整个事情归结为递归调用outputToken模板。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

  <xsl:template name="outputToken">
    <xsl:param name="currElem"/>
    <xsl:param name="startTxt" select="''"/>
    <xsl:param name="level" select="1"/>
    <xsl:variable name="subElems" select=
      "$currElem/entry[starts-with(@key,$startTxt)][count(tokenize(@key,'/'))=$level]"/>
    <xsl:if test="count($subElems) &gt; 0">
      <xsl:for-each select="$subElems">
        <xsl:variable name="keyTokens" select="tokenize(@key,'/')"/>
        <xsl:variable name="currTok" select="$keyTokens[$level]"/>
        <!-- Current token - element name -->
        <xsl:if test="not(starts-with($currTok, '@'))">
          <!-- Create an alement -->
          <xsl:element name="{$currTok}">
            <xsl:variable name="newStart">
              <xsl:if test="$startTxt">
                <xsl:value-of select="concat($startTxt, '/', $currTok)"/>
              </xsl:if>  
              <xsl:if test="not($startTxt)">
                <xsl:value-of select="$currTok"/>
              </xsl:if>
            </xsl:variable>
            <xsl:call-template name="outputToken">
              <xsl:with-param name="currElem" select="$currElem"/>  
              <xsl:with-param name="startTxt" select="$newStart"/>
              <xsl:with-param name="level" select="$level + 1"/>
            </xsl:call-template>
          </xsl:element>
        </xsl:if>
        <!-- Current token - '@' + attribute name -->
        <xsl:if test="starts-with($currTok, '@')">
          <xsl:attribute name="{substring($currTok, 2)}">
            <xsl:text>dummyData</xsl:text>
          </xsl:attribute>
          <xsl:text>dummyData</xsl:text>
        </xsl:if>
      </xsl:for-each>
    </xsl:if>
    <xsl:if test="count($subElems) = 0">
      <xsl:text>dummyData</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="data">
    <xsl:element name="mainModule">
      <xsl:call-template name="outputToken">
        <xsl:with-param name="currElem" select="."/>  
      </xsl:call-template>
    </xsl:element>
  </xsl:template>

</xsl:transform>

关于您的意见的一句话:为了获得您的预期结果,请更改: <entry key='mainElem1/subElem4/List/List/strVP/@name'/><entry key='mainElem1/subElem4/List/strVP/@name'/>(删除重复的List)。