Должен ли я использовать 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 мне следует использовать?


person Pete    schedule 04.03.2011    source источник


Ответы (4)


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

Вот почему:

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

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

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

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

person Alain Pannetier    schedule 05.03.2011

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

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

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

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

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

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

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

person hookenz    schedule 05.03.2011

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

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

person Jon    schedule 04.03.2011

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

/*/sig[$pN]/*

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

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

/*/sig[2]/*

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

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

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

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

person Dimitre Novatchev    schedule 04.03.2011
comment
Я вижу, как нотация XPAth упрощает описание узла, но когда это реализовано в C++ API, преимущества становятся гораздо менее очевидными. - person Pete; 07.03.2011
comment
@Pete: Почему ты говоришь мне, что не собираешься обернуть весь этот код C++ в функцию? Таким образом, у вас будет только someObj.SelectNode('Expression') -- хорошие принципы разработки программного обеспечения не зависят от языка. - person Dimitre Novatchev; 07.03.2011
comment
@Dimitre Novatchev: Я не уверен, к чему ты клонишь. Я пытаюсь обернуть это в функцию, указанную в исходном вопросе, будет ли это лучше с XPath, чем без него? Из-за отсутствия у меня опыта работы с XPath в вашем SomeType something = someObj.SelectNode ("Expression") я не вижу, какие SomeType, someObj или Exptression могут помочь. - person Pete; 07.03.2011
comment
@Pete: Почему бы тебе не прочитать документацию о методах SelectNodes() и SelectSingleNode()? Это даст вам хорошую идею. Кроме того, если эти два метода уже реализованы, зачем вообще нужно их повторно реализовывать? - person Dimitre Novatchev; 07.03.2011
comment
@Dimitre: кажется, я вижу путаницу: у TinyXPath нет метода SelectNodes. Где я должен искать документацию по этим методам? Я обнаружил, что некоторые из них применимы к JScript API. В любом случае, если я получу узлы, разве я не вернусь к использованию методов DOM для извлечения из них содержимого? - person Pete; 07.03.2011
comment
@Pete: это документация MSDN (щелкните вкладку C++): msdn. microsoft.com/en-us/library/hcebdtae.aspx - person Dimitre Novatchev; 07.03.2011
comment
Я понимаю. Если бы я только использовал .Net. Однако спасибо, это помогло прояснить, что мне делать с библиотекой, которую я использую. - person Pete; 07.03.2011
comment
@Пит: Точно. Я думаю, что это поможет в вашем дизайне. - person Dimitre Novatchev; 07.03.2011