Должен ли я использовать XPath или просто DOM? - PullRequest
9 голосов
/ 04 марта 2011

У меня есть куча иерархических данных, хранящихся в файле 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 ]

5 голосов
/ 05 марта 2011

В целом я предпочитаю решения на основе 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 .

3 голосов
/ 05 марта 2011

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

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

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

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

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

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

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

1 голос
/ 04 марта 2011

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

/*/sig[$pN]/*

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

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

/*/sig[2]/*

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

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

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

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

1 голос
/ 04 марта 2011

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

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

...