【问题标题】:Can't access XML node using xpath (namepace issue?)无法使用 xpath 访问 XML 节点(命名空间问题?)
【发布时间】:2019-01-29 15:20:09
【问题描述】:

我有一小部分从名为 tridion 的 cms 导出的 xml,我想使用 php 解析这些信息。

我尝试使用DOMDocumentDOMXPath 访问数据,但未能检索到所需信息。

例如,当我尝试从示例数据中访问节点 title 时,我没有得到任何结果。

$xmlDoc = new DOMDocument();
$xmlDoc->load($xmlFilePath);

$xpath = new DOMXPath($xmlDoc);
$xpath->registerNamespace('tcm', 'http://www.tridion.com/ContentManager/5.0');
$xpath->registerNamespace('xmlns', 'http://www.w3.org/1999/xlink');
$result = $xpath->query('title');

我认为这是一个命名空间问题,但我真的不明白如何处理它。

这是导出文件的样子(为了便于阅读,有些缩短):

<PackageItem xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.sdltridion.com/ContentManager/ImportExport/Package/2013">
  <PrimaryBlueprintParentUrl>/webdav/Content%20%28en%29/Content/120_external%20Links/Services/EL_www%2some-domin%2Ecom.xml</PrimaryBlueprintParentUrl>
  <Data>
    <tcm:Data>
      <tcm:Title>EL_www.some-domain.com</tcm:Title>
      <tcm:Type>Normal</tcm:Type>
      <tcm:Schema xlink:type="simple" xlink:title="External Link (EL)" xlink:href="/webdav/Content/System/Schemas/Common/External%20Link%20%28EL%29.xsd" IsMandatory="false" />
      <tcm:Content>
        <externallink xmlns="uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8">
          <title>www.some-domain.com</title>
          <url xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.some-domain.com" />
        </externallink>
      </tcm:Content>
    </tcm:Data>
  </Data>
</PackageItem>

【问题讨论】:

  • 您是否尝试过使用 simplexml_load_string。这会将 xml 转换为对象
  • 复制完整的错误信息也很有帮助
  • 没有错误信息,我的 xpath 查询根本没有返回任何东西。
  • 我也尝试过使用simplexml_load_string(),但这个函数似乎无法处理 xml 命名空间。

标签: php dom xpath tridion


【解决方案1】:

&lt;externallink&gt; 元素之前定义了它的默认命名空间,&lt;title&gt; 元素定义为xmlns="uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8"。所以如果你定义这个命名空间(我只是使用一个虚拟的 - d)然后在你的表达式中使用它......

$xpath->registerNamespace('d', "uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8");
$result = $xpath->query('//d:title');

更新...

对于网址...

$result = $xpath->query('//d:url');

echo $xmlDoc->saveXML($result[0]);

给...

<url xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.some-domain.com"/>

因为它没有这样的值(我刚刚说过要输出找到的第一个节点的 XML),所以不确定你需要什么。

如果你只想要 href 属性...

echo $result[0]->getAttribute("xlink:href");

【讨论】:

  • 感谢您的帖子。您建议的代码可以很好地检索标题信息!您能否添加一些有关如何获取 url 信息的信息?似乎附加到 url 属性的命名空间引起了一些麻烦。至少$xpath-&gt;query('//d:url'); 不起作用。
  • 我已经添加了 URL 代码 - 这取决于你想从中得到什么?
【解决方案2】:

您错过了为正确的命名空间注册别名。这是命名空间 uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8 的元素 externallink 的命名空间定义。 XML 解析器将该节点理解为{uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8}externallink,将title 子元素理解为{uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8}title。以下 3 个示例都解析为这样的 title 节点:

  • &lt;title xmlns="uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8"/&gt;
  • &lt;t:title xmlns:t="uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8"/&gt;
  • &lt;el:title xmlns:el="uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8"/&gt;

通过在 DOMXpath 实例上注册别名,您允许它对表达式执行相同的操作。

$xpath->registerNamespace('e', 'uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8');

e:title -> {uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8}title

Xpath 1.0 没有默认命名空间,因此您必须为要在表达式中使用的任何命名空间注册一个别名。

但是e:title 只会查找子节点。要查看文档中的任何节点,请使用//e:title。起始 / 将表达式锚定到文档本身(而不是当前上下文节点)。第二个/ 将轴从child 更改为descendant。 使用string() 将第一个匹配的节点转换为字符串并返回:

$xpath = new DOMXPath($xmlDoc);
$xpath->registerNamespace('e', 'uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8');
var_dump($xpath->evaluate('string(//e:title)'));

输出:

string(19) "www.some-domain.com"

DOMXpath::query() 只能返回节点列表,DOMXpath::evaluate() 也可以返回标量值。

对于xlink:href 属性,您还需要注册该命名空间:

$xpath = new DOMXPath($xmlDoc);
$xpath->registerNamespace('e', 'uuid:D612E2C9-CD2E-4CD8-9FAE-3826311343A8');
$xpath->registerNamespace('xlink', 'http://www.w3.org/1999/xlink');
var_dump($xpath->evaluate('string(//e:url/@xlink:href)'));

输出:

string(26) "http://www.some-domain.com"

【讨论】:

    猜你喜欢
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    相关资源
    最近更新 更多