3

私は XSLT を初めて使用し、かなり複雑な問題を抱えています...入力ファイルは次のようになります

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

この問題は、「2 番目の」要素で発生します。入力ファイルでは、次の 3 つの形式のいずれかを使用できます。

MISSING

<second>
  <textElement>Some Text</textElement>
</second>

<second missingCause="" />

出力ファイルでは、2 番目の形式のように挿入する必要があります。textElement がテンプレートによって挿入されたことを示す前に欠落していた場合、ここで重要なのは、xsd スキーマに対して検証したいので、2 番目の位置にある必要があることです...

これが私の現在のXSLです:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <!-- remove Elements with attribute deleteme -->
  <xsl:template match="outerElement/second[@missingCause='*']" />

  <!-- look if second is there. If not insert -->
  <xsl:template match="outerElement">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      <xsl:if test="not(second)">
        <second>
        </second>
      </xsl:if>
    </xsl:copy>    
  </xsl:template>

  <!-- Insert Element second -->
  <xsl:template match="outerElement/second">
    <xsl:apply-templates select="node()|@*"/>
    <xsl:copy>
      <xsl:if test="not(textElement)">
        <textElement>Inserted by Template</textElement>
      </xsl:if>
    </xsl:copy>    
  </xsl:template>

</xsl:stylesheet> 

「second」が欠落している場合、出力ファイルは要素「」を取得するだけですが、それは空であり、最後の変換は適用されません。ドキュメントにあるときに警告が表示される間、他のすべては問題ないように見えます...

誰かが要素をあるべき場所に移動して、スキーマに対して検証し、3つのケースすべてで機能させるのを手伝ってもらえますか?

このように挿入/削除する類似の要素がいくつかあるため、私のやり方はあまり良くないようで、混乱してしまうと思います。

読んでくれてありがとう ;)

4

2 に答える 2

4

outerElementこれは、の任意の数の異なる名前の子とそれらの間の任意の優先順序に対して機能する一般的なソリューションです

<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="outerElement">
  <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}">
        <textElement>Some Text</textElement>
    </xsl:element>
 </xsl:template>

 <xsl:template match="outerElement" 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>
        <first>
            <textElement>Some Text</textElement>
        </first>
        <second missing-cause="">
            <textElement>Some Text</textElement>
        </second>
        <third>
            <textElement>Some Text</textElement>
        </third>
    </outerElement>
</doc>

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

<doc>
   <outerElement>
      <first>
         <textElement>Some Text</textElement>
      </first>
      <second>
         <textElement>Some Text</textElement>
      </second>
      <third>
         <textElement>Some Text</textElement>
      </third>
   </outerElement>
</doc>

このXMLドキュメントに適用される場合

<doc>
    <outerElement>
        <first>
            <textElement>Some Text</textElement>
        </first>
        <third>
            <textElement>Some Text</textElement>
        </third>
    </outerElement>
</doc>

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

<doc>
   <outerElement>
      <first>
         <textElement>Some Text</textElement>
      </first>
      <second>
         <textElement>Some Text</textElement>
      </second>
      <third>
         <textElement>Some Text</textElement>
      </third>
   </outerElement>
</doc>

最後に、同じ変換がこのXMLドキュメントに適用される場合:

<doc>
    <outerElement>
        <first>
            <textElement>Some Text</textElement>
        </first>
        <second>
            <textElement>Some Text</textElement>
        </second>
        <third>
            <textElement>Some Text</textElement>
        </third>
    </outerElement>
</doc>

ここでも、同じように、正しい結果が生成されます。

<doc>
   <outerElement>
      <first>
         <textElement>Some Text</textElement>
      </first>
      <second>
         <textElement>Some Text</textElement>
      </second>
      <third>
         <textElement>Some Text</textElement>
      </third>
   </outerElement>
</doc>

異なる名前の子outerElement(3つだけではない)は無制限に存在する可能性があり、それらの順序は事前にわからない場合があります。

このXMLドキュメントを考えると

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

そしてこの順序:4番目、2番目、3番目、1番目

交換するだけです:

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

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

そして今、新しい望みの結果が生成されます:

<doc>
   <outerElement>
      <fourth>
         <textElement>Some Text</textElement>
      </fourth>
      <second>
         <textElement>Some Text</textElement>
      </second>
      <third>
         <textElement>Some Text</textElement>
      </third>
      <first>
         <textElement>Some Text</textElement>
      </first>
   </outerElement>
</doc>

説明

  1. これは2パス変換です。

  2. 存在する場合と存在しない場合がある要素の名前は、external/globalパラメーターで指定されます$pUncertainElName。この説明の便宜上、この要素を。と呼びsecondます。

  3. 最初のパスでは、属性を持つものouterElementを除いて、のすべての子が「そのまま」コピーされます。要素が存在しないか、属性を持っている場合は、正確に必要な要素の新しい子を出力します。secondmissing-causesecondmissing-causeouterElementsecond

  4. 2番目のパスでは、最初のパスで生成された子を、名前がouterElement付けられた別の外部/グローバルパラメーターで指定された優先度に従って並べ替えます$pOrderedNames(この文字列で別の名前が残っている名前の方が優先度が高くなります)

于 2012-06-26T03:16:46.857 に答える
3

テンプレートの仕組みを誤解していると思います。達成する必要があることについては、必要なテンプレートは 1 つだけ (および ID テンプレート) のようです。試してフィードバック:

<xsl:template match="outerElement[not(second) or second[@missingCause='']]">
    <xsl:apply-templates select="@*|first"/>
    <second>
        <textElement>Inserted by Template</textElement>
    </second>
    <xsl:apply-templates select="third"/>
</xsl:template>
于 2012-06-25T17:29:38.593 に答える