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

Eva*_*oll 2 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>
....
Run Code Online (Sandbox Code Playgroud)

现在,排除空白,我正在尝试重新创建它XML::LibXML.但是,我很遗憾地陷入了第一线.这只关注第一行:

我读到这个

  1. 元素RDF,在命名空间中rdf声明
    1. 带有值的rdf名称空间属性xmlnshttp://www.w3.org/1999/02/22-rdf-syntax-ns#
    2. 带有值的rdfs名称空间属性xmlnshttp://www.w3.org/2000/01/rdf-schema#
    3. 带有值的foaf名称空间属性xmlnshttp://xmlns.com/foaf/0.1/
    4. 带有值的admin名称空间属性xmlnshttp://webns.net/mvcb/

首先你需要一个元素rdf:RDF,这似乎很棘手.阅读我找到的文档,但这似乎没有做我想要的:XML::LibXML::DocumentcreateElementNS()

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"/>
Run Code Online (Sandbox Code Playgroud)

现在,我尝试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' );
Run Code Online (Sandbox Code Playgroud)

实际上我得到了这个错误:"无法在属性上创建新的命名空间!" 这似乎与方法名称所暗示的相矛盾,以及它对文档的描述:"创建绑定到命名空间的属性".

所以,我想,好吧我做不到createattributeNS,也许我可以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' );
Run Code Online (Sandbox Code Playgroud)

这次我得到一个不同的错误:"坏ns属性!" .所以我回顾了一些测试,并发现这个需要一个属性键值而不是命名空间声明来做我想要的..这不是我想要的.

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

$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"/>
Run Code Online (Sandbox Code Playgroud)

尽管我知道它们与XML命名空间有关,但似乎没有任何*NS方法可以工作.最后,我尝试非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#"/>
Run Code Online (Sandbox Code Playgroud)

我感觉到这种可怕的感觉我没有做到这一点.我做对了吗?如何使用DOM(不使用appendTextChild)添加子元素?

这整个XML::LibXML非常不良记录,但似乎是最好的Perl所提供的快速XML创建一个DOM.

And*_*ker 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;
Run Code Online (Sandbox Code Playgroud)

也就是说,您始终需要使用命名空间URI并将命名空间声明添加到根节点(这是您指定命名空间前缀的唯一位置 - 我认为如果您不提供它们,libxml将创建自己的前缀).从维护的角度来看,把它们放在一些变量中显然是明智的.

只要您不需要内存中的DOM来识别名称空间,您的最终(非命名空间)版本就会起作用.这就像1级DOM不了解名称空间一样:您可以将名称空间视为普通属性,文档仍然可以很好地形成(但可能没有很好地形成名称空间).

这有点起作用,但名称空间前缀不是给定的.对此的讨论在别处.