2017-02-20 48 views
1

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

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

<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代码achived?

回答

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

+0

是的,那很棒 – divya

1

XSLT的2.0: 下面是我的尝试与使用函数接受字符串(@key)值,以及令牌化和分组输入字符串创建层次结构XSLT的2.0代码。

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

是的工作感谢你 – divya