2

別の投稿から次のテンプレートを入手しました。

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="pUncertainElName" select="'second'"/>
<xsl:param name="pParentPath" select="'outerElement/innerElement'" />
<xsl:param name="pOrderedNames" select="'|first|second|third|'"/>

<xsl:template match="node()|@*">
  <xsl:copy>
  <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="outerElement/innerElement">
  <xsl:variable name="vrtfFirstPass">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      <xsl:apply-templates select=
        "self::*[not(*[name() = $pUncertainElName])
                or
                *[name()=$pUncertainElName and @missing-cause]]"
        mode="missing"/>
      </xsl:copy>
  </xsl:variable>

  <xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
</xsl:template>

<xsl:template match="*[@missing-cause]"/>

<xsl:template match="*" mode="missing">
    <xsl:element name="{$pUncertainElName}">
        <CharacterString>INSERTED BY TEMPLATE</CharacterString>
    </xsl:element>
</xsl:template>

<xsl:template match="outerElement/innerElement" mode="pass2">
  <xsl:copy>
  <xsl:apply-templates>
    <xsl:sort data-type="number" select=
    "string-length(substring-before($pOrderedNames,
                                    concat('|', name(), '|')
                                    )
                  )"/>
  </xsl:apply-templates>
  </xsl:copy>
</xsl:template>
</xsl:stylesheet>

目的は、欠落している要素を追加することです。ソースドキュメントで欠落している特定の場所を追加します。ソースドキュメントは次のようになります

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<doc>
  <outerElement>
    <innerElement>
      <first>
        <textElement>Some Text</textElement>
      </first>
      <second missing-cause="bla" />
      <third>
        <textElement>Some Text</textElement>
      </third>
    </innerElement>
  </outerElement>
</doc>

同様の方法でこのような要素をたくさん追加する必要があるので、パラメーターを使用して、挿入する親パスと要素を指定します。

それで、ここに最初の質問があります:マッチでパラメータを使用するにはどうすればよいですか?match ="$parameter"またはバリアントが機能していないようです。

そして2番目のもの:このテンプレートで要素を追加することにはまだ問題があります。これは2番目のパスから来ていると思います。

私のドキュメントが上に投稿されたように見える場合は、出力をフラットにします

<doc>
  <outerElement>Some TextSome TextINSERTED BY TEMPLATE</outerElement>
</doc>

が正常に機能しない場合。2番目のパスの構築に何かが欠けている可能性がありますが、これを修正する方法がわかりません。

そして最後に..1つのドキュメントで20回など、さまざまなパラメータを使用してこのテンプレートを呼び出して変換しても大丈夫ですか、それとも別の方法を試す必要がありますか?

もう一度助けてくれてありがとう、そして申し訳ありませんが私はこれに不慣れです;)

4

1 に答える 1

1

XSLT1.0とXSLT2.0の両方で、XPath式を動的に評価することはできません。

したがって、何をしようとしても$pParentPath、望ましい結果は得られません。

回避策として、2つの異なるパラメーターを渡すことができます。pchildNameそしてpgrandchildName次のようなものを使用します。

