2

xpath ステートメントのリストを指定して、xml ドキュメントを実行し、同じドキュメントを出力するスタイルシートを作成したいと思いますが、各 xpath ステートメントで識別されるノードの前にコメントが挿入されます。例を作ってみましょう。xpath ステートメントを保持する xml インスタンスから始めます。

<paths>
  <xpath location="/root/a" annotate="1"/>
  <xpath location="/root/a/b" annotate="2"/>
</paths>

入力が与えられた場合:

<root>
  <a>
    <b>B</b>
  </a>
  <c>C</c>
</root>

以下を生成する必要があります。

<root>
  <!-- 1 -->
  <a>
    <!-- 2 -->
    <b>B</b>
  </a>
  <c>C</c>
</root>

私の最初の考えは、パラメーターを取り、その関数をfile-list呼び出してdocumentxpath ノードのリストを取得する ID スタイルシートを用意することです。次に、入力の各ノードをそのリストに対してチェックし、コメントノードが見つかったら挿入しますが、xpaths のリストが大きくなるため、非常に非効率的であると予想されます (または、そうでないかもしれません。教えてください。私は使用していますサクソン 9)。

だから私の質問: このようなことを行う効率的な方法はありますか?

4

3 に答える 3

2

2 番目の変換を作成するという kjhughes の提案が、元のアイデアよりも効率的かどうかはわかりません。pathsXML が大きくなると、その 2 番目の変換が巨大になる可能性があることは確かです。

これが私がそれを行う方法です...

XML 入力

<root>
    <a>
        <b>B</b>
    </a>
    <c>C</c>
</root>

「パス」XML (paths.xml)

<paths>
    <xpath location="/root/a" annotate="1"/>
    <xpath location="/root/a/b" annotate="2"/>
</paths>

XSLT 2.0

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

    <xsl:param name="paths" select="document('paths.xml')"/>

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

    <xsl:template match="*" priority="1">
        <xsl:variable name="path">
            <xsl:for-each select="ancestor-or-self::*">
                <xsl:value-of select="concat('/',local-name())"/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:if test="$paths/*/xpath[@location=$path]">
            <xsl:comment select="$paths/*/xpath[@location=$path]/@annotate"/>
        </xsl:if>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML 出力

<root>
    <!--1-->
    <a>
        <!--2-->
        <b>B</b>
    </a>
    <c>C</c>
</root>
于 2013-10-05T04:30:07.483 に答える
2

概要:

ファイルを入力として受け取り、新しい XSLT 変換を出力として生成するメタXSLT 変換を記述します。pathsこの新しい XSLT は、root入力 XML から注釈付きコピー出力 XML に変換されます。

ノート:

  1. XSLT 1.0、2.0、または 3.0 で動作します。
  2. XSLT ベースのインタープリターとのマッチングを再実装するのではなく、ネイティブ XSLT に効果的にコンパイルされるため、生成された変換を大量の入力に対して実行する必要がある場合や、繰り返し実行する必要がある場合は特に、非常に効率的です。
  3. 要素の祖先をコードで手動で再構築する必要があるアプローチよりも堅牢です。template/@matchパスを属性にマップするため 、 @matching の高度な機能を効率的に利用できます。例として、属性値テストを含めました。
  4. 特に中間メタ XSLT ファイルが機能しない場合は、@DanielHaley と @MartinHonnen によるエレガントな XSLT 2.0 および 3.0 ソリューションを必ず検討してください。XSLT 3.0 の XPath 評価機能を活用することで、@MartinHonnen の回答は、template/@matchここよりもさらに堅牢なマッチングを提供できるようです。

XPath と注釈を指定するこの入力 XML は、次のとおりです。

<paths>
  <xpath location="/root/a" annotate="1"/>
  <xpath location="/root/a/b" annotate="2"/>
  <xpath location="/root/c[@x='123']" annotate="3"/>
</paths>

このメタ XSLT 変換への入力時:

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

  <xsl:template match="/paths">
    <xsl:element name="xsl:stylesheet">
      <xsl:attribute name="version">1.0</xsl:attribute>
      <xsl:element name="xsl:output">
        <xsl:attribute name="method">xml</xsl:attribute>
        <xsl:attribute name="indent">yes</xsl:attribute>
      </xsl:element>
      <xsl:call-template name="gen_identity_template"/>
      <xsl:apply-templates select="xpath"/>
    </xsl:element>
  </xsl:template>

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

  <xsl:template match="xpath">
    <xsl:element name="xsl:template">
      <xsl:attribute name="match">
        <xsl:value-of select="@location"/>
      </xsl:attribute>
      <xsl:element name="xsl:comment">
        <xsl:value-of select="@annotate"/>
      </xsl:element>
      <xsl:element name="xsl:text">
        <xsl:text disable-output-escaping="yes">&amp;#xa;</xsl:text>
      </xsl:element>
      <xsl:element name="xsl:copy">
        <xsl:element name="xsl:apply-templates">
          <xsl:attribute name="select">node()|@*</xsl:attribute>
        </xsl:element>
      </xsl:element>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

次の XSLT 変換が生成されます。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="/root/a">
      <xsl:comment>1</xsl:comment>
      <xsl:text>&#xa;</xsl:text>
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="/root/a/b">
      <xsl:comment>2</xsl:comment>
      <xsl:text>&#xa;</xsl:text>
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="/root/c[@x='123']">
      <xsl:comment>3</xsl:comment>
      <xsl:text>&#xa;</xsl:text>
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

この入力 XML ファイルを指定すると、次のようになります。

<root>
  <a>
    <b>B</b>
  </a>
  <c x="123">C</c>
</root>

目的の出力 XML ファイルが生成されます。

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <!--1-->
   <a>
    <!--2-->
      <b>B</b>
  </a>
  <!--3-->
   <c x="123">C</c>
</root>
于 2013-10-05T03:57:57.683 に答える