Использование XML :: LibXML: как создать пространства имен и дочерние элементы и заставить их работать вместе?

Я пытаюсь что-то делать с FOAF и Perl. Я недоволен текущими решениями и хочу использовать свои собственные. Пожалуйста, не ссылайтесь ни на какой другой модуль, кроме XML::LibXML.

Для справки - отрывок из файла FOAF.

<rdf:RDF
      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
      xmlns:foaf="http://xmlns.com/foaf/0.1/"
      xmlns:admin="http://webns.net/mvcb/">

  <foaf:Person rdf:ID="me">
  <foaf:name>Evan Carroll</foaf:name>
....

Теперь, исключая пробелы, я пытаюсь воссоздать это с помощью XML::LibXML. Однако, к сожалению, я застрял на самой первой строчке. Это просто фокусируется на первой строке:

Я прочитал это, чтобы быть

  1. element RDF, in namespace rdf declares
    1. attribute rdf in namespace xmlns with value http://www.w3.org/1999/02/22-rdf-syntax-ns#
    2. атрибут rdfs в пространстве имен xmlns со значением http://www.w3.org/2000/01/rdf-schema#
    3. атрибут foaf в пространстве имен xmlns со значением http://xmlns.com/foaf/0.1/
    4. атрибут admin в пространстве имен xmlns со значением http://webns.net/mvcb/

Во-первых, вам нужен элемент rdf:RDF, это может показаться сложным. Прочитав документацию для XML::LibXML::Document, я обнаружил createElementNS() но, похоже, это не то, что я хочу:

use XML::LibXML;
my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $foaf = $doc->createElementNS( 'RDF', 'rdf' );
print $foaf->toString; # prints <rdf xmlns="RDF"/>

Теперь я пробую createElement('rdf:RDF'), и он работает! Получил корневой элемент rdf:RDF. Так мы должны создавать корневые элементы? Я просто неправильно читаю XML?

Теперь мне нужно создать атрибуты (объявления схемы). Я пробовал плохо документированные XML::LibXML::Document createAttributeNS, но это тоже не сработало:

my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $foaf = $doc->createElement( 'rdf:RDF' );
$doc->createAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf' );

На самом деле я получаю такую ​​ошибку: «не могу создать новое пространство имен для атрибута!», что кажется противоречащим тому, что подразумевает имя метода, и его описанию в документации: «Создает Атрибут, привязанный к пространству имен "

Итак, я полагаю, хорошо, я не могу create и attributeNS, может, тогда я смогу set и attributeNS. И на этот раз на XML::LibXML::Element я перехожу к следующему документированному методу, который выглядит применимым: setAttributeNS.

my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $foaf = $doc->createElement( 'rdf:RDF' );
$foaf->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf' );

На этот раз я получаю другую ошибку: "bad ns attribute!". Итак, я просматриваю некоторые из тестов и обнаруживаю, что для этого требуется атрибут "ключ-значение", отличный от объявления пространства имен, чтобы делать то, что я хочу ... Это не то, что я хочу.

Вот несколько возможных комбинаций и выходов:

