사용자 도구

사이트 도구


sdk:boost:property-tree

Boost.PropertyTree

문서 주소 : http://www.boost.org/doc/libs/1_51_0/doc/html/property_tree.html#boost_propertytree.intro

프로퍼티트리란?

  • 데이터 구조를 저장하는 라이브러리.
  • 데이터 구조 중에, 트리 형식으로 저장 되는 것들을 다룬다.
  • 트리의 형식은,
    • 깊이에 대한 제한이 없고 트리의 각 단계가 키로 정렬되는 형식을 갖는다.
    • 각 노드는 고유 값이나 정렬된 상태의 서브 노드를 갖을 수 있다.
    • 이 트리는 각 노드에 접근할 때 키의 이름들이 연결 해서 찾으려는 노드에 접근하는 방식을 취한다.
  • 궁극적으로는 트리형식인, XML, INI, JSON에 대한 파서(읽기)와 생성자(제네레이터)를 제공한다.

프로퍼티 트리는 다재다능한 데이터 구조체로 특히, 설정 데이터를 저장하는데 적합하다.
트리는 각 트리에 맞는 인터페이스를 갖고 있고, 각 노드들은 STL호환되는 시퀀스이다.
개념적으로는 각 노드는 이런 형식이 된다.

struct ptree {
  data_type data; // 노드의 데이터
  list< pair<key_type, ptree> > children; // 새로운 키와 새 리스트

'key_type'과 'date_type'은 설정에 따르게 된다. 하지만 보통은 std::string이다. 많은 sw 프로젝트에서 이와 비슷한 툴을 개발하는데, 프로퍼티 트리가 다시 만들어야 하는 굴레를 없앴으면 한다.

Five Minute Tutorial

문서 : http://www.boost.org/doc/libs/1_51_0/doc/html/boost_propertytree/tutorial.html

이 튜토리얼은 xml을 사용하지만 다른 형식의 데이터(INI나 JSON)에도 적용이 가능한다. XML이 광범위하게 사용 되기 때문에 예제로 적당하다고 보고 사용했을 뿐이다.

어떤 앱을 위한 로그 시스템을 만든다고 가정하고, 프로그램이 시작될 때 설정을 읽어오는 부분을 작성한다. 로그 시스템을 위한 설정 파일의 예는 이것 :

<debug>
    <filename>debug.log</filename>
    <modules>
        <module>Finance</module>
        <module>Admin</module>
        <module>HR</module>
    </modules>
    <level>2</level>
</debug>

로그 파일 이름과 로그 기록이 적용되어야 할 모듈 이름, 디버그 레벨이 있다.

로그 설정 정보를 저장할 구조체, debug_settings 구조체는 아래와 같이 작성한다.

struct debug_settings
{
    std::string m_file;          // log filename
    int m_level;                 // debug level
    std::set<string> m_modules;  // modules where logging is enabled
    void load(const std::string &filename);
    void save(const std::string &filename);
};

남은 작업은 load()와 save()함수를 구현하는 것. load() 함수부터 시작한다. 에러 처리를 포함해도 7줄의 코드면 충분하다.

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
 
// debug_settings 구조체에 xml 파일을 읽어온다.
void debug_settings::load(const std::string &filename)
{
    // 프로퍼티트리 선언, 속이 빈 트리 생성
    using boost::property_tree::ptree;
    ptree pt;
 
    // 프로퍼티트리에 xml 파일을 읽어온다. 읽는 작업이 실패하면 
    // (파일 열기 실패, 파싱 실패) 예외처리를 던진다.
    read_xml(filename, pt);
 
    // 주목할 부분은 도트(점,'.')로 구분되는 키key 문자열 스트링을 사용해서 값을 읽어온다는 점. 
    // 다른 구분자는 사용되지 않는다.
    // 'debug.filename' 키가 없으면 예외 리턴(던진다.)
    m_file = pt.get<std::string>("debug.filename");
 
    // m_level 변수에 디버그 레벨을 저장한다.
    // 다른 방식의 get() 메소드를 사용하는데, 값이 없는 경우에는 두번째 파라미터에 있는 기본값(default value)을 리턴한다.
    // 리턴되는 값의 형식의 이 두번째 파라미터에 의해 자동 결정 된다. 따라서 get<int>() 대신 get()만으로 사용할 수 있다.
    m_level = pt.get("debug.level", 0);
 
    // 'debug.modules' 섹션을 반복 검색해서 모든 모듈 값을 m_modules 변수에 저장한다.
    // get_child() 함수는 특정 경로에 있는 자식 노드(child)의 레퍼런스를 리턴한다.
    // 값이 없는 경우, 자식 노드가 없는 경우, 예외를 던진다.
    // 프로퍼티 트리의 이터레이터(iterator)는 BidirectionalIterator 을 사용한다.
    BOOST_FOREACH(ptree::value_type &v,
            pt.get_child("debug.modules"))
        m_modules.insert(v.second.data());
}

save()함수로, 마찬가지로 7줄이다.

// debug_settings 구조체 내용을 xml파일로 저장한다.
void debug_settings::save(const std::string &filename)
{
   // 프로퍼티 트리 선언
   using boost::property_tree::ptree;
   ptree pt;
 
   // 프로퍼티트리에 파일 이름을 기록
   pt.put("debug.filename", m_file);
 
   // 디버그 레벨 값을 기록 예약
   pt.put("debug.level", m_level);
 
   // 모든 모듈 이름을 프로퍼티 트리에 저장.
   // 주목할 점은, put() 함수는 새로운 값은 리스트의 마지막에 추가한다.
   // 이건 보통 괜찮지만, 저장 위치를 처음이나 중간에 하려고 했을 때는
   // put_own()함수와 같이 사용해서 처리할 수 있다.
   BOOST_FOREACH(const std::string &name, m_modules)
      pt.add("debug.modules.module", name);
 
   // 파일로 저장.
   write_xml(filename, pt);
}

예제 소스는 debug_settings.cpp에 있다.

Property Tree as a Container 컨테이너(Container)로서 프로퍼티트리

프로퍼티 트리는 특정 노드에서, 그 노드의 자식 노드를 바로 쓸 수 있도록 고안되었다. 즉, ptree 로 반복수행(iterating)할 때는 트리 전체가 아니라 한 단계의 노드씩 순행 된다는 것이다.

프로퍼티가 키에 의해 정렬된 것이 아니라는 것이 중요하다. 추가될 때의 순서대로 노드들이 구성된다. std::list와 비슷하다. 이름으로 자식 노드에 빨리 이동할 수 있는 것은 전혀 다른 색인 구조로 구성된다.

'binary_search'와 같이 정렬된 상태에서 쓰는 알고리즘을 사용 하면 안된다.

대신 프로퍼티 트리는 컨테이너와 유사한 '뷰'라는 인터페이스를 제공한다. 뷰의 이터레이터는 assoc_iterator 내부의 이터레이터 형식이다.(?) 결국, 정렬된 뷰를 얻을 수 있다. 이때 사용되는 함수는 ordered_begin()과 ordered_end().

The associative view also provides find() and equal_range() members, which return assoc_iterators, but otherwise have the same semantics as the members of std::map of the same name.

You can get a normal iterator from an assoc_iterator by using the to_iterator() member function. Converting the other way is not possible.

How to Populate a Property Tree 프로퍼티 트리에 어떻게 저장되는가

XML Parser

나중에 읽기

JSON Parser

