我需要用我自己的值更改 xmlns 属性。我该怎么做?最好使用DOMDocument 类。
这在设计上是不可能的。每个DOMDocument 都有一个根/文档元素。
在您的示例 XML 中,根元素是:
{http://test.com/test}ONIXMessage
我将元素名称写为 expanded-name,约定将命名空间 URI 放在尖括号中。
将元素名称写成显示其完整的形式expanded-name也表明您不仅要在此处更改属性的值,而且要更改名称空间的URI一个特定的元素。所以你想改变元素名称。如果子元素在同一个命名空间中,它还可能包含它包含的任何子元素名称。
由于xmlns attribute 只反映了元素本身的命名空间URI,你不能改变它。一旦在DOMDocument 中设置,您将无法更改它。
你可以替换整个元素,但是子元素的命名空间也不会改变。这里有一个类似于你的 XML 的示例,只有 textnode 子节点(没有命名空间):
$xml = <<<EOD
<?xml version="1.0"?>
<ONIXMessage xmlns="uri:old">
...data...
</ONIXMessage>
EOD;
$doc = new DOMDocument();
$doc->loadXML($xml);
$newNode = $doc->createElementNS('uri:new', $doc->documentElement->tagName);
$oldNode = $doc->replaceChild($newNode, $doc->documentElement);
foreach(iterator_to_array($oldNode->childNodes, true) as $child) {
$doc->documentElement->appendChild($child);
}
生成的 XML 输出为:
<?xml version="1.0"?>
<ONIXMessage xmlns="uri:new">
...data...
</ONIXMessage>
现在将输入 XML 更改为包含类似子项的内容
<?xml version="1.0"?>
<ONIXMessage xmlns="uri:old">
<data>
...data...
</data>
</ONIXMessage>
然后将创建以下输出,注意现在再次弹出的旧命名空间 URI:
<?xml version="1.0"?>
<ONIXMessage xmlns="uri:new">
<default:data xmlns:default="uri:old">
...data...
</default:data>
</ONIXMessage>
如您所见,DOMDocument 不提供开箱即用替换现有元素的命名空间 URI 的功能。但是希望到目前为止,通过此答案中提供的信息,可以更清楚地说明为什么如果该属性值已经存在,则无法更改它。
expat based parser in the libxml based PHP extension 确实允许“更改”现有属性值,无论它是否为 xmlns* 属性 - 因为它只是解析数据,您可以使用它即时处理它。
一个工作示例是:
$xml = <<<EOD
<?xml version="1.0" encoding="utf-8"?>
<ONIXMessage xmlns="uri:old">
<data>
...data...
</data>
</ONIXMessage>
EOD;
$uriReplace = [
'uri:old' => 'uri:new',
];
$parser = xml_parser_create('UTF-8');
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_default_handler($parser, function ($parser, $data) {
echo $data;
});
xml_set_element_handler($parser, function ($parser, $name, $attribs) use ($xml, $uriReplace) {
$selfClosing = '/>' === substr($xml, xml_get_current_byte_index($parser), 2);
echo '<', $name;
foreach ($attribs as $name => $value) {
if (substr($name, 0, 5) === 'xmlns' && isset($uriReplace[$value])) {
$value = $uriReplace[$value];
}
printf(' %s="%s"', $name, htmlspecialchars($value, ENT_COMPAT | ENT_XML1));
}
echo $selfClosing ? '/>' : '>';
}, function ($parser, $name) use ($xml) {
$selfClosing = '/>' === substr($xml, xml_get_current_byte_index($parser) - 2, 2);
if ($selfClosing) return;
echo '</', $name, '>';
});
xml_parse($parser, $xml, true);
xml_parser_free($parser);
然后输出透明地将命名空间 URI 从 uri:old 更改为 uri:new:
<ONIXMessage xmlns="uri:new">
<data>
...data...
</data>
</ONIXMessage>
正如本例所示,您在 XML 中使用的每个 XML 特性都需要由解析器处理。例如,缺少 XML 声明。然而,这些可以通过实现缺失的处理程序类回(例如for CDATA sections)或通过输出缺失的输出(例如“缺失”的 XML 声明)来添加。我希望这会有所帮助,并向您展示如何更改这些不打算更改的值的替代方法。