PHP - SimpleXMLElement 无法正确解析名称空间
PHP - SimpleXMLElement not parsing correctly with namespaces
这是由API返回的:
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="https://exmple.com/odata/">
<id>https://example.com/odata/PicklistOption(989L)</id>
<title type="text" />
<updated>2015-09-03T11:56:51Z</updated>
<author>
<name />
</author>
<link rel="edit" title="PicklistOption" href="PicklistOption(989L)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/childPicklistOptions" type="application/atom+xml;type=feed" title="childPicklistOptions" href="PicklistOption(989L)/childPicklistOptions" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/parentPicklistOption" type="application/atom+xml;type=entry" title="parentPicklistOption" href="PicklistOption(989L)/parentPicklistOption" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/picklistLabels" type="application/atom+xml;type=feed" title="picklistLabels" href="PicklistOption(989L)/picklistLabels" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/picklist" type="application/atom+xml;type=entry" title="picklist" href="PicklistOption(989L)/picklist" />
<category term="SFOData.PicklistOption" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:id m:type="Edm.Int64">989</d:id>
<d:status>ACTIVE</d:status>
<d:sortOrder m:type="Edm.Int32">229</d:sortOrder>
<d:minValue m:type="Edm.Double">-1</d:minValue>
<d:externalCode>PL</d:externalCode>
<d:optionValue m:type="Edm.Double">-1</d:optionValue>
<d:maxValue m:type="Edm.Double">-1</d:maxValue>
</m:properties>
</content>
</entry>
正在尝试获取 <d:id>
$xml = new SimpleXMLElement($xmlstr);
$namespaces = $xml->getNameSpaces(true);
$xml->registerXPathNamespace('m', $namespaces['m']);
$xml->registerXPathNamespace('d', $namespaces['d']);
$id = $xml->xpath('/entry/content/m:properties/d:id');
var_dump($id);
但我得到 array(0)
。
不要从文档中获取命名空间。在您的应用程序中定义它们。命名空间是 xmlns
/xmlns:*
属性的值。 xmlns
属性是默认命名空间。所以标签 entry
实际上是 {http://www.w3.org/2005/Atom}:entry
.
命名空间必须是唯一的。为避免冲突,大多数人使用 URL。 (其他人不太可能使用您的域来定义他们的名称空间。)这样做的缺点是名称空间是带有特殊字符的大字符串。这可以通过使用名称空间前缀作为别名来解决。
Xpath 没有默认命名空间。您需要为您喜欢使用的每个命名空间注册一个前缀。 Xpath引擎会将前缀解析为实际的命名空间,并将其与解析后的节点命名空间进行比较。
$xml = new SimpleXMLElement($xmlstr);
$namespaces = [
'a' => 'http://www.w3.org/2005/Atom',
'm' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
'd' => 'http://schemas.microsoft.com/ado/2007/08/dataservices',
'o' => 'https://exmple.com/odata/'
];
foreach ($namespaces as $prefix => $namespace) {
$xml->registerXPathNamespace($prefix, $namespace);
}
$id = $xml->xpath('/a:entry/a:content/m:properties/d:id');
var_dump($id);
输出:
array(1) {
[0]=>
object(SimpleXMLElement)#2 (0) {
}
}
您必须在每个 SimpleXMLElement 上再次注册 Xpath 命名空间。
这在 DOM 中更方便。 DOMXpath::evaluate()
执行 Xpath 表达式并且可以 return 节点列表或标量,具体取决于表达式。
$document = new DOMDocument($xmlstr);
$document->loadXml($xmlstr);
$xpath = new DOMXpath($document);
$namespaces = [
'a' => 'http://www.w3.org/2005/Atom',
'm' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
'd' => 'http://schemas.microsoft.com/ado/2007/08/dataservices',
'o' => 'https://exmple.com/odata/'
];
foreach ($namespaces as $prefix => $namespace) {
$xpath->registerNamespace($prefix, $namespace);
}
$id = $xpath->evaluate('string(/a:entry/a:content/m:properties/d:id)');
var_dump($id);
输出:
string(3) "989"
这是由API返回的:
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="https://exmple.com/odata/">
<id>https://example.com/odata/PicklistOption(989L)</id>
<title type="text" />
<updated>2015-09-03T11:56:51Z</updated>
<author>
<name />
</author>
<link rel="edit" title="PicklistOption" href="PicklistOption(989L)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/childPicklistOptions" type="application/atom+xml;type=feed" title="childPicklistOptions" href="PicklistOption(989L)/childPicklistOptions" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/parentPicklistOption" type="application/atom+xml;type=entry" title="parentPicklistOption" href="PicklistOption(989L)/parentPicklistOption" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/picklistLabels" type="application/atom+xml;type=feed" title="picklistLabels" href="PicklistOption(989L)/picklistLabels" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/picklist" type="application/atom+xml;type=entry" title="picklist" href="PicklistOption(989L)/picklist" />
<category term="SFOData.PicklistOption" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:id m:type="Edm.Int64">989</d:id>
<d:status>ACTIVE</d:status>
<d:sortOrder m:type="Edm.Int32">229</d:sortOrder>
<d:minValue m:type="Edm.Double">-1</d:minValue>
<d:externalCode>PL</d:externalCode>
<d:optionValue m:type="Edm.Double">-1</d:optionValue>
<d:maxValue m:type="Edm.Double">-1</d:maxValue>
</m:properties>
</content>
</entry>
正在尝试获取 <d:id>
$xml = new SimpleXMLElement($xmlstr);
$namespaces = $xml->getNameSpaces(true);
$xml->registerXPathNamespace('m', $namespaces['m']);
$xml->registerXPathNamespace('d', $namespaces['d']);
$id = $xml->xpath('/entry/content/m:properties/d:id');
var_dump($id);
但我得到 array(0)
。
不要从文档中获取命名空间。在您的应用程序中定义它们。命名空间是 xmlns
/xmlns:*
属性的值。 xmlns
属性是默认命名空间。所以标签 entry
实际上是 {http://www.w3.org/2005/Atom}:entry
.
命名空间必须是唯一的。为避免冲突,大多数人使用 URL。 (其他人不太可能使用您的域来定义他们的名称空间。)这样做的缺点是名称空间是带有特殊字符的大字符串。这可以通过使用名称空间前缀作为别名来解决。
Xpath 没有默认命名空间。您需要为您喜欢使用的每个命名空间注册一个前缀。 Xpath引擎会将前缀解析为实际的命名空间,并将其与解析后的节点命名空间进行比较。
$xml = new SimpleXMLElement($xmlstr);
$namespaces = [
'a' => 'http://www.w3.org/2005/Atom',
'm' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
'd' => 'http://schemas.microsoft.com/ado/2007/08/dataservices',
'o' => 'https://exmple.com/odata/'
];
foreach ($namespaces as $prefix => $namespace) {
$xml->registerXPathNamespace($prefix, $namespace);
}
$id = $xml->xpath('/a:entry/a:content/m:properties/d:id');
var_dump($id);
输出:
array(1) {
[0]=>
object(SimpleXMLElement)#2 (0) {
}
}
您必须在每个 SimpleXMLElement 上再次注册 Xpath 命名空间。
这在 DOM 中更方便。 DOMXpath::evaluate()
执行 Xpath 表达式并且可以 return 节点列表或标量,具体取决于表达式。
$document = new DOMDocument($xmlstr);
$document->loadXml($xmlstr);
$xpath = new DOMXpath($document);
$namespaces = [
'a' => 'http://www.w3.org/2005/Atom',
'm' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
'd' => 'http://schemas.microsoft.com/ado/2007/08/dataservices',
'o' => 'https://exmple.com/odata/'
];
foreach ($namespaces as $prefix => $namespace) {
$xpath->registerNamespace($prefix, $namespace);
}
$id = $xpath->evaluate('string(/a:entry/a:content/m:properties/d:id)');
var_dump($id);
输出:
string(3) "989"