Я реализовал подпрограмму 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 с помощью этого метода (т. Е. Сравнивать текст ())?
В частности, должен ли я быть осторожным с особыми случаями, как QDomCDATASection
элементы и двоичный формат?
если QDomNode
содержит двоичные данные, как их объединять, возвращая истину, когда внутри находятся одни и те же данные?
Спасибо !
Я пришел к следующему алгоритму проверки равенства:
a
а также b
равны, если a >= b
а также b>=a
bool compare( QDomElement element1, QDomElement element2 )
{
return ! lessThen(element1, element2) && !lessThen(element2, element1);
}
Теперь нам осталось только ввести
Сейчас буду использовать родной QString
сравнить функцию
Прежде всего, в общем подходе мы должны сравнивать не только QDomElement
с, но каждый QDomNode
в дом.
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()
,nodeValue
, Если это некоторый текст, написанный внутри элемента, элемент будет иметь дочерний узел текстового типа. Поэтому element.nodeValue()
call всегда возвращает пустую строкуlessThen
сравнить функцию.c
принадлежит a
а также d
принадлежит b
:
d > c
, затем a > b
c < d
, затем a < b
c==d
) продолжить сравнение для следующего c
а также d
,c
равно 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 минут для обработки 2 МБ XML-файла (с XML-должен-быть-равно к себе тестовое задание)
Формат:
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
Работает с методом Qt NodeValue()
который превращается в QString
значение 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 ;
}
Обратите внимание, что это не учитывает атрибуты.
Следующее основано на коде 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;
}