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

如何在PHP中从XML中删除所有名称空间(标记和属性),php,xml,regex,xml-parsing,xml-namespaces,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',

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

是否有任何正则表达式大师可以提供帮助?

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

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

然后可以动态更改这些值并输出可能更改的数据

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


您可以找到一些样板代码来开始这项工作。

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

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

然后可以动态更改这些值并输出可能更改的数据

通过这种方式,您不再需要关心正则表达式,这对于正确的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进行搜索,搜索任何关于使用正则表达式解析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>";
?>

你在用什么?我发现通过使用基于expat的解析器来重新编写XML通常比较容易,下面是一个答案,其中有一个例子说明了基本语法是如何工作的:您在使用吗?我发现通过使用基于expat的解析器来重写XML通常更容易,下面是一个答案,其中有一个例子说明了基本语法是如何工作的:感谢这个答案,我避免使用XMLParser扩展名,因为它一次只读取一个文件块。我处理的文件太大,服务器无法一次性处理。XMLReader允许我读取文件并动态执行操作,但SimpleXML不允许您立即访问带名称空间的标记或属性,因此我希望在使用SimpleXML解析XML块之前删除所有名称空间,希望在标记的每次迭代中都能给我一个完整的数组/对象。@BenArtiss:那么我有个好消息告诉你,XMLParser也能处理数据块。你可以传递桶,对于最后一个桶,你会发送一个标志,表明这是最后一个桶。虽然我很高兴使用hakre的解决方案,但知道如何在preg_替换中实现重复条件还是很好的。如果有人知道如何使用正则表达式,它肯定会对将来的其他正则表达式有所帮助。@Ben Artiss:你的意思是想学习如何用常规的epress解析XML?好了,没有人阻止你,这里有一个很好的介绍性阅读::谢谢你的回答,我避免使用XMLParser扩展名,因为它一次读取一整块文件。我处理的文件太大,服务器无法一次性处理。XMLReader允许我读取文件并动态执行操作,但SimpleXML不允许您立即访问带名称空间的标记或属性,因此我希望在使用SimpleXML解析XML块之前删除所有名称空间,希望在标记的每次迭代中都能给我一个完整的数组/对象。@BenArtiss:那么我有个好消息告诉你,XMLParser也能处理数据块。你可以传入bucket,在最后一个bucket中,你会发送一个标志,表明这是最后一个bucket
e很高兴知道如何实现preg_替换中的重复条件。如果有人知道如何使用正则表达式,它肯定会对将来的其他正则表达式有所帮助。@Ben Artiss:你的意思是想学习如何用常规的epress解析XML?好吧,没有人阻止你,这里有一个很好的介绍性阅读::完美。我正在编写一个可以使用来自任何源的任何XML的系统,因此在运行中弄清楚如何处理所有名称空间比我想承担的工作量要大得多,这在将来可能会对我不利,但值得为原型设计冒风险。一个变化:这段代码在嵌套的名称空间上不起作用;我将getDocNamespaces切换为getNamespacestrue,解决了这个问题。但愿我能再投一票。太好了。我正在编写一个可以使用来自任何源的任何XML的系统,因此在运行中弄清楚如何处理所有名称空间比我想承担的工作量要大得多,这在将来可能会对我不利,但值得为原型设计冒风险。一个变化:这段代码在嵌套的名称空间上不起作用;我将getDocNamespaces切换为getNamespacestrue,解决了这个问题。但愿我能再投一票。