Как получить внутренний XML узла в pugi xml? - PullRequest
0 голосов
/ 21 февраля 2020

Я анализирую документ и хочу получить часть дерева XML в виде строки. Документ (пример):

<?xml version="1.0"?>
<MyConfig>
    <MyData>
        <Foo bar="baz>42</Foo>
    </MyData>
    <OtherData>Something</OtherData>
</MyConfig>

Код:

  pugi::xml_document doc;
  doc.load_file(documentFileName);
  pugi::xml_node root = doc.child("MyConfig");

  // parse custom data
  _customData = root.child("MyData"). <-- HOW TO GET INNER XML?

Ожидаемое содержимое пользовательских данных (если форматирование потеряно, я не против):

"<Foo bar="baz>42</Foo>"

Как это сделать?

Ответы [ 2 ]

2 голосов
/ 21 февраля 2020

Я думаю pugi::xml_node::print() - это путь.

pugi::xml_node node = root.child("MyData");
pugi::xml_node child = node.first_child();

std::stringstream ss;
child.print(ss);
std::string s = ss.str();

Проблема в том, что s теперь будет иметь значение

<Foo bar="baz&gt;42&lt;/Foo&gt;     &lt;/MyData&gt;     &lt;OtherData&gt;Something&lt;/OtherData&gt; &gt; &#10;&lt;/MyConfig&gt;" />
  1. Это текстовое дерево от узла и далее;
  2. Это беспорядок с html escape-последовательностями, а не < и >

Не идеально, но это, очевидно, можно решить с помощью некоторых манипуляций со строками.

// replace &lt; with <
size_t off = 0;
while ((off = s.find("&lt;", off)) != s.npos)
  s.replace(off, 4, "<");

// replace &gt; with >
off = 0;
while ((off = s.find("&gt;", off)) != s.npos)
  s.replace(off, 4, ">");

// truncate at the closing tag
size_t end_open = s.find(">", 0);
size_t end_close = s.find(">", end_open + 1);
s = s.substr(0, end_close + 1);

Что будет привести к s, имеющему значение

<Foo bar="baz>42</Foo>
1 голос
/ 21 февраля 2020

Я нашел решение прямо в документах , просто Google плохо их индексирует, поэтому мне пришлось искать его вручную. Моим решением было использовать pugi::xml_writer и node.print. В документах они даже уже показывают реализацию для std::string:

struct xml_string_writer: pugi::xml_writer
{
    std::string result;

    virtual void write(const void* data, size_t size)
    {
        result.append(static_cast<const char*>(data), size);
    }
};

. Имея эту возможность, я просто сделал вспомогательную функцию для объединения XML всех дочерних узлов:

std::string InnerXML(pugi::xml_node target)
{
  xml_string_writer writer;
  for (pugi::xml_node child = target.first_child(); child; child = child.next_sibling())
    child.print(writer, "");
  return writer.result;
}
...