【问题标题】:Using perl's XML::LibXML how do you use XML Prefixes and not xmlns attributes?使用 perl 的 XML::LibXML 你如何使用 XML Prefixes 而不是 xmlns 属性?
【发布时间】:2010-03-01 23:36:17
【问题描述】:

我相信这个问题might have been previously attempted in 2006 在另一个网站上。但是,我当前的 XML/RDF 编写器 (XML::LibXML1.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>

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

【问题讨论】:

  • 我什至不确定这是否正确。我在这里完全糊涂了。
  • 我和埃文在一起。你错了——你试图把一个有效的 FOAF 文件变成不是的东西。使用非命名空间感知“XML 解析器”的人不是你的问题,如果是,你不应该尝试通过在你的最后破坏东西来修复它。
  • 您是“与”提出问题的埃文还是发表第一个评论的埃文?我不确定你认为谁是“错误的”,但是(有时)有合理的理由来严格控制命名空间声明。这可以通过 XML::LibXML 的 DOM 绑定来实现。就我所见,没有什么是通过行使这种控制“破坏”的。
  • @reinierpost,这是我的困惑:(a) 我不想依赖 XML-NS 感知的 foaf 机器人。 (b) 我不知道或在视觉上不喜欢冗余的 xmlns 属性,并且 (c) 我不知道 foaf:xmlns= 都可以被排除在外,并且仍然有一个工作 foaf 文档。
  • 我支持评论者 Evan,因为您永远不应该更改元素上的命名空间,但您的答案正是提问者 Evan 想要的。

标签: xml perl libxml2 xml-namespaces


【解决方案1】:

简短的回答是,如果您已经声明了 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 Namespaces 的存在允许多个词汇表在同一个 XML 文档中一起使用。为了实现这一点,引入了命名空间URI (nsURI) 的概念,并且在XML 上改进了一种指示哪个nsURI 与XML 文档中的哪些元素和属性相关的机制。这样做是因为属性名称以“xml”are reserved 开头的事实允许使用特殊属性名称 (xmlns) 而不会发生冲突。

一般的想法是,可以将 XML 文档中使用的每个词汇表与唯一的 nsURI(被视为不透明字符串)链接起来。 XHTML 词汇表中的 head 元素完全由 {'http://www.w3.org/1999/xhtml':'head'} 定义,这与(假设的)anatomy-ML {'my-made-up-URI': '头'}。问题是如何在 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 文档时,名称空间前缀可能会在奇怪的地方发生变化。大多数解析器都知道命名空间。

【讨论】:

  • 非常感谢。非常感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 2023-04-11
  • 1970-01-01
相关资源
最近更新 更多