2017-02-20 33 views
1

Мой XML выглядит следующим образом:Создание сложного xml с использованием xslt, когда иерархия доступна как атрибут?

Ключевой атрибут имеет иерархию элементов, мне нужно найти, что и создать 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> 

, как это может быть achived с помощью кода XSLT?

ответ

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: Ниже моя попытка с XSLT-2.0 код, который использует функцию, чтобы принять строки (@key) значения, а также создать иерархию tokenizing и группирования строк ввода.

<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