如何从PHP中删除XML中的所有命名空间(标记和属性)

时间:2013-03-05 11:59:04

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

我最近对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>

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

2 个答案:

答案 0 :(得分:4)

我一直在寻找相同的东西,但我知道最好不要尝试使用正则表达式来对抗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>";
?>

答案 1 :(得分:1)

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

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

然后,您可以动态更改这些值并输出(可能已更改的)数据。

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

您可以在a previous answer of mine中找到一些样板代码来启动它。