1

私は次のXMLファイルを持っています:

<?xml version="1.0" encoding="utf-8"?>
<gexf>
  <graph>
    <nodes>
      <node id="0" label="0" start="0" end="25"/>
      <node id="1" label="1" start="1"/>
      <node id="2" label="2" start="2"/>
      ...
    </nodes>
    <edges>
      <edge id="0" source="0" target="1" start="7" end="19"/>
      <edge id="1" source="0" target="2" start="8" end="20"/>
      ...
    </edges>
  </graph>
</gexf>

andを使用してエッジからstartandend属性を削除したいと思います。source="0"target="1"

私がこれをやろうとした方法は、次のコードにあります。XMLファイルに名前が付けられていると仮定して、ptree_test.gexfそれを読み込み、ツリー内の正しいエッジを見つけてから、を使用eraseして属性を削除しようとします。

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>

using boost::property_tree::ptree;

int main(int argc, char *argv[]) {

  ptree pt;

  read_xml("ptree_test.gexf", pt);

  // Now find edge (0, 1) and delete the start and end attributes
  ptree edge;
  int id1, id2;
  id1 = 0;
  id2 = 1;

  for(auto &e : pt.get_child("gexf.graph.edges")) {
    int s, t;
    s = e.second.get<int>("<xmlattr>.source");
    t = e.second.get<int>("<xmlattr>.target");

    // Check if this is the correct edge
    // Two checks because it can be reversed
    if((id1 == s && id2 == t) || (id1 == t && id2 == s)) {
      edge = e.second;
      break;
    }
  }

  for(auto & attr : edge.get_child("<xmlattr>")) {
    if(attr.first == "end" || attr.first == "start") {
      edge.erase(attr.first);
    }
  }

  write_xml(std::cout, pt);
  return 0;
}

これは動作しません。属性は削除されません。実際、その戻り値を出力するデバッグステートメントを入力すると、がedge.erase(attr.first)表示されます0

4

2 に答える 2

0

答える前に、Boost.PropertyTreeを手っ取り早いXML処理システムとして使用することをお勧めしません。実際のXMLパーサーを使用してください; 選択できるものはたくさんあり、非常に効果的で依存関係のメンテナンスがほとんど必要ないものもあります。

とにかく、あなたの問題はあなたの使用eraseから来ています。繰り返し処理しているリストから要素を消去しようとしています。それはうまくいきません。ループの特別なコーディングなしではありません。

したがって、ここでは範囲ベースのforループを使用できません。イテレータに対して実際のforループを使用する必要があります。

auto &children = edge.get_child();
for(auto &attrIt = children.begin(); attrIt != children.end();)
{
  auto &attr = *attrIt;
  //Do stuff here.


  if(attr.first == "end" || attr.first == "start")
    attrIt = children.erase(attrIt);
  else
    ++attrIt;
}
于 2013-02-08T22:09:02.500 に答える
0

主な問題は、次の行でサブツリーのコピーを作成していることです。

  edge = e.second;

そして、オリジナルの代わりにそのコピーを変更します。後で、@NicolBolas が言ったように、 にはインターレーターが必要ですerase。完全なコードは次のようになります。

int main(){
        boost::property_tree::ptree pt;
        read_xml("ptree_test.gexf", pt, boost::property_tree::xml_parser::trim_whitespace);
        int id1, id2;
        id1 = 0;
        id2 = 1;
        for(auto &e : pt.get_child("gexf.graph.edges")) {
            int s, t;
            s = e.second.get<int>("<xmlattr>.source");
            t = e.second.get<int>("<xmlattr>.target");
            // Check if this is the correct edge
            // Two checks because it can be reversed
            if((id1 == s && id2 == t) || (id1 == t && id2 == s)){
                auto &children = e.second.get_child("<xmlattr>");
                for(auto attrIt = children.begin(); attrIt != children.end(); ++attrIt){
                  if(attrIt->first == "end" || attrIt->first == "start")
                    attrIt = children.erase(attrIt);
                }
                break; // maybe shouldn't be here to keep looking?
            }
        }
        write_xml("ptree_test_copy.gexf", pt, std::locale(), bpt::xml_writer_settings<std::string>{'\t', 1});
}

前後

于 2016-01-02T18:56:53.343 に答える