  • JSON 오브젝트는 노드로 맵핑된다. 각 프로퍼티는 자식 노드가 된다.
  • JSON 배열도 노드로 매핑된다. 각 배열 항목 이름이 없는 자식 노드가 된다. 노드에 이름 있는 노드 없는 노드가 같이 있는 경우 JSON의 의도대로 맵핑 되지 않는다.
  • JSON의 값은 노드에 있는 값으로 저장 된다. 이때 타입 정보는 모두 삭제된다. “null”, “true”, “false” 와 같은 문자형식의 값도 모두 문자열로 저장된다.
  • 자식노드와 데이터를 같이 갖고 있는 프로퍼티 트리는 맵핑되지 않는다.

예시 JSON:

{
   "menu":
   {
      "foo": true,
      "bar": "true",
      "value": 102.3E+06,
      "popup":
      [
         {"value": "New", "onclick": "CreateNewDoc()"},
         {"value": "Open", "onclick": "OpenDoc()"},
      ]
   }
}

프로퍼티 트리에는 이렇게 저장된다. (JSON의 진짜 장점을 살리는 건 아니네)

menu
{
   foo true
   bar true
   value 102.3E+06
   popup
   {
      ""
      {
         value New
         onclick CreateNewDoc()
      }
      ""
      {
         value Open
         onclick OpenDoc()
      }
   }
}

INI Parser

나중에 읽기

INFO Parser

나중에 읽기
sdk/boost/property-tree.txt · 마지막으로 수정됨: 2024/04/23 22:44 저자 127.0.0.1