Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/230.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 不需要前缀的默认名称空间的SimpleXML中的XPath_Php_Xml_Xpath_Namespaces_Simplexml - Fatal编程技术网

Php 不需要前缀的默认名称空间的SimpleXML中的XPath

Php 不需要前缀的默认名称空间的SimpleXML中的XPath,php,xml,xpath,namespaces,simplexml,Php,Xml,Xpath,Namespaces,Simplexml,我有一个附加了默认名称空间的XML文档,例如 ... 实际上,这是一个符合复杂模式的复杂XML文档。我的工作是从中解析出一些数据。为了帮助我,我有一个XPath电子表格。XPath嵌套得相当深,例如 level1/level2/level3[@foo="bar"]/level4[@foo="bar"]/level5/level6[2] 生成XPath的人是模式方面的专家,因此我假设我不能简化它,也不能使用对象遍历快捷方式 我用它来解析一切。我的问题与如何处理默认名称空间有关 因为根元素上有

我有一个附加了默认名称空间的XML文档,例如


...
实际上,这是一个符合复杂模式的复杂XML文档。我的工作是从中解析出一些数据。为了帮助我,我有一个XPath电子表格。XPath嵌套得相当深,例如

level1/level2/level3[@foo="bar"]/level4[@foo="bar"]/level5/level6[2]
生成XPath的人是模式方面的专家,因此我假设我不能简化它,也不能使用对象遍历快捷方式

我用它来解析一切。我的问题与如何处理默认名称空间有关

因为根元素上有一个默认名称空间,所以我不能这样做

$xml = simplexml_load_file($somepath);
$node = $xml->xpath('level1/level2/level3[@foo="bar"]/level4[@foo="bar"]/level5/level6[2]');
我必须,将其分配给前缀,然后在XPath中使用前缀,例如

$xml = simplexml_load_file($somepath);
$xml->registerXPathNamespace('myns', 'http://www.example.com/ns/1.0');
$node = $xml->xpath('myns:level1/myns:level2/myns:level3[@foo="bar"]/myns:level4[@foo="bar"]/myns:level5/myns:level6[2]');
从长远来看,添加前缀是不可管理的

是否有一种正确的方法来处理默认名称空间,而不需要在XPath中使用前缀

使用空前缀不起作用(
$xml->registerXPathNamespace(“”,”http://www.example.com/ns/1.0);
)。我可以列出默认名称空间,例如

$xml = file_get_contents($somepath);
$xml = str_replace('xmlns="http://www.example.com/ns/1.0"', '', $xml);
$xml = simplexml_load_string($xml);

但是这就回避了这个问题。

为了避免类似于您的
str_replace
这样的黑客攻击(我建议您避免),您可以通过XSLT运行XML文件来去除名称空间:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myns="http://www.example.com/ns/1.0">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="myns:*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@* | node()" />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

在以下任一输入上运行时:

<foo xmlns="http://www.example.com/ns/1.0">
  <a>
    <child attr="5"></child>
  </a>
</foo>

<ex:foo xmlns:ex="http://www.example.com/ns/1.0">
  <ex:a>
    <ex:child attr="5"></ex:child>
  </ex:a>
</ex:foo>

输出相同:

<foo>
  <a>
    <child attr="5" />
  </a>
</foo>

这将允许您在结果上使用前缀较少的XPath

有没有合适的方法来处理默认名称空间而不需要 在XPath中使用前缀

不可以。处理任何名称空间的正确方法是将某个值(前缀)与该名称空间关联,以便可以在XPath表达式中显式选择该名称空间。默认名称空间也不例外

这样考虑:某个名称空间中的元素和另一个名称空间中具有相同名称的元素(或者根本没有名称空间)是不同的元素。它们可能意味着(即代表)不同的事物。这就是重点。您需要告诉XPath要选择哪一个。没有它,XPath就不知道您要的是什么

从长远来看,添加前缀是不可管理的

我真的不明白为什么。创建XPath表达式的任何东西都应该能够指定正确的XPath表达式(或者它是一个坏工具)

您可能会想,“为什么我不能忽略名称空间并获取与该名称匹配的所有元素?”有很多方法可以做到这一点(比如已经发布的基于XSLT的答案),但它们被设计破坏了。XML中的元素通过名称空间和本地名称的组合来标识,就像您的房子可以通过某个城市和州(名称空间)的街道号(本地名称)来标识一样。如果我告诉你我住在主街422号,那么你仍然不知道我住在哪里,直到我告诉你哪个城市和州

您可能仍然会想,“别再进行愚蠢的类比了,我真的,真的很想这么做了”“您可以通过只匹配元素的本地名称部分,在所有名称空间中选择具有给定名称的元素,如下所示:

*[local-name()='level1']/*[local-name()='level2']
    /*[local-name()='level3' and @foo="bar"]/*[local-name()='level4' and 
        @foo="bar"]/*[local-name()='level5']/*[local-name()='level6'][2]');
请注意,这不会将其自身限制为默认名称空间。它完全忽略名称空间。这很难看,我不推荐这样做,但有时候你只是想忽略最好的,然后做点什么


顺便说一下,这不是PHP的错。这是XPath规范所要求的。必须指定前缀才能选择命名空间中的节点。如果PHP允许您以其他方式进行操作,那么无论他们如何称呼它,它将不再是XPath(根据规范)。

通过在线阅读,这并不局限于任何特定的PHP或其他库,而是XPath本身——至少在XPath版本1.0中是如此

XPath 1.0不包含任何“默认”名称空间的概念,因此无论元素名称在XML源中如何显示,如果元素名称绑定了名称空间,则它们的选择器必须以
ns:name
格式的基本XPath选择器作为前缀。请注意,
ns
是XPath处理器中定义的前缀,而不是由正在处理的文档定义的,因此与XML表示中如何使用
xmlns
属性无关

例如,请参见谈论密切相关的XSLT 1.0:

要访问XPath中带名称空间的元素,必须为其名称空间定义前缀。[…]不幸的是,XSLT版本1.0没有类似于默认名称空间的概念;因此,必须一次又一次地重复名称空间前缀

根据,XPath2.0确实包含了“默认名称空间”的概念,上面链接的XSLT页面在XSLT2.0的上下文中也提到了这一点

不幸的是,PHP中的所有内置XML扩展都是在和库之上构建的,这些库只支持XPath和XSLT的1.0版本

因此,除了不使用名称空间对文档进行预处理之外,您唯一的选择是找到一个可以插入PHP的XPath2.0处理器


(顺便说一句,值得注意的是,如果XML文档中有不固定的属性,从技术上讲,它们不在默认名称空间中,而是根本不在名称空间中;有关名称空间规范这种奇怪之处的讨论,请参阅。)

您所说的“添加前缀从长远来看是不可管理的”是什么意思?为什么会这样?@JLRishe我尽量简化这个问题。XPath当前位于XLS中。我们可能会自动完成这一过程,因此系统将读取XLS(XML文件的目录),然后输入所有数据映射。我发现通过代码向XPath添加前缀容易出错