$foaf->setAttributeNS( http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:', undef );
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:=""/>

$foaf->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:foo', 'bar' );
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:foo="bar"/>

Кажется, что ни один из методов * NS не работает, хотя я знаю, что они связаны с пространствами имен XML. Наконец, я пробую версию, отличную от NS:

my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $foaf = $doc->createElement( 'rdf:RDF' );
$foaf->setAttribute( 'xmlns:rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' );
print $foaf->toString; # <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>

У меня ужасное чувство, что я делаю это неправильно. Я сделал это правильно? Как мне добавить дочерний элемент в DOM (не используя appendTextChild)?

Все это XML::LibXML очень плохо документировано, но кажется лучшим, что Perl может предложить для быстрого создания XML с помощью DOM.


person Evan Carroll    schedule 01.03.2010    source источник
comment
Поскольку Эван явно запретил это, я не буду упоминать другие модули, но отмечу, что при работе с RDF лучше использовать модуль, специфичный для RDF, тем более, что XML - плохая сериализация RDF.   -  person MkV    schedule 02.03.2010
comment
Я делаю это для FOAF, если вы знаете о более широком распространении этого, чем XML, тогда дерзайте! Если нет, то я пытаюсь создать модель, которая предоставит вам шаблоны и визуализации FOAF и HCARD из TT и Catalyst. В частности, для создания материалов социального веб-типа и обслуживания поисковых роботов, которые могут их использовать (карты Google).   -  person Evan Carroll    schedule 02.03.2010


Ответы (1)


По памяти (и отредактировано для корректности), вы делаете это так:

use XML::LibXML;
my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $foaf = $doc->createElementNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDF' );
$doc->setDocumentElement( $foaf );
$foaf->setNamespace( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' , 'rdf', 1 );
$foaf->setNamespace( 'http://www.w3.org/2000/01/rdf-schema#' , 'rdfs', 0 );
$foaf->setNamespace( 'http://xmlns.com/foaf/0.1/' , 'foaf', 0 );
$foaf->setNamespace( 'http://webns.net/mvcb/' , 'admin', 0 );
my $node = $doc->createElementNS( 'http://xmlns.com/foaf/0.1/', 'Person');
$foaf->appendChild($node);
$node->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'ID', 'me');
my $node2 = $doc->createElementNS( 'http://xmlns.com/foaf/0.1/', 'name');
$node2->appendTextNode('Evan Carroll');
$node->appendChild($node2);
print $doc->toString;

То есть вам всегда нужно использовать URI пространства имен и добавлять объявления пространств имен к корневому узлу (это единственное место, где вы указываете префикс пространства имен - я думаю, libxml изобретет свои собственные префиксы, если вы их не предоставите). Очевидно, с точки зрения обслуживания было бы разумно поместить их в некоторые переменные.

Ваша окончательная версия (без пространства имен) будет работать до тех пор, пока вам не понадобится DOM в памяти для поддержки пространства имен. Это работает, поскольку DOM уровня 1 не знает о пространствах имен: вы можете рассматривать пространства имен как обычные атрибуты, и документ все равно будет правильно сформирован (но, возможно, не будет правильно сформировано пространство имен).

Это работает до определенной степени, но префиксы пространства имен не такие, как указано. Обсуждение этого в другом месте.

person Andrew Walker    schedule 01.03.2010
comment
Это отличный пост, но он вообще не компилируется для меня? Любые идеи? - person Evan Carroll; 02.03.2010
comment
@Evan: какая часть не компилируется? - person Ether; 02.03.2010
comment
Не удается скомпилировать с XML :: LibXML 1.70: не удается найти метод объекта createElementNS через пакет XML :: LibXML :: Element - person Evan Carroll; 02.03.2010
comment
Было сказано, что W3C DOM API довольно противоречиво интуитивно понятен. Попробуйте эту версию. - person Andrew Walker; 02.03.2010
comment
createElementNS - это метод документа. Я думаю, вы хотите addNewChild при создании дочерних узлов. Кроме того, не должен ли name быть потомком Person, а не корневым узлом? - person cjm; 02.03.2010
comment
Хорошо - я думаю, что ошибка добавления атрибута. Это лучше? - person Andrew Walker; 02.03.2010
comment
Кажется, это работает в значительной степени (забыл несколько точек с запятой), у него <Person xmlns="http://xmlns.com/foaf/0.1/" rdf:ID="me"><name>Evan Carroll</name></Person>, мой первый вопрос будет заключаться в том, как сделать узел, состоящий из <foaf:Person rdf:ID="me">. Я знаю, как установить атрибутNS, но как создать узел <foaf:Person>, поддерживающий NS? - person Evan Carroll; 02.03.2010
comment
Я думаю, что здесь дан ответ на этот вопрос: justskins.com/ форумы / Похоже, что синтаксически они одинаковы, а XML :: LibXML не поддерживает красивую опцию NS. Интересно, сработает ли механизм социального сканирования в Google <person xmlns="foafurl"> или нет ... - person Evan Carroll; 02.03.2010
comment
Я не уверен, что это правильно, см. Мое продолжение stackoverflow.com/questions/2359920/ - person Evan Carroll; 02.03.2010