XSLT1.0:递归展平/反规范化结构
我正试图递归地扁平化/规范化下面的结构,但运气不好XSLT1.0:递归展平/反规范化结构,xslt,recursion,Xslt,Recursion,我正试图递归地扁平化/规范化下面的结构,但运气不好 <models> <model name="AAA" root="true"> <items> <item name="a"/> <item name="b"/> </items> <submodels> <submodel ref="BBB"/> <s
<models>
<model name="AAA" root="true">
<items>
<item name="a"/>
<item name="b"/>
</items>
<submodels>
<submodel ref="BBB"/>
<submodel ref="CCC" />
</submodels>
</model>
<model name="BBB">
<items>
<item name="c"/>
<item name="d"/>
</items>
<submodels>
<submodel ref="CCC" />
</submodels>
</model>
<model name="CCC">
<item name="e" />
</model>
</models>
我尝试过以递归的方式使用。但主要问题是多个模型可以引用单个模型。例如,AAA->CCC和BBB->CCC。首先,我怀疑您想对标记为根的模型进行数学运算
<xsl:apply-templates select="model[@root='true']" />
我不确定你的转换规则是什么。这有点猜测,但下面的XSLT1.0样式表确实将您提供的输入转换为预期的输出
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="models/model[@root='true']">
<xsl:with-param name="base" select="''" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="model|item">
<xsl:param name="base" />
<xsl:variable name="new-base" select="concat($base,'/',@name)" />
<xsl:value-of select="concat($new-base,'
')" />
<xsl:apply-templates select="items/item | item | submodels/submodel/@ref">
<xsl:with-param name="base" select="$new-base" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@ref">
<xsl:param name="base" />
<xsl:apply-templates select="../../../../model[@name=current()]">
<xsl:with-param name="base" select="$base" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
此简短而简单的转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kmodelByName" match="model" use="@name"/>
<xsl:key name="ksubmodelByRef" match="submodel" use="@ref"/>
<xsl:template match="/*">
<xsl:apply-templates select="model[not(key('ksubmodelByRef', @name))]"/>
</xsl:template>
<xsl:template match="model|item">
<xsl:param name="pPath"/>
<xsl:value-of select="concat('
', $pPath, '/', @name)"/>
<xsl:apply-templates select="item|*/item|*/submodel">
<xsl:with-param name="pPath" select="concat($pPath, '/', @name)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="submodel">
<xsl:param name="pPath"/>
<xsl:apply-templates select="key('kmodelByName', @ref)">
<xsl:with-param name="pPath" select="$pPath"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
<models>
<model name="AAA" root="true">
<items>
<item name="a"/>
<item name="b"/>
</items>
<submodels>
<submodel ref="BBB"/>
<submodel ref="CCC" />
</submodels>
</model>
<model name="BBB">
<items>
<item name="c"/>
<item name="d"/>
</items>
<submodels>
<submodel ref="CCC" />
</submodels>
</model>
<model name="CCC">
<item name="e"/>
</model>
</models>
/AAA
/AAA/a
/AAA/b
/AAA/BBB
/AAA/BBB/c
/AAA/BBB/d
/AAA/BBB/CCC
/AAA/BBB/CCC/e
/AAA/CCC
/AAA/CCC/e
说明:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kmodelByName" match="model" use="@name"/>
<xsl:key name="ksubmodelByRef" match="submodel" use="@ref"/>
<xsl:template match="/*">
<xsl:apply-templates select="model[not(key('ksubmodelByRef', @name))]"/>
</xsl:template>
<xsl:template match="model|item">
<xsl:param name="pPath"/>
<xsl:value-of select="concat('
', $pPath, '/', @name)"/>
<xsl:apply-templates select="item|*/item|*/submodel">
<xsl:with-param name="pPath" select="concat($pPath, '/', @name)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="submodel">
<xsl:param name="pPath"/>
<xsl:apply-templates select="key('kmodelByName', @ref)">
<xsl:with-param name="pPath" select="$pPath"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
<models>
<model name="AAA" root="true">
<items>
<item name="a"/>
<item name="b"/>
</items>
<submodels>
<submodel ref="BBB"/>
<submodel ref="CCC" />
</submodels>
</model>
<model name="BBB">
<items>
<item name="c"/>
<item name="d"/>
</items>
<submodels>
<submodel ref="CCC" />
</submodels>
</model>
<model name="CCC">
<item name="e"/>
</model>
</models>
/AAA
/AAA/a
/AAA/b
/AAA/BBB
/AAA/BBB/c
/AAA/BBB/d
/AAA/BBB/CCC
/AAA/BBB/CCC/e
/AAA/CCC
/AAA/CCC/e
可能有一种更简单的方法可以做到这一点,但我能够通过以下xslt获得您想要的输出:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="exsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
<xsl:variable name="root" select="/models/model[@root = 'true']/@name"/>
<xsl:template match="models">
<xsl:for-each select="model">
<xsl:variable name="savedNode" select="."/>
<xsl:variable name="precedingValue">
<xsl:call-template name="preceding">
<xsl:with-param name="modelName" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="not(exsl:node-set($precedingValue)/preceding)">
<xsl:call-template name="model">
<xsl:with-param name="node" select="$savedNode"/>
</xsl:call-template>
</xsl:if>
<xsl:for-each select="exsl:node-set($precedingValue)/preceding">
<xsl:sort select="position()" data-type="number" order="descending"/>
<xsl:variable name="precedingTmp" select="normalize-space(.)"/>
<xsl:variable name="normalizedPreceding" select="translate($precedingTmp, ' ', '')"/>
<xsl:call-template name="model">
<xsl:with-param name="node" select="$savedNode"/>
<xsl:with-param name="preceding" select="$normalizedPreceding"/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="model">
<xsl:param name="node"/>
<xsl:param name="preceding"/>
\<xsl:value-of select="$preceding"/><xsl:value-of select="$node/@name"/>
<xsl:for-each select="$node/items/item">
\<xsl:value-of select="$preceding"/><xsl:value-of select="$node/@name"/>\<xsl:value-of select="@name"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="preceding">
<xsl:param name="modelName"/>
<xsl:for-each select="preceding::model">
<xsl:for-each select="submodels/submodel">
<xsl:choose>
<xsl:when test="contains(@ref, $modelName)">
<preceding>
<xsl:call-template name="preceding">
<xsl:with-param name="modelName" select="$modelName"></xsl:with-param>
</xsl:call-template>
<xsl:value-of select="../../@name"/>\
</preceding>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="items">
<xsl:for-each select="item">
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
希望有帮助。AAA、BBB和CCC型号的输出不一致。为什么BBB是AAA的孩子?是因为子模型节点吗?为什么没有“/BBB”输出?根属性是否有任何意义?
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="models/model[@root='true']">
<xsl:with-param name="base" select="''" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="model|item">
<xsl:param name="base" />
<xsl:variable name="new-base" select="concat($base,'/',@name)" />
<xsl:value-of select="concat($new-base,'
')" />
<xsl:apply-templates select="items/item | item | submodels/submodel/@ref">
<xsl:with-param name="base" select="$new-base" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@ref">
<xsl:param name="base" />
<xsl:apply-templates select="../../../../model[@name=current()]">
<xsl:with-param name="base" select="$base" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kmodelByName" match="model" use="@name"/>
<xsl:key name="ksubmodelByRef" match="submodel" use="@ref"/>
<xsl:template match="/*">
<xsl:apply-templates select="model[not(key('ksubmodelByRef', @name))]"/>
</xsl:template>
<xsl:template match="model|item">
<xsl:param name="pPath"/>
<xsl:value-of select="concat('
', $pPath, '/', @name)"/>
<xsl:apply-templates select="item|*/item|*/submodel">
<xsl:with-param name="pPath" select="concat($pPath, '/', @name)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="submodel">
<xsl:param name="pPath"/>
<xsl:apply-templates select="key('kmodelByName', @ref)">
<xsl:with-param name="pPath" select="$pPath"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
<models>
<model name="AAA" root="true">
<items>
<item name="a"/>
<item name="b"/>
</items>
<submodels>
<submodel ref="BBB"/>
<submodel ref="CCC" />
</submodels>
</model>
<model name="BBB">
<items>
<item name="c"/>
<item name="d"/>
</items>
<submodels>
<submodel ref="CCC" />
</submodels>
</model>
<model name="CCC">
<item name="e"/>
</model>
</models>
/AAA
/AAA/a
/AAA/b
/AAA/BBB
/AAA/BBB/c
/AAA/BBB/d
/AAA/BBB/CCC
/AAA/BBB/CCC/e
/AAA/CCC
/AAA/CCC/e
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="exsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
<xsl:variable name="root" select="/models/model[@root = 'true']/@name"/>
<xsl:template match="models">
<xsl:for-each select="model">
<xsl:variable name="savedNode" select="."/>
<xsl:variable name="precedingValue">
<xsl:call-template name="preceding">
<xsl:with-param name="modelName" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="not(exsl:node-set($precedingValue)/preceding)">
<xsl:call-template name="model">
<xsl:with-param name="node" select="$savedNode"/>
</xsl:call-template>
</xsl:if>
<xsl:for-each select="exsl:node-set($precedingValue)/preceding">
<xsl:sort select="position()" data-type="number" order="descending"/>
<xsl:variable name="precedingTmp" select="normalize-space(.)"/>
<xsl:variable name="normalizedPreceding" select="translate($precedingTmp, ' ', '')"/>
<xsl:call-template name="model">
<xsl:with-param name="node" select="$savedNode"/>
<xsl:with-param name="preceding" select="$normalizedPreceding"/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="model">
<xsl:param name="node"/>
<xsl:param name="preceding"/>
\<xsl:value-of select="$preceding"/><xsl:value-of select="$node/@name"/>
<xsl:for-each select="$node/items/item">
\<xsl:value-of select="$preceding"/><xsl:value-of select="$node/@name"/>\<xsl:value-of select="@name"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="preceding">
<xsl:param name="modelName"/>
<xsl:for-each select="preceding::model">
<xsl:for-each select="submodels/submodel">
<xsl:choose>
<xsl:when test="contains(@ref, $modelName)">
<preceding>
<xsl:call-template name="preceding">
<xsl:with-param name="modelName" select="$modelName"></xsl:with-param>
</xsl:call-template>
<xsl:value-of select="../../@name"/>\
</preceding>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="items">
<xsl:for-each select="item">
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<models>
<model name="AAA" root="true">
<items>
<item name="a"/>
<item name="b"/>
</items>
<submodels>
<submodel ref="BBB"/>
<submodel ref="CCC" />
</submodels>
</model>
<model name="BBB">
<items>
<item name="c"/>
<item name="d"/>
</items>
<submodels>
<submodel ref="CCC" />
</submodels>
</model>
<model name="CCC">
<items>
<item name="e"/>
</items>
</model>
</models>
\AAA
\AAA\a
\AAA\b
\AAA\BBB
\AAA\BBB\c
\AAA\BBB\d
\AAA\BBB\CCC
\AAA\BBB\CCC\e
\AAA\CCC
\AAA\CCC\e