【问题标题】:How to remove attribute with namespace, e.g. xmlns:xsi using DOMElement如何使用命名空间删除属性,例如xmlns:xsi 使用 DOMElement
【发布时间】:2012-10-16 18:12:40
【问题描述】:

我刚刚花了很长时间试图从 DOMNode 中删除一个带有命名空间的属性,但它根本不起作用。

xml 是从数据库生成的,如下所示:

<dictionary>

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <table>answers</table>
  <entity>Answer</entity>
</row>

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <table>file_trans</table>
  <entity>FileTrans</entity>
</row>

...
</dictionary>

我要删除的属性名称显然是“xmlns:xsi”。 postgres db 会自动添加它,我无法在那里删除它,所以我正在尝试使用 php 完成这项工作。

我将 xml 加载为 DOMDocument,然后对所有行元素执行一个 foreach 循环:

$xml = new DOMDocument();
$xml->loadXML($tablesInXml['xmlelement'], LIBXML_NOBLANKS);

foreach($xml->documentElement->childNodes as $row) {
  $row->removeAttribute('xsi');  // not working
  $row->removeAttribute('xmlns:xsi'); // not working
...

我什至尝试探查 DOMNode 属性,它根本不包含任何属性,并且显示长度为 0。

这是 php 5.3 中的错误吗?有人知道我还能做什么吗?

感谢您的任何回答

【问题讨论】:

    标签: php dom


    【解决方案1】:

    你不能用DOMDocument 简单地做到这一点。这些并不是真正的“属性”(它们在 DOM 中作为属性不可见,也不属于 XML 信息集)。它们是命名空间声明,在 xml 序列化之外不存在。最重要的是,它们不会以任何方式出现在 DOM 中。

    libxml2(DOMDocument 的底层 xml 库)在内部跟踪这些“命名空间节点”,但不向它们公开公共接口。因此,如果您克隆或导入一个节点,即使您看不到它,xml 命名空间声明也会随之而来。

    在旧版本的 PHP 中似乎存在一个错误,您可以使用 removeAttributeNS 删除这些节点,但这已得到修复。见the comment on the PHP documentation for this method

    我的意见:你不应该试图摆脱这些节点。这不值得你花时间,离开他们也没有什么坏处。

    但是,如果您真的想摆脱它们,则必须使用另一种方法。一种方法是手动将整个 DOM 树深度复制到新的 DOM 文档中。如果您在复制时使用createElementNSsetAttributeNS(而不是使用importNodecloneNode),则不会在您的副本中创建隐藏的命名空间节点。我不会为您编写代码来执行此操作,因为它会很乏味。

    This stackoverflow answer 建议使用 xslt 解决方案。我不确定它是否会起作用,因为 XSLT 1.0 也没有公开这些命名空间声明“节点”。

    更新

    如果您对 XML 执行的其他操作表示满意,除了只是删除了多余的 XML 节点,您可以尝试XML canonicalization。规范 XML 的目的是确保相同的 XML 信息集始终生成相同的 XML 输出字符串。 (这对于比较 XML 文件或创建校验和哈希等事情很有用。)但它也可以做一些事情,比如从不使用自闭合标签。

    试试看:

    $d = new DOMDocument();
    $d->loadXML($xml, LIBXML_NOBLANKS);
    echo $d->C14N(true, false);
    

    文档:

    【讨论】:

    • 它看起来是蓝色的。我认为这真的不值得我花时间,但我觉得很难做一些如此基本的事情。
    • 你正在做的事情很困难,因为它本质上是一个无操作——它对 XML 信息集没有任何影响。在处理 xml-as-data 时,将输出的 XML 字符串仅视为一种序列化方法会有所帮助。所有 XML 库都将以相同的方式读取此文件。
    • 如果您愿意使用 XML 规范化(这将删除您的命名空间声明,但可能会以其他方式改变您的 XML 序列化),我已经更新了我的答案,提供了有关如何使用它的信息。跨度>
    • 最后,我不需要序列化 ​​xml。 (它用于代码生成。)所以我使用 XML Canonicalization 来完成这项工作。谢谢!
    【解决方案2】:

    你应该使用 removeAttributeNS 方法:

    $row->removeAttributeNS('xmlns:xsi');
    

    更多信息可以在手册中找到:http://www.php.net/manual/en/domelement.removeattributens.php

    【讨论】:

    • 这也不起作用。顺便说一句,您的用法是错误的。该方法需要两个参数,当我执行 $row->removeAttributeNS('xmlns', 'xsi'); 时,它也不会删除该属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2015-07-27
    • 2014-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多