0

この質問は、質問hereの拡張です。ここで提供された @Martin Honnen の回答は、ほぼ正確に私が望むことを行いますが、deep-equalが呼び出されたときに、以前のテンプレートで削除したかった要素/属性が既に削除されていると誤って予想していました (したがって、シーケンスには存在しません)。に渡されdeep-equalます)。

に渡されるシーケンスから要素/属性を削除するにはどうすればよいですか? または、特定の要素/属性を無視するようにdeep-equal指示するにはどうすればよいですか?deep-equal

XSL:

<!--
    When a file is transformed using this stylesheet the output will be
    formatted as follows:

    1.)  Elements named "info" will be removed
    2.)  Attributes named "file_line_nr" or "file_name" will be removed
    3.)  Comments will be removed
    4.)  Processing instructions will be removed
    5.)  XML declaration will be removed
    6.)  Extra whitespace will be removed
    7.)  Empty attributes will be removed
    8.)  Elements which have no attributes, child elements, or text will be removed
    9.)  Duplicate sibling elements will be removed
    10.) All elements will be sorted by name recursively
    11.) All attributes will be sorted by name
-->
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- Set output options -->
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <!-- Match any attribute -->
    <xsl:template match="@*">
        <xsl:copy/>
    </xsl:template>

    <!-- Match any element -->
    <xsl:template match="*">
        <xsl:copy>
          <xsl:apply-templates select="@*">
            <xsl:sort select="local-name()"/>
           </xsl:apply-templates>
           <xsl:for-each-group select="node() except (processing-instruction(), comment())" group-adjacent="boolean(self::*)">
             <xsl:choose>
               <xsl:when test="current-grouping-key()">
                 <xsl:apply-templates select="current-group()">
                   <xsl:sort select="local-name()"/>
                 </xsl:apply-templates>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:apply-templates select="current-group()"/>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <!-- Elements/attributes to ignore -->
    <xsl:template match="@*[normalize-space()='']|info|@file_line_nr|@file_name|*[not(@*|node())]"/>

    <!-- Ignore element nodes which are deep-equal to a preceding sibling element -->
    <xsl:template match="*[some $ps in preceding-sibling::* satisfies deep-equal(., $ps)]"/>

</xsl:stylesheet>

XML 入力:

<root>
    <!-- foo #1 -->
    <foo a="a" file_line_nr="1"/>

    <!-- bar #1 -->
    <bar>
    some text
        <info a="a"/>
    </bar>

    <!-- foo #2 -->
    <foo a="a" file_line_nr="2"/><!-- This should be removed because it is identical to the foo #1 except for the "file_line_nr" attribute which should be removed/ignored -->

    <!-- baz #1 -->
    <baz file_name="some_file.h">
        <bam a="a"/>
    </baz>

    <!-- bar #2 -->
    <bar><!-- This should be removed because it is identical to the bar #1 except for the "info" child element which should be removed/ignored -->
        some text
        <info b="b"/>
    </bar>

    <!-- baz #2 -->
    <baz file_name="some_other_file.h"><!-- This should be removed because it is identical to the baz #1 except for the "file_name" attribute which should be removed/ignored -->
        <bam a="a"/>
    </baz>
</root>

望ましい出力:

<root>
    <foo a="a"/>
    <bar>
    some text
    </bar>
    <baz>
        <bam a="a"/>
    </baz>
</root>
4

1 に答える 1

2

テンプレートはすべて、出力したノードではなく、元の XML ツリーのノードと一致します。処理を 2 つのフェーズに分割する必要があります。最初に、不要な要素や属性などを変数にすべて削除し、次にその変数に対してディープ イコール フィルターを実行します。このようなもの:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- Set output options -->
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
      <!-- first pass with default-mode templates -->
      <xsl:variable name="pass1">
        <xsl:apply-templates />
      </xsl:variable>
      <!-- second pass with dedup templates -->
      <xsl:apply-templates select="$pass1" mode="dedup" />
    </xsl:template>

    <!-- pre-processing templates -->

    <!-- Match any attribute -->
    <xsl:template match="@*">
        <xsl:copy/>
    </xsl:template>

    <!-- Match any element -->
    <xsl:template match="*">
        <xsl:copy>
          <xsl:apply-templates select="@*">
            <xsl:sort select="local-name()"/>
           </xsl:apply-templates>
           <xsl:for-each-group select="node() except (processing-instruction(), comment())" group-adjacent="boolean(self::*)">
             <xsl:choose>
               <xsl:when test="current-grouping-key()">
                 <xsl:apply-templates select="current-group()">
                   <xsl:sort select="local-name()"/>
                 </xsl:apply-templates>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:apply-templates select="current-group()"/>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <!-- Elements/attributes to ignore -->
    <xsl:template match="@*[normalize-space()='']|info|@file_line_nr|@file_name|*[not(@*|node())]"/>


    <!-- de-duplication templates -->

    <!-- Ignore element nodes which are deep-equal to a preceding sibling element -->
    <xsl:template mode="dedup" match="*[some $ps in preceding-sibling::* satisfies deep-equal(., $ps)]"/>

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

</xsl:stylesheet>
于 2013-09-16T14:26:54.437 に答える