1 Kasım 2017 Çarşamba

property_tree xml Parse Etme

Giriş
Bu yazıdaki metod isimileri sıralı değil. get() metodu ile attribute okuma, get_value() ile düğümün değerini okuma ve yine get() metodu ile alt düğümün değerini okuma gösteriliyor.

get metodu - attribute okuma
Örnek
Elimizde şöyle bir xml olsun.
<Element type="MyType">
  <Name type="Number">
    <KeyFrame time="0">1920</KeyFrame>
    <KeyFrame time="3000">1080</KeyFrame>
    <KeyFrame time="4000">720</KeyFrame>
  </Name>
</Element>
Düğümün attribute değerine erişmek için şöyle yaparız.
keyFrame.get<int>("<xmlattr>.time", 0)
Dolaşarak bu işlemi yaparsak çıktı olarak şunu alırız.
0
3000
4000
Örnek
Elimizde şöyle bir xml olsun.
<flight cancelled="true">
...
</flight>
Düğümün attribute değerine erişmek için şöyle yaparız.
ptree flight = ...;
bool cancelled =  flight.get("<xmlattr>.cancelled", false);
Örnek
Elimzde şöyle bir xml olsun.
<Master Name='gamma'>
  <Par1 Name='name1'>
    <Value>0.</Value>
    <Fix>1</Fix>
  </Par1>
  <Par2 Name='name2'>
    <Value>0.</Value>
    <Fix>1</Fix>
  </Par2>
</Master>
Par2 düğümüne erişmek için şöyle yaparız. get() metodu ile alt düğümün değeri okunur.
void processTree(ptree const& par2) {
  std::string n = par2.get<std::string>("<xmlattr>.Name");

  double val = par2.get<double>("Value");
  std::cout << __FUNCTION__ << ": n=" << n << " val=" << val << "\n";
}

processTree(pt.get_child("Master.Par2"));
Çıktı olarak şunu alırız.
processTree: n=name2 val=0
get_child metodu - Alt düğüme erişme
İsmi verilen alt düğüme erişmek için kullanılır. Bu metod yerine get_child_optional tercih edilebilir.

Yeni bir property_tree nesnesi döner. Eğer bu nesnesyi iterator ile dolaşırsak her eleman boost::property_tree::ptree::value_type tipindendir. Bu tip aslında bir std::pair tipidir.
Örnek
Elimizde şöyle bir xml olsun
<Element type="MyType">
  <Name type="Number">
    <KeyFrame time="0">1920</KeyFrame>
    <KeyFrame time="3000">1080</KeyFrame>
    <KeyFrame time="4000">720</KeyFrame>
  </Name>
</Element>
Tüm KeyFrame düğümlerini dolaşmak için şöyle yaparız.
auto& root =  pt.get_child("Element");
for (auto& child : root.get_child("Name")) //Name'in altındaki düğümlere eriş
{
  if(child.first == "KeyFrame")
  {
    std::cout<< child.second.get<int>("<xmlattr>.time", 0) << " : " 
      << childd.second.data() << std::endl;
    }
}
Örnek
Elimizde şöyle bir xml olsun.
<listOfItems>
  <Items>
    <item>
    </item>
    <item> 
    </item>
  </Items>
  <Items>
    <item>
    </item>
    <item> 
    </item>
  </Items>
</listOfItems>
Tüm <item> düğümlerini dolaşmak için şöyle yaparız. Önce get_child ("listOfİtems") ile <Items> düğümleri bulunur. Daha sonra her düğüm için v2.second ile <item> düğümleri dolaşılır.
ptree empty_tree;
for (auto& ptree::value_type &v2, pt.get_child("listOfItems", empty_tree))
{
  if(v2.first == "Items")
  { 
    for (auto& ptree::value_type &v3, v2.second)    {
      if(v3.first == "Item"){
        ...
      }
    }
  }
}
Örnek
Elimizde şöyle bir xml olsun.
<?xml version="1.0" encoding="utf-8"?>
<config>
    <name>testing</name>
    <!-- Test property tree -->
    <lambda min="200000" max="200">100</lambda>
...
Bu xml'i okuyalım. Şöyle yaparız.
ptree tree;
std::ifstream xml("input.txt");
read_xml(tree, config);
Daha sonra iki kırılımlı alt düğüme gidelim. Şöyle yaparız.
ptree const& t = tree.get_child("config.lambda");
get_child metodu - Alt düğüme erişme veya default değer
İsmi verilen alt düğüme erişmek için kullanılır. Bu metod yerine get_child_optional tercih edilebilir.

