5F 是无效的标签名称 - 它们不允许以数字开头。如果您加载此(无效)XML,解析器将抛出警告。
Warning: simplexml_load_string(): namespace error : Failed to parse QName 'FORMM:' in /in/HHTnS on line 33
Warning: simplexml_load_string(): <FORMM:5F> in /in/HHTnS on line 33
Warning: simplexml_load_string(): ^ in /in/HHTnS on line 33
因此您需要对此进行一些错误处理和/或修复 XML。
但是 LibXML(SimpleXML 和 DOM 背后的库)可以容忍它。所以你仍然可以阅读它。
不要从文档中获取命名空间。这是调试或通用转换的方法。命名空间 URI 是命名空间的标识值。命名空间前缀可以在 XML 中的任何元素处更改。为 Xpath 表达式定义/注册您自己的前缀,并在方法调用中使用命名空间 URI。
print_r(), var_dump(), ... 正在使用 XML 元素的 SimpleXMLs 映射。这是一种妥协并且有限制(尤其是命名空间)。尝试SimpleXMLElement::asXML() 调试SimpleXMLElement 实例。
您仍然可以使用属性语法访问元素,但您可能需要使用 SimpleXMLElement::children() 来指定命名空间。
以下是基于您的问题的示例:
$xml = <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<RETURN:RT
xmlns:FORMM="http://example.com/5"
xmlns:Form="http://example.com/master"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:RETURN="http://example.com">
<FORMM:5F>
<Form:Info>
<Form:SWCreatedBy>SW10002087</Form:SWCreatedBy>
</Form:Info>
</FORMM:5F>
</RETURN:RT>
XML;
// define namespaces you're going to use
$xmlns = [
'five' => 'http://example.com/5',
'master' => 'http://example.com/master',
'return' => 'http://example.com',
];
// a function to apply all of them to a SimpleXMLElement
function registerXpathNamespaces(SimpleXMLElement $target, array $xmlns) {
foreach ($xmlns as $prefix => $namespaceURI) {
$target->registerXpathNamespace($prefix, $namespaceURI);
}
}
$rt = simplexml_load_string($xml);
registerXpathNamespaces($rt, $xmlns);
$list = $rt->xpath('//return:RT/*');
foreach ($list as $fiveF) {
// serialize the node into a string for debugging
var_dump($fiveF->asXML());
// use the namespace list to access child elments in a specific namespace
var_dump(
(string)$fiveF->children($xmlns['master'])->Info->SWCreatedBy
);
}
输出:
string(130) "<FORMM:5F>
<Form:Info>
<Form:SWCreatedBy>SW10002087</Form:SWCreatedBy>
</Form:Info>
</FORMM:5F>"
string(10) "SW10002087"
您需要在每个调用xpath() 的SimpleXMLElement 实例上注册命名空间。
在 DOM 中,这里有一个单独的 Xpath 对象,因此您只需注册一次命名空间。此外,DOMXpath::evaluate() 可以返回标量值(不仅仅是节点列表)。这就是示例在 DOM 中的外观:
// define namespaces you're going to use
$xmlns = [
'five' => 'http://example.com/5',
'master' => 'http://example.com/master',
'return' => 'http://example.com',
];
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
foreach ($xmlns as $prefix => $namespaceURI) {
$xpath->registerNamespace($prefix, $namespaceURI);
}
$list = $xpath->evaluate('//return:RT/*');
foreach ($list as $fiveF) {
// serialize the node into a string for debugging
var_dump($document->saveXML($fiveF));
// directly fetch the value using a string cast in Xpath
var_dump(
$xpath->evaluate(
'string(master:Info/master:SWCreatedBy)',
$fiveF
)
);
}
使用 DOM 你可以看看解析器如何读取损坏的标签。
// the RETURN:RT is valid - the parser can match it to the namespace
var_dump($document->documentElement->localName, $document->documentElement->namespaceURI);
foreach ($list as $fiveF) {
// the "5F" or "FORMM:5F" is invalid - the parser will not match it
var_dump($fiveF->localName, $fiveF->namespaceURI);
}
string(2) "RT"
string(18) "http://example.com"
string(8) "FORMM:5F"
NULL
因此它将别名/前缀保留为名称的一部分并忽略命名空间。