使用perl的XML :: LibXML如何使用XML前缀而不是xmlns属性?

时间:2010-03-01 23:36:18

标签: xml perl libxml2 xml-namespaces

我在另一个网站上相信这个问题might have been previously attempted in 2006。但是,我当前的XML / RDF编写器(XML::LibXML 1.70)以xmlns属性的形式输出元素名称空间。这将排除使用非命名空间感知解析器的人,他们只为foaf:Person执行look_down。我想知道是否有人知道在perl中有一种简单的方法来实现这一点,首先是使用XML::LibXML。或者通过不同的方式。

这样的节点:

  <Person xmlns="http://xmlns.com/foaf/0.1/" rdf:ID="me"/>

而且,这个:

  <name xmlns="http://xmlns.com/foaf/0.1/">Evan Carroll</name>

应该看起来像:

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

有什么想法吗?无论哪种方式,我认为它在技术上是正确的,但我宁愿不依赖于其他人知道这一点。我昨天自己也不知道。

1 个答案:

答案 0 :(得分:4)

简短的回答是,如果您已经声明了namespaceURI和前缀,则可以将限定名称(即前缀:localName)指定为元素名称,这将使XML :: LibXML避免重新声明命名空间。因此,修改上一个问题的代码给出了以下内容,它确实使用了所需的名称空间前缀:

#! /usr/bin/perl 
use warnings;
use strict;
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/', 'foaf: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/', 'foaf:name');
$node2->appendTextNode('Evan Carroll');
$node->appendChild($node2);
print $doc->toString;

或许值得尝试回顾一下发生了什么。存在XML Namespaces以允许在同一XML文档中一起使用多个词汇表。为了实现这一点,引入了namespaceURI(nsURI)的概念,并且指示了哪种nsURI与XML文档中的哪些元素和属性相关联的机制被改进到XML上。要做到这一点,请使用以下属性:属性名称以“xml”are reserved开头,允许使用特殊属性名称(xmlns),而不会发生冲突。

一般的想法是,可以将XML文档中使用的每个词汇表与唯一的nsURI(被视为不透明的字符串)链接起来。 XHTML词汇表中的head元素完全由{'http://www.w3.org/1999/xhtml':'head'}定义,这明显不同于(假设的)解剖结构-ML {'my-made-up-URI ':'头'}。问题是如何将nsURI嵌入到XML文档中以及如何将它们链接到元素名称。

在nsURI和元素名称之间建立链接的一种方法是将xmlns属性添加到元素中。例如:

<name xmlns="http://xmlns.com/foaf/0.1/">Evan Carroll</name>

说“名称”位于“http://xmlns.com/foaf/0.1/”命名空间中。名称空间声明由子项继承,因此'age'位于同一名称空间中:

<name xmlns="http://xmlns.com/foaf/0.1/">Evan Carroll<age years='21'/></name>

这可以很好地工作并且非常紧凑。但是,它不适用于属性,如果许多兄弟节点需要从其共同父级更改命名空间,它可能会变得混乱。为了解决这两个问题,引入了NamespacePrefix(nsPrefix)。这给结肠带来了特殊的意义。我们的想法是将nsURI链接到当前文档中使用的字符串。这在文档之外没有任何特殊含义,也不应该由词汇表指定(但有时候,在别处讨论)。所有nsURI都在根元素上声明是特别常见的。语法是声明命名空间:

xmlns:prefix="http://xmlns.com/foaf/0.1/"

并通过在名称前添加nsPrefix来在属性和元素名称中使用它:

<prefix:name prefix:attribute='value'/>

因为nsPrefixes的确切值不重要,所以API通常不会很容易访问/设置它们(Xpath就是一个很好的例子)。具有名称空间导致对应该被视为错误的文档的一些约束,使用未定义的前缀是一个示例。但是这样的文档可以根据XML规范很好地形成(记住名称空间被改进)。您可以将此类文档描述为“不是格式良好的命名空间”。

如果您知道事先使用的名称空间前缀,那么解析使用名称空间的文档与一个对命名空间一无所知的解析器显然会更容易。但这是一个非常脆弱的解决方案,因为在重复处理XML文档时,名称空间前缀可能会在奇怪的位置发生变化。大多数解析器都支持名称空间。