1

子ノードの値に基づいて2つのノードを比較できるようにしたいと思います。演算子を使用してノードの同等性をテストする=には、それぞれのノードの文字列値を比較するだけです。子ノードの値に基づいて比較したいと思います。

もう少し具体的に言うと、一致する属性を持つ要素の値も同じであるため、<a><b>(以下)を等しくしたいと思います。@id<c>@type@id

<a>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-three" id="9088"/>
</a>
<b>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
</b>

しかし、これらは異なります。

<a>
    <c type="type-one" id="5675"/>
</a>
<b>
    <c type="type-one" id="2342"/>
</b>

私が見始めることができる唯一の解決策は、for-eachステートメントとの骨の折れる比較を含みますが、可能であれば避けたいと思います。

可能であれば、XSLT1.0を使い続けたいと思います。xsltprocを使用しています。

4

2 に答える 2

0

まず、「等しい」という関係はその名前を持つことはできません

「等しい」とは、その関係が同値関係であることを意味します。定義により、等価関係~は次のようになります。

  1. 再帰: x ~ x.

  2. 対称: もしそうx ~ yならy ~ x

  3. 他動詞: ifx ~ yy ~ zthen x ~ z.

提案された「等しい」関係が推移的でないことを示す例を次に示します。

xは:

<a>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-three" id="9088"/>
</a>

yは:

<b>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-four" id="1234"/>
</b>

zは:

<b>
    <c type="type-three" id="3333"/>
    <c type="type-four" id="1234"/>
</b>

x ~ yこれで、とがわかりましたy ~ z。ただし、明らかにこれは当てはまりません。x ~ z

これは、関係を「一致」と呼んでおり、「等しい」ではなくリラックスしたものだと言っています。

上記の調整による問題の解決策は次のとおりです。

XPath 1.0 (XSLT 1.0 変換内で使用される) には範囲変数がないため、これは単一の XPath 式では表現できないことに注意してください

<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="/*">
     <xsl:call-template name="matches">
       <xsl:with-param name="pElem1" select="a"/>
       <xsl:with-param name="pElem2" select="b"/>
     </xsl:call-template>
 </xsl:template>

 <xsl:template name="matches">
   <xsl:param name="pElem1" select="/.."/>
   <xsl:param name="pElem2" select="/.."/>

   <xsl:variable name="vMisMatch">
       <xsl:for-each select="$pElem1/c[@type = $pElem2/c/@type]">
        <xsl:if test=
           "$pElem2/c[@type = current()/@type and not(@id = current()/@id)]">1</xsl:if>
       </xsl:for-each>
   </xsl:variable>

   <xsl:copy-of select="not(string($vMisMatch))"/>
 </xsl:template>
</xsl:stylesheet>

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

<t>
    <a>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
        <c type="type-three" id="9088"/>
    </a>
    <b>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
    </b>
</t>

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

true

この XML ドキュメントに同じ変換を適用すると、次のようになります。

<t>
    <a>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
        <c type="type-three" id="9088"/>
    </a>
    <b>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="9876"/>
    </b>
</t>

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

false
于 2013-01-20T17:12:48.660 に答える
0

これが私が思いついたものです。次のようなおもちゃのデータセットがあるとします。

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <a>
        <item key="x" value="123"/>
        <item key="y" value="456"/>
        <item key="z" value="789"/>
    </a>
    <b>
        <item key="x" value="123"/>
        <item key="z" value="789"/>
    </b>
</root>

このスタイルシートは、質問で定義されているように、平等をテストする方法を示しています。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:set="http://exslt.org/sets"  xmlns:exsl="http://exslt.org/common" 
 extension-element-prefixes="set exsl">
<xsl:output method="text" version="1.0" encoding="UTF-8"/> 

<xsl:template match="/">
    <xsl:variable name="values-are-equal">
        <xsl:call-template name="equal">
            <xsl:with-param name="A" select="/root/a"/>
            <xsl:with-param name="B" select="/root/b"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="$values-are-equal = 1">Equal</xsl:when>
        <xsl:otherwise>Inequal</xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="equal">
    <xsl:param name="A" />
    <xsl:param name="B" />
    <xsl:variable name="common-keys" select="$A/item/@key[ count(set:distinct(  . | $B/item/@key )) = count( set:distinct( $B/item/@key ) ) ]"/>
    <xsl:variable name="differences">
        <xsl:for-each select="$common-keys">
            <xsl:if test="$A/item[@key = current()]/@value != $B/item[@key = current()]/@value">
                <different/>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="count( exsl:node-set($differences)/* ) > 0">0</xsl:when>
        <xsl:otherwise>1</xsl:otherwise>
    </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

これは、xsltproc およびその他のプロセッサで利用可能ないくつかの拡張機能を使用します。

于 2013-01-21T03:07:36.397 に答える