2017-11-30 2 views
1

Ich habe folgende XML-Daten und ich möchte durch Boost Xml Parser analysieren.Boost und Xml Parsing

<?xml version="1.0" encoding="UTF-8"?> 
<applications> 
    <application> 
      <id>1</id> 
      <platform>linux-x64</platform> 
      <version>2.4</version> 
    </application> 
    <application> 
      <id>2</id> 
      <platform>windows</platform> 
      <version>2.5</version> 
    </application> 
    <application> 
      <id>3</id> 
      <platform>linux</platform> 
      <version>2.6</version> 
    </application> 
</applications> 

Ich habe unten Boost-Code geschrieben, aber ich lese nur das erste Kind von „Anwendungen“ und nicht in der Lage anderen beiden Childs zu lesen. Jedes Mal erhalten innere Schleifen die Daten des ersten Kindes.

boost::property_tree::ptree pt; 
boost::property_tree::read_xml(sModel, pt); // sModel is filename which contains above xml data 

BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("applications")) 
{ 
    std::string key = v.first.data();  
    std::string Id, platform, version; 

    if (key == std::string("application")) 
    { 
     BOOST_FOREACH(boost::property_tree::ptree::value_type &v_, pt.get_child("applications.application")) 
     { 
      std::string app_key = v_.first.data(); 
      std::string app_value = v_.second.data(); 

      if (app_key == std::string("id")) 
       pkgId = app_value; 
      else if (app_key == std::string("platform")) 
       platform = app_value; 
      else if (app_key == std::string("version")) 
       version = app_value; 
     } 
    } 
} 

Hier bekomme ich jedes mal die Plattform als "linux-x64". Kann jemand sagen, wie man alle Kinder durch dieses Boost-XML liest?

Vielen Dank im Voraus.

+1

ist es nicht wirklich ein Boost-XML-Parser. PropertyTree bietet eine rudimentäre Unterstützung für das Laden von XML über einen modifizierten RapidXML-Parser, unterstützt jedoch den Großteil von XML nicht und ist, wie Sie sehen, beim Zugriff auf die Daten ein wenig unsicher. –

+0

@SebastianRedl danke für die Verbreitung des Evangeliums. Ich bin froh, dass es allgemein bekannt wird. Ich würde nicht sagen, Datenzugriff ist zweifelhaft; in der Tat ist es ziemlich nett für den Zugriff auf Eigentum. (Siehe zB [Vermeidung von Loop-Raserei] (https://stackoverflow.com/questions/47013164/boostproperty-tree-parsing-of-complex-xml-strucure/47019176#47019176) und [Übersetzer] (https: // stackoverflow. com/a/43769414/85371)). – sehe

Antwort

2

get_child (und alle anderen pfadbasierten Zugriffsfunktionen) ist nicht sehr gut im Umgang mit mehreren identischen Schlüsseln. Es wählt das erste Kind mit dem gegebenen Schlüssel aus und gibt das zurück, ignoriert alle anderen.

Aber Sie brauchen nicht get_child, weil Sie bereits den Knoten halten Sie in der Hand halten.

pt.get_child("applications") gibt Ihnen eine ptree. Iterating darüber, gibt Ihnen eine ptree::value_type, die eine ist.

Die erste seltsame Sache, dann ist diese Zeile:

std::string key = v.first.data(); 

Die data() Funktion sind Sie hier Aufruf ist std::string::data, nicht ptree::data. Sie könnten nur schreiben

std::string key = v.first; 

Die nächste Merkwürdige ist der Vergleich:

if (key == std::string("application")) 

Sie müssen nicht explizit ein std::string hier bauen zu. Tatsächlich ist dies eine Pessimierung, da es einen Zeichenfolgenpuffer zuordnen und die Zeichenfolge dort kopieren muss, wenn std::string Vergleichsoperatoren für C-artige Zeichenfolgen hat.

Dann Iterator über pt.get_child("applications.application"), aber Sie müssen diese Suche nicht tun - v.second ist bereits die Struktur, die Sie wollen.

Darüber hinaus müssen Sie nicht über das Kind iterieren, können Sie seine Lookup-Funktionen verwenden, um zu bekommen, was Sie brauchen.

std::string pkgId = v.second.get("id", ""); 

So zusammenzufassen, ist dies der Code, den ich schreiben würde:

boost::property_tree::ptree pt; 
boost::property_tree::read_xml(sModel, pt); 

BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("applications")) 
{ 
    // You can even omit this check if you can rely on all children 
    // being application nodes. 
    if (v.first == "application") 
    { 
     std::string pkgId = v.second.get("id", ""); 
     std::string platform = v.second.get("platform", ""); 
     std::string version = v.second.get("version", ""); 
    } 
} 
+0

Danke Sebastian für deine Detailantwort. Ich habe den addierten Code ausprobiert, aber jedesmal druckt er "id: 1".Plattform: linux-x64 und Version: 2.4. Irgendeine Idee ? – Neel

+0

Wird es mindestens dreimal gedruckt? Ich habe im Moment keinen Computer mit Boost, so dass ich meinen Code nicht debuggen kann. –

+0

Ja. Es druckt dreimal. – Neel