6

Ok, so here's a sample of the XML structure:

<config>
  <Ignored>
    <Ignore name="Test A">
       <Criteria>
          <value>actual value</value>
       </Criteria>
    </Ignore>
    <Ignore name="Test B">
       <Criteria>
          <value>actual value</value>
       </Criteria>
    </Ignore>
  </Ignored>
<config>

I would like to be able to do two things:

  1. Perform a get directly to the Test A element without having to loop all Ignore elements..like a selector on an attribute.
  2. If nothing else, I need a method of updating either of the Ignore elements and can't seem to figure it out

Do I have to delete the element and recreate it? I can't seem to figure out a way to perform a put which qualifies an element (where there a many with the same name at the same level) by an attribute (which would be unique at that level).

Something like:

pt.put("config.Ignored.Ignore.<xmlattr>.name='Test A'.Criteria.value",some_var)

Or anything else that can achieve the end goal. Thank you very much!

Full disclosure: I'm pretty new to C++ and may be missing something blatantly obvious.

CapersL
  • 174
  • 2
  • 7
  • Is there a good reason that you're using boost property tree for this? You may be better off using a real XML library instead. – Michael Anderson Dec 15 '11 at 03:34
  • Honestly? No can't say I have a good reason. I happened to have boost and figured I'd try to use what was there, and it's worked fine..until getting to this issue. If you were to recommend a real XML library, what would it be? – CapersL Dec 15 '11 at 03:38
  • I'd recommend tinyxml and libxml2 (depending on your other needs). – Michael Anderson Dec 16 '11 at 07:34

2 Answers2

6

Boost.property_tree xml parser (RapidXML) doesn't support this.
Consider using something like TinyXPath is you want such functionality out of the box.

Or use explicit loop to find Ignore node with required attribute. Then you can use

someIgnoreNode.put("Criteria.value", some_var);
Abyx
  • 12,345
  • 5
  • 44
  • 76
  • Thanks. That's what I was trying to do when I posted the question, I think I'm missing something. `BOOST_FOREACH(const ptree::value_type &v2, pt.get_child("config.Ignored")) { if(_stricmp( cText, v2.second.get(".name","").c_str() ) == 0 ) { BOOST_FOREACH(const ptree::value_type &v3, v2.second) { if(v3.first == "Criteria"){ v3.second.put("value", szValue); } } }` But I get this error: `cannot convert 'this' pointer from 'const boost::property_tree::basic_ptree' to 'boost::property_tree::basic_ptree &' ` Like I said, it's probably something stupid. – CapersL Dec 15 '11 at 13:52
  • @CapersL, you are trying to modify `const` object - remove `const` from both `v3` and `v2` types – Abyx Dec 15 '11 at 14:55
  • You see, I knew it would be something REALLY stupid! As I said, I'm just a C++ n00b who was using example snippets, not really understanding what they were doing. Thank you so much! – CapersL Dec 15 '11 at 15:10
0

you may use a method like:

auto & pt_child = pt.getchild("config.Ignored");
BOOST_FOREACH(ptree::value_type &v1, pt_child)
{
    if (v1.first == Ignore && v1.second.get<std::string>("<xmlattr>.name") == "Test A")
    {
        ptree & ptGrandChild = v1.second;
        ptGrandChild.put<std::string>("Criteria.value", some_var);
    }
}

boost::property_tree::xml_writer_settings<std::string> settings = 
boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
write_xml(xmlPath, pt, std::locale(), settings);

 
Y.Chan
  • 1
  • 1