【问题标题】:How to remove all namespaces from XML in PHP (tags and attributes)如何从 PHP 中的 XML 中删除所有命名空间(标签和属性)
【发布时间】:2013-02-19 19:40:50
【问题描述】:

我最近对 ​​XML 命名空间感到非常痛苦,并在 PHP 中有效地处理它们。这是最坏的罪魁祸首的示例:

<dc:type xsi:type="TypeName" xsi:identifier="NN">Others</dc:type>

我使用 preg_replace 成功地做到的是使用以下方法“取消命名空间”标签(不破坏 URL):

$xml = preg_replace(
  '/<(\/?)([^:" ].*):([^>\/ ].*)(\/?)>/msiU',
  '<$1$2_$3$4>',
  $x->readOuterXML()
);

# <dc_type xsi:type="TypeName" xsi:identifier="NN">Others</dc_type>

由于缺少正则表达式魔法,我无法将所有命名空间属性转换为相同的格式。我设法转换了第一次出现,但不知道如何设置可重复的条件。我删除了代码,因为它不起作用(我不记得我做了什么),但结果是这样的:

<dc_type xsi_type="TypeName" xsi:identifier="NN">Others</dc_type>

而美丽的是这样:

<dc_type xsi_type="TypeName" xsi_identifier="NN">Others</dc_type>

有没有正则表达式大师可以提供帮助?

【问题讨论】:

标签: php xml regex xml-parsing xml-namespaces


【解决方案1】:

我一直在寻找同样的东西,但我知道最好不要尝试对 XML 使用正则表达式(搜索关于使用正则表达式解析 XML/HTML 的任何 StackOverfow 问题,并阅读整个答案以找出原因。你会看到就知道了)!

这是我想出的代码:

<?php
// Some test XML
$xml = <<<XML
<root xmlns:a="bogus.a" xmlns:b="bogus.b">
    <a:first>
        <b:second>text</b:second>
    </a:first>
</root>
XML;

$sxe = new SimpleXMLElement($xml);
$dom_sxe = dom_import_simplexml($sxe);

$dom = new DOMDocument('1.0');
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);

$element = $dom->childNodes->item(0);

// See what the XML looks like before the transformation
echo "<pre>\n" . htmlspecialchars($dom->saveXML()) . "\n</pre>";
foreach ($sxe->getDocNamespaces() as $name => $uri) {
    $element->removeAttributeNS($uri, $name);
}
// See what the XML looks like after the transformation
echo "<pre>\n" . htmlspecialchars($dom->saveXML()) . "\n</pre>";
?>

【讨论】:

  • 完美。我正在编写一个可以使用来自任何来源的任何 XML 的系统,因此即时弄清楚如何处理所有命名空间比我想要承担的工作要多得多(将来它会咬我的可能性很小,但值得冒险进行原型设计)。一个变化:这段代码不适用于嵌套的命名空间;我将getDocNamespaces() 切换为getNamespaces(true),这解决了问题。希望我能再投赞成票。
【解决方案2】:

要重写完整的 XML 文档,例如重命名元素或属性名称以及更改命名空间相关数据(例如 xmlns 属性),您可以使用基于 expat 的 xml 解析器扩展:

这通过解析文件并动态更改输出来工作。解析器调用回调函数(所谓的handler),获取预先解析的数据,例如字符串形式的元素名称和数组形式的属性。

然后您可以即时更改这些值并输出(可能更改的)数据。

通过这种方式,您不再需要关心正则表达式(这对于正确的 XML 解析来说非常重要)。

您可以在 a previous answer of mine 中找到一些样板代码来开始这项工作。

【讨论】:

  • 感谢您的回答,我避免使用 XMLParser 扩展,因为它以一个块(AFAIK)读取整个文件。我一直在处理的文件太大,服务器无法一次性处理。 XMLReader 允许我读取文件并即时执行操作,但 SimpleXML 不能让您立即访问命名空间标签或属性,因此我希望在使用 SimpleXML 解析 XML 块之前删除所有命名空间,希望能给我一个完整的在标签的每次迭代中使用的数组/对象。
  • @BenArtiss:那么我要告诉你一个好消息,XMLParser 也可以处理数据块。您可以传入存储桶,并为最后一个存储桶发送一个标志,说明它是最后一个。
  • 虽然我很高兴使用 hakre 的解决方案,但如果知道如何在 preg_replace 中实现重复条件,仍然会很高兴。如果有人知道如何,它肯定会在未来对其他正则表达式有所帮助。
  • @Ben Artiss:您的意思是您想学习如何使用常规 epressions 解析 XML?好吧,没有人阻止你,这是一个很好的介绍性阅读:cs.sfu.ca/~cameron/REX.html :)
猜你喜欢
  • 2020-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
相关资源
最近更新 更多