我的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代码实现这一目标?
答案 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) > 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
)。