0

在大多数情况下,我实现了一个例程 C++/Qt 来比较 QDomElement。

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. 如果 aQDomNode包含二进制数据,如何比较它们,当内部数据相同时返回 true ?

谢谢 !

4

3 回答 3

1

我想出了以下相等检查算法:

两个节点ab相等,如果a >= bb>=a

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

现在我们只需要介绍

比较算法

现在将使用本机QString比较功能

首先,在一般的方法中,我们不仅要比较QDomElements,还要比较QDomNodeDom 中的 every。

  • 如果a.nodeType < b.nodeType,那么a < b
  • 否则,如果a.nodeName < b.nodeName,则a < b
  • 否则,如果a.children.size() < b.children().size(),则a < b
  • 否则,如果a.children().size() ==0 && b.children().size() ==0,比较nodeValue()。请注意,这种方法适用于属性节点和文本节点。QDomElement 本身没有nodeValue. 如果是一些文本,写在元素内部,元素将有文本类型的子节点。这就是为什么element.nodeValue()调用总是返回空字符串。
  • 否则,使用lessThen比较函数对给定节点的所有子节点进行排序。
  • 然后,检查每个孩子的c属于ad属于b
    • 如果d > c,那么a > b
    • 如果c < d,那么a < b
    • 否则 ( c==d) 继续比较下一个cd
  • 如果 allc等于d,则a == 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);
}

请注意,该比较算法具有极高的复杂性。我花了大约 10 分钟来处理 2MB xml 文件(使用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

它与 Qt 方法一起使用,该方法NodeValue()转换为QStringa 的值,QDomNode而不管其类型如何。我的比较功能如下:

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 回答
0

请注意,这没有考虑属性。以下基于 octoback 的代码,但在应用于 Lol4t0 的排序版本时可能会更好(更快)。我没有彻底测试这个。

bool compareElements (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);

    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 = element1.nodeValue ();
        if (!value1.isEmpty ())
        {
            value2 = element2.nodeValue ();
            if (!value2.isEmpty ())
            {
                if (value1 != value2)
                    return false;
            }
        }

        // attributes
        QDomNamedNodeMap attributes1 = element1.attributes ();
        QDomNamedNodeMap attributes2 = element2.attributes ();
        if (attributes1.size () != attributes2.size ())
            return false;
        for (int i1 = 0; i1 < attributes1.size (); i1++)
        {
            QDomNode item1 = attributes1.item (i1);
            QString a1 = item1.nodeName ();
            if (!a1.isEmpty ())
            {
                bool found = false;
                for (int i2 = 0; i2 < attributes2.size (); i2++)
                {
                    QDomNode item2 = attributes2.item (i2);
                    QString a2 = item2.nodeName ();
                    if (a1 == a2)
                    {
                        if (item1.nodeValue () != item2.nodeValue ())
                            return false;
                        found = true;
                        break;
                    }
                }
                if (!found)
                    return false;
            }
        }
    }

    QDomElement c1, c2;
    for (int i = elts1.size () - 1; i > -1; i--)
    {
        c1 = elts1.at (i);
        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 (!compareElements (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;
}
于 2018-08-21T16:00:15.410 回答