在有效的 PHP query() XPath 中转换 Javascript XPath |规范化 JS XPath --> PHP
Posted
技术标签:
【中文标题】在有效的 PHP query() XPath 中转换 Javascript XPath |规范化 JS XPath --> PHP【英文标题】:Transform Javascript XPath in valid PHP query() XPath | normalize JS XPath --> PHP 【发布时间】:2012-08-01 12:55:42 【问题描述】:这是 javascript 中的有效 XPath:
id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]
这变成了与 DOMXPath 一起使用的有效 php XPath->query() 是
//*[@id="priceInfo"]//div[@class="standardProdPricingGroup"]//span[1]
-
您知道任何已经进行此转换的库或自定义组件吗?
您知道列出这两种语法差异的可用文档吗?
我主要担心可能存在很多差异,我正在寻找这些差异,但我在识别这些差异时遇到了问题。
这个问题也可以用不同的方式提出:由于 Javascript 可以有不同的有效 XPath 格式,如何规范它们以与 PHP 一起使用。
其中一个更新还提到,如果存在包含此定义的有效 DTD,则 id() 函数是有效的 XPath。我对输入 DTD 没有控制权,如果有办法找到无需任何特定 DTD 即可工作的解决方案,那就太棒了。
更新:
我想用算法将第一种格式转换为第二种格式。我的输入是第一个而不是第二个。无法更改。
正如@Nison Maël 所指出的,第二种格式是有效的 Javascript XPath,如下所示:http://jsbin.com/elatum/2/edit 不幸的是,这只会增加 Javascript XPath“碎片化”的问题。
@salathe 指出,如果记录的输入具有有效的 DTD(@Dimitre Novatchev 在评论中提到这一点,但忽略了重要性),则有效的 Javascript XPath 查询在 PHP 中可以正常工作。不幸的是,我无法控制输入 DTD,所以现在我必须研究一种方法来克服这个问题,或者找到一个即使没有有效 DTD 也能工作的解决方案。
【问题讨论】:
这是一个很好的问题!看起来那里没有任何文档(至少不是通过粗略的谷歌搜索)。我很高兴看到这个问题的答案。 第一个表达式是合法的 XPath 表达式。但是,要使 Xpath 函数id()
起作用,XML 必须具有 DTD,并且 DTD 中的元素定义必须具有具有 ID
关键字的属性。
@DimitreNovatatchev:那么//
到/
的翻译呢?
@choroba Java 在整个问题中没有被提及一次。此外,id()
是您链接到的规范中提到的 节点集函数。
我不认为 javascript 的 xpath 与 php 有很大不同。我的意思是xpath语言应该是一样的,对吧?您能否添加您具体指的是哪个javascript xpath?对于 php,很明显,只有一个。但是等等,不止一个,但你已经写过你指的是标准的 DOMDocument 扩展,对吧。
【参考方案1】:
刚刚看到 Salathe 实际上回答了同样的问题,但考虑到您的评论并更加强调这一点:
您不需要指定任何 DTD。只要您使用DOMDocument::loadhtml
或DOMDocument::loadHTMLFile
函数,HTML id
属性实际上是为xpath id()
函数注册的。使用http://jsbin.com/elatum/2/edit 中给出的演示 HTML,您甚至会在加载文档时遇到错误:
警告:DOMDocument::loadHTMLFile(): ID priceInfo 已在...中定义
这已经表明这是一个真正的 ID 属性,因为它抱怨重复。相关示例代码如下所示:
$xpath = 'id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]';
$doc = new DOMDocument();
$doc->loadHTMLFile(__DIR__ . '/../data/file-11796340.html');
$xp = new DOMXPath($doc);
$r = $xp->query($xpath);
echo $xpath, "\n";
echo $r ? $r->length : 0, ' elements found', "\n";
if (!$r) return;
foreach($r as $node)
echo " - ", $node->nodeValue, "\n";
输出是:
id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]
1 elements found
- hello
如果您需要更多控制,请先运行 xpath 以将所有 HTML id
属性标记为 xpath 的 ID:
$r = $xp->query("//*[@id]");
if ($r) foreach($r as $node)
$node->setIdAttribute('id', true);
然后您可以使用与 id()
函数相同的 xpath,无需更改它。
【讨论】:
【参考方案2】:您不能在表达式的开头将id("...")
翻译成//*[@id="..."][1]
吗?
例如,如果可以假设您在 id(...)
表达式中没有任何括号:
$queryRewritten = preg_replace('/^id\(([^\)]+)\)/','//*[@id=$1][1]',$query);
Sample code
编辑:更正了替换,id() 必须是表达式中的第一个
【讨论】:
它有帮助,但我很好奇未来还会出现什么其他未记录的东西。 这并不是真正的无证资料,XPATH 规范对这种行为非常清楚。未记录的部分是关于浏览器 DOM 引擎隐式地将 Doctype 应用于 HTML DOM。 @Pentium10 也许您需要更明确地说明您要实现的目标 正如我更新问题的最后一行所说,我想找到一个独立于 DTD 的解决方案。 除了使用不同命名空间前缀的文档外,这可能会欺骗 wpath 引擎。或为属性指定默认隐含值的 DTD(HTML 绝不应如此)。你应该是安全的【参考方案3】:这不是一个完整的答案,但它太大而无法作为评论发表,它可能会对您有所帮助。
如果您可以控制输入 XML,那么您可以通过在 id
属性前加上 xml:
前缀,在 XML 文档本身中显式声明它们,而不是使用 DTD 来声明 id
属性。
例如,如果你有 XML
<foo id="x27"/>
改成
<foo xml:id="x27"/>
那么 id() 函数会将该属性识别为正式的 XML id
类型,而不仅仅是名称为 id
的属性。
我知道这个“技巧”在 Saxon 处理器上有效,但我必须承认我没有在 PHP 上尝试过。
W3C xml:id
【讨论】:
PHP 的DOMElement::setIdAttribute
允许指定xml:id
属性的名称,而不管输入如何(并且无需更改它)。一个例子是my answer以上是关于在有效的 PHP query() XPath 中转换 Javascript XPath |规范化 JS XPath --> PHP的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PHP 的 mysqli_query() 中转义双引号字符?