2

我相信这个问题可能曾在 2006 年在不同的网站上尝试过。但是,我当前的 XML/RDF 编写器 ( XML::LibXML1.70) 以 xmlns 属性的形式输出元素名称空间。这将排除使用非命名空间感知解析器的人,他们只是对foaf:Person. 我想知道是否有人知道 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>

有任何想法吗?我相信无论哪种方式在技术上都是正确的,但我宁愿不依赖其他人知道这一点。昨天我自己都不知道。

4

1 回答 1

5

简短的回答是,如果您已经声明了 namespaceURI 和前缀,您可以指定限定名称(即 prefix: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 命名空间的存在允许多个词汇表在同一个 XML 文档中一起使用。为了实现这一点,引入了命名空间URI (nsURI) 的概念,并在XML 上改进了一种指示哪个nsURI 与XML 文档中的哪些元素和属性相关的机制。为了做到这一点,使用以“xml”开头的属性名称是保留的,允许使用特殊的属性名称(xmlns)而不会有冲突的风险。

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

在 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 文档时,名称空间前缀可能会在奇怪的地方发生变化。大多数解析器都知道命名空间。

于 2010-03-02T10:14:57.533 回答