I have two XML files and I want to compare a subsection of it if it is equal. The XML files can be very different but I give an example. I have following XML files:
<EXECUTION_SET>
<RESULT query_id="7" >
<OP>
<PROJ>
<COLUMN col_name="City.ID" col_type="3" col_length="11" />
<OP>
<JOIN>
<OP>
<TABLE name="City" alias="City" access_type="5" total_record_length="67">
<COLUMN col_name="ID" col_type="3" col_length="11" raw_length="4" />
<COLUMN col_name="Name" col_type="254" col_length="35" raw_length="35" />
<COLUMN col_name="CountryCode" col_type="254" col_length="3" raw_length="3" />
<COLUMN col_name="District" col_type="254" col_length="20" raw_length="20" />
<COLUMN col_name="Population" col_type="3" col_length="11" raw_length="4" />
</TABLE>
</OP>
<OP>
<SEL>
<COND>
<COND>
<VALUE><VARIABLE>Country.Population</VARIABLE></VALUE>
</COND>
<BOP><![CDATA[>]]></BOP>
<COND>
<VALUE><CONSTANT>80000000</CONSTANT></VALUE>
</COND>
</COND>
<OP>
<OP>
<TABLE name="Country" alias="Country" access_type="5" total_record_length="261">
<COLUMN col_name="Code" col_type="254" col_length="3" raw_length="3" />
<COLUMN col_name="Name" col_type="254" col_length="52" raw_length="52" />
<COLUMN col_name="Continent" col_type="254" col_length="13" raw_length="1" />
<COLUMN col_name="Region" col_type="254" col_length="26" raw_length="26" />
<COLUMN col_name="SurfaceArea" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="IndepYear" col_type="2" col_length="6" raw_length="2" />
<COLUMN col_name="Population" col_type="3" col_length="11" raw_length="4" />
<COLUMN col_name="LifeExpectancy" col_type="4" col_length="3" raw_length="4" />
<COLUMN col_name="GNP" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="GNPOld" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="LocalName" col_type="254" col_length="45" raw_length="45" />
<COLUMN col_name="GovernmentForm" col_type="254" col_length="45" raw_length="45" />
<COLUMN col_name="HeadOfState" col_type="254" col_length="60" raw_length="60" />
<COLUMN col_name="Capital" col_type="3" col_length="11" raw_length="4" />
<COLUMN col_name="Code2" col_type="254" col_length="2" raw_length="2" />
</TABLE>
</OP>
</OP>
</SEL>
</OP>
</JOIN>
</OP>
</PROJ>
</OP>
</RESULT>
</EXECUTION_SET>
And the second XML file:
<EXECUTION_SET>
<RESULT query_id="13" >
<OP>
<PROJ>
<COLUMN col_name="Country.Code" col_type="254" col_length="3" />
<OP>
<SEL>
<COND>
<COND>
<VALUE><VARIABLE>Country.Population</VARIABLE></VALUE>
</COND>
<BOP><![CDATA[>]]></BOP>
<COND>
<VALUE><CONSTANT>80000000</CONSTANT></VALUE>
</COND>
</COND>
<OP>
<OP>
<TABLE name="Country" alias="Country" access_type="5" total_record_length="261">
<COLUMN col_name="Code" col_type="254" col_length="3" raw_length="3" />
<COLUMN col_name="Name" col_type="254" col_length="52" raw_length="52" />
<COLUMN col_name="Continent" col_type="254" col_length="13" raw_length="1" />
<COLUMN col_name="Region" col_type="254" col_length="26" raw_length="26" />
<COLUMN col_name="SurfaceArea" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="IndepYear" col_type="2" col_length="6" raw_length="2" />
<COLUMN col_name="Population" col_type="3" col_length="11" raw_length="4" />
<COLUMN col_name="LifeExpectancy" col_type="4" col_length="3" raw_length="4" />
<COLUMN col_name="GNP" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="GNPOld" col_type="4" col_length="10" raw_length="4" />
<COLUMN col_name="LocalName" col_type="254" col_length="45" raw_length="45" />
<COLUMN col_name="GovernmentForm" col_type="254" col_length="45" raw_length="45" />
<COLUMN col_name="HeadOfState" col_type="254" col_length="60" raw_length="60" />
<COLUMN col_name="Capital" col_type="3" col_length="11" raw_length="4" />
<COLUMN col_name="Code2" col_type="254" col_length="2" raw_length="2" />
</TABLE>
</OP>
</OP>
</SEL>
</OP>
</PROJ>
</OP>
</RESULT>
</EXECUTION_SET>
With this two XML files, I want to compare the subsection under the tag if this subsection is equal. For that I do for both xpath queries following: doc.select_nodes(std::string("//TABLE[@name='Country']/ancestor::SEL/COND").c_str());
and write it in the variables pugi::xpath_node_set partialTree1
and partialTree2
.
So I get the subsections of both xml files. Now I want to compare both subsections. It should be a good efficient way.
I have a solution but I don't like it because it needs to much time and space. At the moment I use the traverse
function to go throw the subsections and write all in a string for both subsections. Then I compare it. But there must be a better way for that.
Would be nice if someone have some ideas.
As a result of your query, you have a set of nodes from different documents. Each node has a certain amount of descendants, and to compare two nodes you have to compare all of their descendants - if you miss one you don't know whether the trees are equal.
This suggests that the approach of comparing the string dump of the nodes is optimal complexity-wise in terms of time. It is not optimal in terms of space - an optimal algorithm in terms of space goes through both trees in sync and compares values directly. Something like this should work:
template <typename It, typename Pred>
bool rangeEquals(It lb, It le, It rb, It re, Pred pred)
{
It li = lb, ri = rb;
for (; li != le && ri != re; ++li, ++ri)
if (!pred(*li, *ri))
return false;
return li == le && ri == re;
}
bool attrEquals(pugi::xml_attribute la, pugi::xml_attribute ra)
{
return
strcmp(la.name(), ra.name()) == 0 &&
strcmp(la.value(), ra.value()) == 0;
}
bool nodeEquals(pugi::xml_node ln, pugi::xml_node rn)
{
return
ln.type() == rn.type() &&
strcmp(ln.name(), rn.name()) == 0 &&
strcmp(ln.value(), rn.value()) == 0 &&
rangeEquals(ln.attributes_begin(), ln.attributes_end(), rn.attributes_begin(), rn.attributes_end(), attrEquals) &&
rangeEquals(ln.begin(), ln.end(), rn.begin(), rn.end(), nodeEquals);
}