我有一个XML文档,它附加了一个默认命名空间,例如
...
实际上,这是一个符合复杂模式的复杂XML文档.我的工作是从中解析出一些数据.为了帮助我,我有一个XPath的电子表格. XPath是相当深层嵌套的,例如
level1/level2/level3[@foo="bar"]/level4[@foo="bar"]/level5/level6[2]
生成XPath的人是模式的专家,所以我假设我不能简化它,或者使用对象遍历快捷方式.
我正在使用SimpleXML来解析所有内容.我的问题与如何处理默认命名空间有关.
由于根元素上有一个默认命名空间,我不能这样做
$xml = simplexml_load_file($somepath);
$node = $xml->xpath('level1/level2/level3[@foo="bar"]/level4[@foo="bar"]/level5/level6[2]');
我必须到register the namespace,将它分配给前缀,然后在我的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);
但这是在绕过这个问题.
解决方法:
从在线阅读,这不仅限于任何特定的PHP或其他库,而是限于XPath本身 – 至少在XPath版本1.0中
XPath 1.0不包含任何“默认”命名空间的概念,因此无论元素名称如何出现在XML源中,如果它们具有绑定到它们的命名空间,则它们的选择器必须以表单的基本XPath选择器为前缀NS:名称.请注意,ns是在XPath处理器中定义的前缀,而不是正在处理的文档,因此与XML表示中如何使用xmlns属性无关.
To access namespaced elements in XPath, you must define a prefix for their namespace. […] Unfortunately, XSLT version 1.0 has no concept similar to a default namespace; therefore, you must repeat namespace prefixes again and again.
根据an answer to a similar question,XPath 2.0确实包含“默认命名空间”的概念,上面链接的XSLT页面也在XSLT 2.0的上下文中提到了这一点.
遗憾的是,PHP中的所有内置XML扩展都是在libxml2和libxslt库之上构建的,这些库仅支持1.0版的XPath和XSLT.
因此,除了预处理文档而不使用命名空间之外,您唯一的选择是找到可以插入PHP的XPath 2.0处理器.
(另外,值得注意的是,如果你在XML文档中有无前缀的属性,它们在技术上并不在默认命名空间中,而是根本没有命名空间;请参阅XML Namespaces and Unprefixed Attributes以讨论命名空间规范的这种奇怪之处.)
标签:php,xml,xpath,namespaces,simplexml
来源: https://codeday.me/bug/20190926/1818841.html