Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT1.0:递归展平/反规范化结构_Xslt_Recursion - Fatal编程技术网

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,'&#x0A;')" />
  <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('&#xA;', $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('&#xA;', $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,'&#x0A;')" />
      <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('&#xA;', $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