3

以下の構造を再帰的に平坦化/正規化しようとしていますが、うまくいきません。

<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

再帰的に使ってみました。しかし、主な問題は、複数のモデルが単一のモデルを参照できることです。例えば。AAA -> CCC および BBB -> CCC。

4

4 に答える 4

1

この短くて簡単な変換:

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

提供された XML ドキュメントに適用した場合:

<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

説明:

  1. キーを適切に使用すると、変換が短くなり、表現が容易になり、効率的になります。

  2. テンプレートの適切な使用。

  3. パラメータの適切な使用 - テンプレートへの受け渡し。

于 2012-09-21T14:59:41.233 に答える
0

まず、ルートとしてマークされているモデルを計算したいと思います

<xsl:apply-templates select="model[@root='true']" />

次に、モデル要素に一致するテンプレートがありますが、親モデルへの現在の「パス」を含むパラメーターを受け取るテンプレートがあります

<xsl:template match="model">
   <xsl:param name="path" />

あなたはそのようにフルパスを出力することができます

<xsl:variable name="newpath" select="concat($path, '/', @name)" />
<xsl:value-of select="concat($newpath, '&#13;')" />

次に、アイテムを出力できますが、新しいパスをパラメーターとして渡します

<xsl:apply-templates select="items/item|item">
   <xsl:with-param name="path" select="$newpath" />
</xsl:apply-templates>

サブモデルを一致させるために、理想的にはキーを使用できます

<xsl:key name="models" match="model" use="@name" />

次に、そのようにサブモデルを一致させることができます

<xsl:apply-templates select="key('models', submodels/submodel/@ref)">
   <xsl:with-param name="path" select="$newpath" />
</xsl:apply-templates>

これは、同じモデルテンプレートと再帰的に一致します。

これが完全なXSLTです

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" indent="yes"/>
   <xsl:key name="models" match="model" use="@name" />

   <xsl:template match="/models">
      <xsl:apply-templates select="model[@root='true']" />
   </xsl:template>

   <xsl:template match="model">
      <xsl:param name="path" />

      <xsl:variable name="newpath" select="concat($path, '/', @name)" />
      <xsl:value-of select="concat($newpath, '&#13;')" />

      <xsl:apply-templates select="items/item|item">
         <xsl:with-param name="path" select="$newpath" />
      </xsl:apply-templates>

      <xsl:apply-templates select="key('models', submodels/submodel/@ref)">
         <xsl:with-param name="path" select="$newpath" />
      </xsl:apply-templates>

   </xsl:template>

   <xsl:template match="item">
      <xsl:param name="path" />
      <xsl:value-of select="concat($path, '/', @name, '&#13;')" />
   </xsl:template>
</xsl:stylesheet>

サンプルXMLに適用すると、次のように出力されます。

/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
于 2012-09-21T14:44:30.143 に答える
0

あなたの変換のルールが何であるかわかりません。これは推測にすぎませんが、次の XSLT 1.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>
于 2012-09-21T14:51:21.897 に答える
0

これを行うにはおそらくもっと簡単な方法がありますが、次の 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>

入力

<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

お役に立てば幸いです。

于 2012-09-21T18:44:28.360 に答える