0

最も一般的なケースで QDomElement を比較するルーチン C++/Qt を実装しました。

bool XMLtools::compare( QDomElement & element1, QDomElement & element2 )
{
    QString tag1 = element1.tagName() ;   
    QString tag2 = element2.tagName() ;
    if ( tag1 != tag2 )
        return false ;
    QList<QDomElement> elts1 = getChildElements(element1);
    QList<QDomElement> elts2 = getChildElements(element2);
    QDomElement c1, c2, tmp ;

    QString name1, name_tmp, text1, text2 ;
    if(elts1.size() != elts2.size())
        return false ;
    if(elts1.size() == 0)
    {
        text1 = c1.text() ;
        text2 = c2.text() ;

        if( text1 != text2 )
            return false ;
    }
    for ( int i = elts1.size() - 1 ; i > -1 ; i-- ) 
    {
        c1 = elts1.at(i);
        QString name1 = c1.tagName();

        for( int j = elts2.size() - 1 ; j > -1 ; j-- )
        {
            tmp = elts2.at(j) ;
            name_tmp = tmp.tagName() ;

            if( name_tmp == name1 )
            {
                c2 = tmp ;
                break ;
            }

            if( j == 0 )
                return false ; 
        }
        if ( ! compare(c1, c2) )
            return false ;      
    }
    return true ;
}

1. このメソッドを使用してすべての QDomNode 要素を比較できますか (つまり、text() の比較)?

  1. QDomCDATASection特に、要素やバイナリ形式などの特殊なケースには注意が必要ですか?

  2. にバイナリデータが含まれている場合、QDomNodeそれらを比較して、同じデータが内部にあるときに true を返す方法は?

ありがとう !

4

3 に答える 3

1

次の等価性チェックアルゴリズムを思いつきました:

2 つのノードabが等しい場合、a >= bb>=a

bool compare( QDomElement  element1, QDomElement  element2 )
{
    return ! lessThen(element1, element2) && !lessThen(element2, element1);
}

あとは紹介するだけです

比較アルゴリズム

ネイティブのQString比較機能を使用するようになりました

まず、一般的なアプローチでは、QDomElements だけでなくQDomNodeDom 内のすべてを比較する必要があります。

  • ならa.nodeType < b.nodeTypea < b
  • そうでなければ、もしa.nodeName < b.nodeNamea < b
  • そうでなければ、もしa.children.size() < b.children().size()a < b
  • それ以外の場合a.children().size() ==0 && b.children().size() ==0は、比較しnodeValue()ます。このアプローチは、属性ノードとテキスト ノードの両方で機能することに注意してください。QDomElement 自体にはありませんnodeValue。要素内に記述されたテキストの場合、要素にはテキスト型の子ノードがあります。そのため、element.nodeValue()呼び出しは常に null 文字列を返します。
  • lessThenそれ以外の場合は、 compare 関数を使用して、指定されたノードのすべての子を並べ替えます。
  • 次に、すべての子がcに属し、ad属していることを確認しbます。
    • ならd > ca > b
    • ならc < da < b
    • それ以外の場合 ( ) 次のとc==dの比較を続行します。cd
  • すべてcが に等しい場合da == b、そして明らかa < bに間違っています。

このアルゴリズムを実装するコード:

QList<QDomNode> getChildElements(const QDomNode& e)
{
    QList<QDomNode> r;
    for (int k = 0; k < e.childNodes().size(); ++k) {
        QDomNode n = e.childNodes().at(k);
        r << n;
    }
    return r;
}


