PHP - SimpleXMLElement 未使用名称空间正确解析

问题描述 投票:0回答:2

这是由 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)

php xml xpath simplexml
2个回答
1
投票

不要从文档中获取命名空间。在您的应用程序中定义它们。命名空间是

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 表达式,并可以返回节点列表或标量,具体取决于表达式。

$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"

0
投票

这是如何通过节点元素方法完成的,例如 $xml->内容->属性->id ?

© www.soinside.com 2019 - 2024. All rights reserved.