1

私の入力 XML は次のもので構成されています。

<root>
    <entry>
        <type>U</type>
        <value>111</value>
    </entry>
    <entry>
        <type>X</type>
        <value>222</value>
    </entry>
    <entry>
        <type>E</type>
        <value>333</value>
    </entry>
    <entry>
        <type>Q</type>
        <value>444</value>
    </entry>
</root>

出力 i が必要です。 <ROOT> <ENTRY> <SLNO>1</SLNO> <VALUE>111</VALUE> </ENTRY> <ENTRY> <VALUE>222</VALUE> </ENTRY> <ENTRY> <VALUE>333</VALUE> </ENTRY> <ENTRY> <SLNO>2</SLNO> <VALUE>444</VALUE> </ENTRY> </ROOT>

すべてのレコードを解析する必要がありますが、タイプが X と E ではないレコードのシリアル番号を入力する必要があります。

同じように for-each を作成し、「position()」を使用して、タイプ E および X の条件付きのシリアル番号を表示しました。位置()´.

グローバル変数を作成して if ブロック内でインクリメントすることを考えましたが、XSLT 1.0 では変数値をインクリメントできません。

どうすればこれを達成できますか?

私のサンプル XSL コードは次のとおりです。

<xsl:for-each select="/ROOT/ENTRY">
    <xsl:if test="(TYPE != 'X') and (TYPE != 'E')">             
        <xsl:text><![CDATA[<SLNO>]]></xsl:text>
        <xsl:number value="position()"/>
        <xsl:text><![CDATA[</SLNO>]]></xsl:text>
    </xsl:if>
    <!-- Printing remaining values -->
</xsl:for-each>

助けてください。

4

2 に答える 2

0

受け入れられた答えは良いものですが、実装されたアルゴリズムは O(N^2) (二次) 時間の複雑さを持ち、大きな入力で非常に遅く実行されます。

線形時間複雑度 O(N) を使用した変換は次のとおりです。

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

 <xsl:template match="node()|@*">
  <xsl:param name="pCount" select="0"/>
  <xsl:copy>
   <xsl:apply-templates select="node()[1]|@*">
     <xsl:with-param name="pCount" select="$pCount"/>
   </xsl:apply-templates>
  </xsl:copy>
  <xsl:apply-templates select="following-sibling::node()[1]">
     <xsl:with-param name="pCount" select="$pCount"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="entry[not(contains('EX', type))]">
  <xsl:param name="pCount" select="0"/>

  <xsl:copy>
   <slno><xsl:value-of select="$pCount+1"/></slno>
   <xsl:apply-templates select="node()[1]|@*">
     <xsl:with-param name="pCount" select="$pCount+1"/>
   </xsl:apply-templates>
  </xsl:copy>
  <xsl:apply-templates select="following-sibling::node()[1]">
     <xsl:with-param name="pCount" select="$pCount+1"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="type">
   <xsl:param name="pCount" select="0"/>
   <xsl:apply-templates select="following-sibling::node()[1]">
     <xsl:with-param name="pCount" select="$pCount+1"/>
   </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

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

<root>
    <entry>
        <type>U</type>
        <value>111</value>
    </entry>
    <entry>
        <type>X</type>
        <value>222</value>
    </entry>
    <entry>
        <type>E</type>
        <value>333</value>
    </entry>
    <entry>
        <type>Q</type>
        <value>444</value>
    </entry>
</root>

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

<root>
   <entry>
      <slno>1</slno>
      <value>111</value>
   </entry>
   <entry>
      <value>222</value>
   </entry>
   <entry>
      <value>333</value>
   </entry>
   <entry>
      <slno>2</slno>
      <value>444</value>
   </entry>
</root>

説明:

  1. 「きめ細かいアイデンティティ ルール」の使用とオーバーライド。テンプレートは一度に 1 つのノード (ドキュメント順) にのみ適用されるため、その名前が付けられています。

  2. $pCountこれまでに到達した最大の現在の「シリアル番号」を含むparameter を含めて渡すように、「きめ細かな ID ルール」が変更されました。

  3. entryすべての要素が兄弟であるため、これは現在のシリアル番号を返す必要なく機能します。

  4. 他の回答で行われているように、すべてのノードで先行するすべての兄弟がカウントされないため、時間の複雑さは線形です。

于 2012-06-08T03:37:42.503 に答える
0

position() を使用する代わりに、XML 内の先行する型要素の数を数えることができます

<xsl:value-of select="count(preceding::type[. != 'X' and . != 'E']) + 1" />

さらに、 entry要素ではなく、 type要素を直接照合することで現在の XSLT を簡素化し、それを新しいslno要素に置き換えるだけです。

<xsl:template match="type[. != 'X' and . != 'E']">

たとえば、次の XSLT を試してください。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="type[. != 'X' and . != 'E']">
      <slno><xsl:value-of select="count(preceding::type[. != 'X' and . != 'E']) + 1" /></slno>
   </xsl:template>

   <xsl:template match="type" />

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

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

<root>
   <entry>
      <slno>1</slno>
      <value>111</value>
   </entry>
   <entry>
      <value>222</value>
   </entry>
   <entry>
      <value>333</value>
   </entry>
   <entry>
      <slno>2</slno>
      <value>444</value>
   </entry>
</root>

ここではすべて小文字の要素名を使用していることに注意してください。あなたの質問から、それらを大文字に変換したいかどうかわかりませんでした。

于 2012-06-07T14:51:53.577 に答える