Örnek
Elimizde şöyle bir xml olsun
<?xml version="1.0" encoding="UTF-8"?>
<document version="1.3.0">
  <chunk>
    <cameras>
      <camera...>
        ...
      </camera>
      <camera ...>
        ...
      </camera>
    </cameras>
   </chunk>
</document>
Şöyle yaparız.
ptree tree;
...
const ptree & formats = tree.get_child("document.chunk.cameras", empty_ptree());
Örnek
Bur örnekte attribute mevcudiyeti kontrol ediliyor. Elimizde şöyle bir xml olsun.
<lambda min="200000" max="200">100</lambda>
Düğümün attribute'leri olup olmadığını anlamak için şöyle yaparız.
boost::property_tree::ptree lambda = ...;
// Get the attributes (or empty)
auto p = lambda.get_child("<xmlattr>", boost::property_tree::ptree());

// If we have attributes, read them
if (p != boost::property_tree::ptree())
{
  auto min = lambda.get<double>("<xmlattr>.min");  
  auto max = lambda.get<double>("<xmlattr>.max");       
 }
get_child_optional metodu - Alt düğüme erişme
boost::optional döner. Alt düğüme erişir.
Örnek
Elimizde şöyle bir xml olsun
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Txn ver="1.0">
  <TOpts tCount="1"  tformat="0"  ttimeout="10" />
  <TData>
    <Tvalue date="YYMMDD" time="HHMM" Ref="100"/>
  </TData>
  <TCustOpts>
    <Param name="SALE" value="xyz" />
  </TCustOpts>
</Txn>
Bu xml'i şu yapılara okumak isteyelim.
struct TOpts {
  size_t count;
  std::string format;
  size_t timeout ;
};

struct TData {
  std::string date; // YYMMD
  std::string time; // HHMM
  size_t ref;
};

struct TCustOpts {
  std::multimap<std::string, std::string> params;
};

struct Txn {
  std::string version;
  TOpts opts;
  TData data;
  TCustOpts custom_opts;
};
Her tag için parse metodu yazarız.
// concrete parse functions
void parse(Domain::TOpts& v, ptree const& pt) {
  v.count   = pt.get("<xmlattr>.tCount", 0);
  v.format  = pt.get("<xmlattr>.tformat", "0");
  v.timeout = pt.get("<xmlattr>.ttimeout", 0);
}

void parse(Domain::TData& v, ptree const& pt) {
  v.date = pt.get("Tvalue.<xmlattr>.date", "YYMMDD");
  v.time = pt.get("Tvalue.<xmlattr>.time", "HHMM");
  v.ref  = pt.get("Tvalue.<xmlattr>.Ref", 0);
}

void parse(Domain::TCustOpts& v, ptree const& pt) {
  for (auto& param : pt) {
    if (param.first != "Param")
      continue;

  v.params.emplace(
    param.second.get("<xmlattr>.name", "(anon)"),
    param.second.get("<xmlattr>.value", ""));
  }
}
Her tag'e erişmek için şöyle yaparız.
// make any parse helper available optionally
template <typename T>
void parse_optional(T& v, boost::optional<ptree const&> pt) {
  if (pt) parse(v, *pt);
}

void parse(Domain::Txn& v, ptree const& pt) {
  v.version = pt.get("<xmlattr>.ver", "0.0");
  parse_optional(v.opts,        pt.get_child_optional("TOpts"));
  parse_optional(v.data,        pt.get_child_optional("TData"));
  parse_optional(v.custom_opts, pt.get_child_optional("TCustOpts"));
}
Kök düğümden parse etmek için şöyle yaparız.
boost::property_tree::ptree pt = ...;

Txn transaction;
parse(transaction, pt.get_child("Txn"));
get_value metodu - tag içindeki değer
Düğümün kendi değerine alır.
Örnek
Elimizde şöyle bir xml olsun.
<Element type="MyType">
  <Name type="Number">
    <KeyFrame time="0">1920</KeyFrame>
    <KeyFrame time="3000">1080</KeyFrame>
    <KeyFrame time="4000">720</KeyFrame>
  </Name>
</Element>

KeyFrame düğümlerinin değerini almak için şöyle yaparız.
node.get_value<int>();
Dolaşarak bu işlemi yaparsak çıktı olarak şunu alırız.
1920
1080
720
Örnek
Elimizde şöyle bir xml olsun.
<lambda min="200000" max="200">100</lambda>
Şöyle yaparız.
double value = t.get_value<double>();

get metodu - alt düğümü okuma
Düğümün altındaki ismi verilen düğümün değerini alır.
Örnek
Elimizde şöyle bir xml olsun.
<flight cancelled="true">
  <number>4002</number>
  ...
</flight>
Düğümün değerine erişmek için şöyle yaparız.
int number = flight.get("number", 0);


Hiç yorum yok:

Yorum Gönder