bool lessThen( QDomNode  element1, QDomNode  element2 )
{
    if (element1.nodeType() != element2.nodeType()) {
        return element1.nodeType() < element1.nodeType();
    }
    QString tag1 = element1.nodeName() ;
    QString tag2 = element2.nodeName() ;

    //qDebug() << tag1 <<tag2;
    if ( tag1 != tag2 )
        return tag1 < tag2;

    QList<QDomNode> elts1 = getChildElements(element1);
    QList<QDomNode> elts2 = getChildElements(element2);


    QString value1, value2 ;

    if(elts1.size() != elts2.size())
        return elts2.size() < elts1.size() ;

    if(elts1.size() == 0)
    {
        value1 = element1.nodeValue();
        value2 = element2.nodeValue();

        //qDebug() <<value1 << value2 << (value1 < value2);
        return value1 < value2;

    }

    qSort(elts1.begin(), elts1.end(), lessThen);
    qSort(elts2.begin(), elts2.end(), lessThen);
    //qDebug() << "comparing sorted lists";
    for(int  k = 0; k < elts1.size(); ++k) {
        if (!lessThen(elts1[k], elts2[k])) {
            if (lessThen(elts2[k], elts1[k])) {
                //qDebug() << "false!";
                return false;
            }
        }else {
            //qDebug() << "true!";
            return true;
        }
    }
    return false;
}

bool compare( QDomElement  element1, QDomElement  element2 )
{
    return ! lessThen(element1, element2) && !lessThen(element2, element1);
}

比較アルゴリズムは非常に複雑であることに注意してください。2MBのxmlファイルを処理するのに約10分かかりました(xml-should-be-equal-to-itselfテストあり)

可能なテスト

フォーマット:

description (desired result)
<xml1>
<xml2>
result

テスト:

different order (true) 
"<r>
 <a>x</a>
 <a>y</a>
</r>
" 
"<r>
 <a>y</a>
 <a>x</a>
</r>
" 
true 
different text (false) 
"<a>x</a>
" 
"<a>y</a>
" 
false 
different text with structure (false) 
"<a>x<b/>ddcd</a>
" 
"<a>y<b/>dede</a>
" 
false 
same structure different names (false) 
"<r>
 <a/>
 <a/>
 <b/>
</r>
" 
"<r>
 <a/>
 <b/>
 <b/>
</r>
" 
false 
same text with structure (true) 
"<a>y<b/>x</a>
" 
"<a>x<b/>y</a>
" 
true 
attributes vs text (false) 
"<a b="c"/>
" 
"<a>
 <b>c</b>
</a>
" 
false 
于 2012-11-22T19:23:06.620 に答える
0

タイプに関係なくa の値にNodeValue()変換するQt メソッドで動作します。私の比較機能は次のとおりです。QStringQDomNode

bool XMLtools::compare( QDomElement & element1, QDomElement & element2 )
{
    QString tag1 = element1.tagName() ;  //attribute("Name") ;
    QString tag2 = element2.tagName() ;

    if ( tag1 != tag2 )
        return false ;

    QList<QDomElement> elts1 = getChildElements(element1);
    QList<QDomElement> elts2 = getChildElements(element2);
    QDomElement c1, c2 ;

    bool these_nodes_are_equal = true ;
    bool one_comparing_tag = false ;

    QString name1, name2, value1, value2 ;

    if(elts1.size() != elts2.size())
        return false ;

    if(elts1.size() == 0)
    {
        value1 = c1.nodeValue() ;
        value2 = c2.nodeValue() ;

        if( value1 != value2 )
            return false ;
    }

    for ( int i = elts1.size() - 1 ; i > -1 ; i-- ) 
    {
        c1 = elts1.at(i);
        QString name1 = c1.tagName();

        for( int j = elts2.size() - 1 ; j > -1 ; j-- )
        {
            c2 = elts2.at(j) ;
            name2 = c2.tagName() ;

            if( name2 == name1 )
            {
                one_comparing_tag = true ;
                if ( ! compare(c1, c2) ) // c1 and c2 are potential identical nodes
                    these_nodes_are_equal = false ;
                else
                {
                    these_nodes_are_equal = true ;
                    break ;
                }
            }
        }

        if( !one_comparing_tag ) // if no node in elts2 is corresponding to node in elts1
            return false ; 

        if ( !these_nodes_are_equal ) // if no node in elts2 could compare to this node in elts1
            return false;   
    }

    return true ;
}
于 2012-11-22T16:44:27.337 に答える