使用XML :: LibXML:如何创建名称空间和子元素并使它们协同工作?

时间:2010-03-01 19:57:58

标签: xml perl xml-namespaces libxml2

我正在尝试用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重新创建此内容。但是,我很遗憾地陷入了第一线。这只关注第一行:

我读到这是

    名称空间RDF中的
  1. 元素rdf声明
      名称空间rdf中的
    1. 属性xmlns,其值为http://www.w3.org/1999/02/22-rdf-syntax-ns#
    2. 名称空间rdfs中的
    3. 属性xmlns,其值为http://www.w3.org/2000/01/rdf-schema#
    4. 名称空间foaf中的
    5. 属性xmlns,其值为http://xmlns.com/foaf/0.1/
    6. 名称空间admin中的
    7. 属性xmlns,其值为http://webns.net/mvcb/
  2. 首先你需要一个元素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::LibXML::Document并且它有效!我得到了根元素createAttributeNS。这是我们应该如何创建根元素?我只是读错了XML吗?

    现在,我需要创建属性(模式声明)。我尝试了记录欠佳的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' ); 上继续使用下一个文档化的方法:$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"/>

    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#"/>
    

    这次我得到一个不同的错误:“bad ns attribute!”。所以我回顾了一些测试,并发现这个测试需要一个除了命名空间声明之外的属性键值来做我想做的事情。这不是我想要的。

    以下是一些可能的组合和输出:

    appendTextChild

    即使我知道它们与XML命名空间有关,但似乎没有任何* NS方法可以工作。最后,我尝试了非NS版本:

    XML::LibXML

    我感到这种可怕的感觉,我做得不对。我做对了吗?如何使用DOM添加子元素(不使用{{1}})?

    整个{{1}} 非常记录不足,但似乎是Perl为使用DOM快速创建XML而提供的最佳功能。

1 个答案:

答案 0 :(得分:6)

从内存(并编辑正确性),你这样做:

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来识别名称空间,您的最终(非命名空间)版本就会起作用。这是因为Level 1 DOM不知道名称空间:您可以将名称空间视为普通属性,并且文档仍然可以很好地形成(但可能没有很好地形成名称空间)。

这很有用,但命名空间前缀不是给定的。讨论这个is elsewhere