Сравнение XML QDomElement сделано вообще — C ++ / Qt

Я реализовал подпрограмму 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 с помощью этого метода (т. Е. Сравнивать текст ())?

  1. В частности, должен ли я быть осторожным с особыми случаями, как QDomCDATASection элементы и двоичный формат?

  2. если QDomNode содержит двоичные данные, как их объединять, возвращая истину, когда внутри находятся одни и те же данные?

Спасибо !

0

Решение

Я пришел к следующему алгоритму проверки равенства:

Два узла 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(),
    Обратите внимание, что этот подход будет работать как для атрибута, так и для текстовых узлов. Сам QDomElement не имеет 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
1

Другие решения

Работает с методом 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 ;
}
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;
}
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector