Должен ли я использовать XPath или просто DOM?

У меня есть куча иерархических данных, хранящихся в файле XML. Я оборачиваю это позади созданных вручную классов, используя TinyXML. Данный фрагмент XML, который описывает сигнатуру источника как набор пар (частота, уровень), выглядит примерно так:

<source>
  <sig><freq>1000</freq><level>100</level><sig>
  <sig><freq>1200</freq><level>110</level><sig>
</source>

Я извлекаю пары с этим:

std::vector< std::pair<double, double> > signature() const
{
    std::vector< std::pair<double, double> > sig;
    for (const TiXmlElement* sig_el = node()->FirstChildElement ("sig");
        sig_el;
        sig_el = sig_el->NextSiblingElement("sig"))
    {
        const double level = boost::lexical_cast<double> (sig_el->FirstChildElement("level")->GetText());
        const double freq =  boost::lexical_cast<double> (sig_el->FirstChildElement("freq")->GetText());
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

где node() указывает на <source> узел.

Вопрос: получу ли я более аккуратный, более изящный, более удобный для обслуживания или каким-либо иным способом более качественный кусок кода с использованием библиотеки XPath?

Обновление: я пробовал использовать TinyXPath двумя способами. Ни один из них на самом деле не работает, что, очевидно, является важным аргументом против них. Я делаю что-то в корне неправильно? Если так будет выглядеть XPath, я не думаю, что он мне что-то даст.

std::vector< std::pair<double, double> > signature2() const
{
    std::vector< std::pair<double, double> > sig;
    TinyXPath::xpath_processor source_proc (node(), "sig");
    const unsigned n_nodes = source_proc.u_compute_xpath_node_set();
    for (unsigned i = 0; i != n_nodes; ++i)
    {
        TiXmlNode* s = source_proc.XNp_get_xpath_node (i);
        const double level = TinyXPath::xpath_processor(s, "level/text()").d_compute_xpath();
        const double freq =  TinyXPath::xpath_processor(s, "freq/text()").d_compute_xpath();
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

std::vector< std::pair<double, double> > signature3() const
{
    std::vector< std::pair<double, double> > sig;
    int i = 1;
    while (TiXmlNode* s = TinyXPath::xpath_processor (node(), 
        ("sig[" + boost::lexical_cast<std::string>(i++) + "]/*").c_str()).
        XNp_get_xpath_node(0))
    {
        const double level = TinyXPath::xpath_processor(s, "level/text()").d_compute_xpath();
        const double freq =  TinyXPath::xpath_processor(s, "freq/text()").d_compute_xpath();
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

В качестве вторичной проблемы, если так, какую библиотеку XPath я должен использовать?

4 ответа

Решение

В целом я предпочитаю решения на базе XPath за их краткость и универсальность, но, честно говоря, в вашем случае, я не думаю, что использование XPath принесет много пользы вашему signature,

Вот почему:

Код элегантности
Ваш код красив и компактен, и он не станет лучше с выражением XPath.

След памяти
Если ваш входной XML-файл конфигурации не является огромным (своего рода оксюморон) и анализ DOM повлечет за собой большой объем памяти, для которого нет никаких доказательств того, что использование XPath будет решающим лекарством, я бы придерживался DOM.

Скорость выполнения
В таком простом дереве XML скорость выполнения должна быть сопоставимой. Если бы была разница, это, вероятно, было бы выгодно для TinyXml из-за расположения freq а также level теги под данным узлом.

Библиотеки и внешние ссылки Это решающий момент.
Ведущий движок XPath в мире C++ - XQilla. Он поддерживает XQuery (следовательно, и XPath 1.0 и 2.0) и поддерживается Oracle, потому что он разработан группой, ответственной за продукты DB Berkeley (включая именно Berkeley DB XML - который использует XQilla).
Проблема для разработчиков C++, желающих использовать XQilla, состоит в том, что у них есть несколько альтернатив

  1. используйте Xerces 2 и XQilla 2.1, засоряйте ваш код кастами.
  2. используйте XQilla 2.2+ и используйте Xerces 3 (здесь не нужно кастовать)
  3. используйте TinyXPath, красиво интегрированный с TinyXml, но для которого, однако, существует ряд ограничений (например, нет поддержки пространств имен)
  4. смешайте Xerces и tinyXml

Таким образом, в вашем случае переход на XPath только ради этого принесет мало пользы, если таковой будет.

Тем не менее, XPath является очень мощным инструментом в сегодняшнем наборе инструментов для разработчиков, и никто не может его игнорировать. Если вы просто хотите попрактиковаться на простом примере, ваш так же хорош, как и любой другой. Тогда я бы помнил о вышеприведенных пунктах и, возможно, все равно использовал TinyXPath.

Вам нужен XPath, если вам нужна гибкость для внесения изменений во время выполнения в извлеченные значения.

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

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

Я бы, безусловно, задокументировал то, что у вас есть, немного лучше, поскольку те, кто не знаком с библиотеками tinyxml или xml, могут быть не уверены в том, что они делают, но их нетрудно понять.

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

Если вы действительно хотите использовать библиотеку xpath, то все, что я могу сказать, - это то, что я использовал ту, которая шла с Xerces-C++, и это было не слишком сложно для изучения. Я использовал TinyXML раньше, и кто-то здесь упомянул TinyXPath. У меня нет опыта с этим, но он доступен.

Я также нашел эту ссылку полезной, когда впервые узнал о выражениях XPath. http://www.w3schools.com/xpath/default.asp

XPath был создан для этого, поэтому, конечно, ваш код будет "лучше", если вы его используете.

Я не могу рекомендовать конкретную библиотеку XPath C++, но даже если ее использование будет правильным решением в большинстве случаев, прежде чем добавлять ее, проведите анализ затрат и выгод. Может быть, ЯГНИ.

Это выражение XPath:

/*/sig[$pN]/*

выбирает все дочерние элементы (только пара freq а также level) из $pN-го sig дочерний элемент верхнего элемента XML-документа.

Строка $pN должен быть заменен определенным положительным целым числом, например:

/*/sig[2]/*

выбирает эти два элемента:

<freq>1200</freq><level>110</level>

Использование выражения XPath, поскольку это, очевидно, намного короче и понятнее, чем предоставляемый код C++.

Другое преимущество заключается в том, что одно и то же выражение XPath можно использовать из программ на C#, Java или... без какой-либо его модификации - таким образом, соблюдение XPath приводит к очень высокой степени переносимости.

Другие вопросы по тегам