среда, 25 ноября 2009 г.

[comp.prog.3.1415…] Крик души: как же я ненавижу XML!!!

Это просто не передать словами… Когда приходится писать код вида:

std::string get_service_name( const Document & document )
  {
    AutoPtr< NodeList > services = document.getElementsByTagName( "service" );
    if( 1 != services->length() )
      throw ...;
    Node * first = services->item( 0 )->firstChild();
    if( !first )
      throw ...;
    if( Node::TEXT_NODE != first->nodeType() )
      throw ...;
    return first->nodeValue();
  }

я испытываю если не рвотные позывы, то что-то очень близкое к ним.

Хочется попробовать в деле что-то вроде Code Synthesis’s C++/Tree, да нет времени, трясти нужно. Если у кого-то есть опыт работы с данным продуктом, поделитесь, пожалуйста, впечатлениями – как оно? Еще интересно, сколько стоит коммерческая лицензия, а то они на сайте цену не указывают.

9 комментариев:

Alexander P. комментирует...

Ну если сокращать конкретно этот код (не обращая внимания на то, что при парсинге XML/YAML обычными С++-методами такой код вообще почти везде :-)), то можно последние строчки выделить в отдельную функцию std::string xml::get_single_child_value(Node*) и мы сэкономим 5 строчек!

Сделаем ещё одну функцию, чтобы сократить начало.

Node* xml::get_document_single_node_by_name(Document*, const std::string&)

Итого одна длинная строчка!

Чем не костыль? :-)

P.S. Я с Вами полностью согласен, да. Ненавижу.

eao197 комментирует...

Ну да, как только такой код начал плодиться, я почти сразу выделил такие функции.

Зверёк комментирует...

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

Потому что без них он бы превратился в

document.getElementsByTagName( "service" )->item( 0 )->firstChild()->nodeValue();

...что является почти что прямым изложением соответствующего XPath-выражения.

XML-то причём? Если проверять каждый элемент сложных данных с таким же уровнем тщательности, то код всегда будет так выглядеть.

Анонимный комментирует...

Может попробовать Poco::Util::XMLConfiguration ?

Типа так:

struct service_xml_t : public Poco::Util::XMLConfiguration
{
service_xml_t( const std::string& file ) : XMLConfiguration( file ) {}

std::string get_service_name() const
{
std::string value;

if ( getRaw( "service.name[0]", value ) )
return value;

throw ...
}
};

...

service_xml_t service( "1.xml" );
std::cout << service.get_service_name() << std::endl;


Получается что-то вроде XPath. Они даже сами об этом пишут:
http://www.appinf.com/docs/poco/Poco.Util.XMLConfiguration.html

Роман

eao197 комментирует...

2coolaga: за подсказку спасибо, раньше я про XMLConfiguration не знал. Посмотрю поближе.

eao197 комментирует...

2zverok: если параноидальная проверка должна присутствовать (а она должна, поскольку данные приходят от партнера), то код по работе с XML вырождается именно в такие штуки. И даже XPath, имхо, здесь не будет большим помошником.

А XML здесь причем, поскольку это угробищный формат и инструменты для него угробищные.

Kodt комментирует...

Насчёт параноидности...
А несложно её в выражение завернуть:

template<class T> bool exists(T*p)
{ return p!=0; }

template<class T> bool singular(T*p)
{ return p!=0 && p->length()==1; }

template<class T> bool textnode(T*p)
{ return p!=0 && p->nodeType()==TEXT_NODE; }

template<class T> T* ensure(bool(*test)(T*), T* p)
{
if(!test(p)) throw .....;
return p;
}
.....
return
ensure(textnode,
ensure(exist,
ensure(singular, document.getElementsByTagName("service")
)->item(0)
)->firstChild()
)->nodeValue();

Или, в инфиксной форме, - нужно пойти на маленькие хитрости: перегрузить оператор, ну скажем, ->*

document.getElementsByTagName("service") ->* ensure(exists) ->* ensure(singular) -> item(0) ->* ensure(exists) ->* firstChild() ->* ensure(textnode) -> nodeValue();

Но это уже совсем уличная магия будет. Пошаговой отладке практически недоступная :)))

Kodt комментирует...

Проклятые рудники!
Почему нет тэга <pre>

eao197 комментирует...

2Kodt: такой магический код я бы своих подчиненных заставил бы переписывать ;)