*[name()=$pchildName]/*[name()=$pgrandchildName]

XSLT 1.0では、変数またはパラメーターの参照は一致パターンで禁止されています。XSLT2.0では問題ありません。

この特定のXMLドキュメントで機能するように修正された変換は次のとおりです。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pUncertainElName" select="'second'"/>
    <xsl:param name="pOrderedNames" select="'|first|second|third|'"/>

    <xsl:template match="node()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="innerElement">
      <xsl:variable name="vrtfFirstPass">
          <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
          <xsl:apply-templates select=
            "self::*[not(*[name() = $pUncertainElName])
                    or
                    *[name()=$pUncertainElName and @missing-cause]]"
            mode="missing"/>
          </xsl:copy>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
    </xsl:template>

    <xsl:template match="*[@missing-cause]"/>

    <xsl:template match="*" mode="missing">
        <xsl:element name="{$pUncertainElName}">
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
        </xsl:element>
    </xsl:template>

    <xsl:template match="innerElement" mode="pass2">
      <xsl:copy>
      <xsl:apply-templates>
        <xsl:sort data-type="number" select=
        "string-length(substring-before($pOrderedNames,
                                        concat('|', name(), '|')
                                        )
                      )"/>
      </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

この変換が提供されたXMLドキュメントに適用される場合:

<doc>
    <outerElement>
        <innerElement>
            <first>
                <textElement>Some Text</textElement>
            </first>
            <second missing-cause="bla" />
            <third>
                <textElement>Some Text</textElement>
            </third>
        </innerElement>
    </outerElement>
</doc>

必要な正しい結果が生成されます。

<doc>
   <outerElement>
      <innerElement>
         <first>
            <textElement>Some Text</textElement>
         </first>
         <second>
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
         </second>
         <third>
            <textElement>Some Text</textElement>
         </third>
      </innerElement>
   </outerElement>
</doc>

変換は、ドキュメント階層のさまざまな場所にあるさまざまな要素の子を処理するように変更できます

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pUncertainElName" select="'second'"/>
    <xsl:param name="pOrderedNames" select="'|first|second|third|'"/>

    <xsl:template match="node()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="/">
      <xsl:variable name="vrtfFirstPass">
        <xsl:apply-templates select="node()|@*"/>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
    </xsl:template>

    <xsl:template match="innerElement">
      <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
          <xsl:apply-templates select=
            "self::*[not(*[name() = $pUncertainElName])
                    or
                    *[name()=$pUncertainElName and @missing-cause]]"
            mode="missing"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[@missing-cause]"/>

    <xsl:template match="*" mode="missing">
        <xsl:element name="{$pUncertainElName}">
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
        </xsl:element>
    </xsl:template>

    <xsl:template match="node()|@*" mode="pass2">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*" mode="pass2"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="innerElement" mode="pass2">
      <xsl:copy>
       <xsl:apply-templates>
         <xsl:sort data-type="number" select=
        "string-length(substring-before($pOrderedNames,
                                        concat('|', name(), '|')
                                        )
                      )"/>
       </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

この変換が次のXMLドキュメントに適用される場合innerElement(親が異なり、深さが異なる2つの要素を含み、その子には特殊な処理が必要です)。

<doc>
    <outerElement>
        <innerElement>
            <first>
                <textElement>Some Text</textElement>
            </first>
            <second missing-cause="bla" />
            <third>
                <textElement>Some Text</textElement>
            </third>
        </innerElement>
        <outerElement2>
          <outerElement3>
            <innerElement>
                    <first>
                        <textElement>Some Text</textElement>
                    </first>
                    <third>
                        <textElement>Some Text</textElement>
                    </third>
            </innerElement>
          </outerElement3>
        </outerElement2>
    </outerElement>
</doc>

必要な正しい結果が生成されます:

<doc>
   <outerElement>
      <innerElement>
         <first>
            <textElement>Some Text</textElement>
         </first>
         <second>
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
         </second>
         <third>
            <textElement>Some Text</textElement>
         </third>
      </innerElement>
      <outerElement2>
         <outerElement3>
            <innerElement>
               <first>
                  <textElement>Some Text</textElement>
               </first>
               <second>
                  <CharacterString>INSERTED BY TEMPLATE</CharacterString>
               </second>
               <third>
                  <textElement>Some Text</textElement>
               </third>
            </innerElement>
         </outerElement3>
      </outerElement2>
   </outerElement>
</doc>

最後に、変換をさらに変更して、異なる名前の親の子を処理できるようにすることができます-say innerElementand someOtherInnerElement

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pUncertainElName" select="'second'"/>
    <xsl:param name="pOrderedNames" select="'|first|second|third|'"/>

    <xsl:template match="node()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="/">
      <xsl:variable name="vrtfFirstPass">
        <xsl:apply-templates select="node()|@*"/>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
    </xsl:template>

    <xsl:template match="innerElement | someOtherInnerElement">
      <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
          <xsl:apply-templates select=
            "self::*[not(*[name() = $pUncertainElName])
                    or
                    *[name()=$pUncertainElName and @missing-cause]]"
            mode="missing"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[@missing-cause]"/>

    <xsl:template match="*" mode="missing">
        <xsl:element name="{$pUncertainElName}">
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
        </xsl:element>
    </xsl:template>

    <xsl:template match="node()|@*" mode="pass2">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*" mode="pass2"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="innerElement | someOtherInnerElement" mode="pass2">
      <xsl:copy>
       <xsl:apply-templates>
         <xsl:sort data-type="number" select=
        "string-length(substring-before($pOrderedNames,
                                        concat('|', name(), '|')
                                        )
                      )"/>
       </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

この変換が次のXMLドキュメントに適用される場合、必要な方法で処理される子には、次の2つの名前(innerElementおよびsomeOtherInnerElement)で名前が付けられた親があります。

<doc>
    <outerElement>
        <innerElement>
            <first>
                <textElement>Some Text</textElement>
            </first>
            <second missing-cause="bla" />
            <third>
                <textElement>Some Text</textElement>
            </third>
        </innerElement>
        <outerElement2>
          <outerElement3>
            <someOtherInnerElement>
                    <first>
                        <textElement>Some Text</textElement>
                    </first>
                    <third>
                        <textElement>Some Text</textElement>
                    </third>
            </someOtherInnerElement>
          </outerElement3>
        </outerElement2>
    </outerElement>
</doc>

ここでも、必要な正しい結果が生成されます。

<doc>
   <outerElement>
      <innerElement>
         <first>
            <textElement>Some Text</textElement>
         </first>
         <second>
            <CharacterString>INSERTED BY TEMPLATE</CharacterString>
         </second>
         <third>
            <textElement>Some Text</textElement>
         </third>
      </innerElement>
      <outerElement2>
         <outerElement3>
            <someOtherInnerElement>
               <first>
                  <textElement>Some Text</textElement>
               </first>
               <second>
                  <CharacterString>INSERTED BY TEMPLATE</CharacterString>
               </second>
               <third>
                  <textElement>Some Text</textElement>
               </third>
            </someOtherInnerElement>
         </outerElement3>
      </outerElement2>
   </outerElement>
</doc>

説明

これは基本的に前の質問と同じロジックです。

  1. 2パス処理。

  2. IDルールをオーバーライドします。

  3. テンプレートとテンプレートの一致パターンの適切な使用。

  4. 名前の優先順位で要素を並べ替えます。

于 2012-06-26T16:12:07.923 に答える