哪个HTML解析器(最好是PHP)支持获取当前节点在输入字符串中的偏移量?

4
我正在寻找一个HTML或XML解析器,可以让用户访问输入字符串或文件中当前元素的偏移/位置
例如,如果遍历以下字符串:
<div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
    <p>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>

我正在寻找一种方法来获取每个<p>标签的起始位置(包括空格),这里是:772
如果PHP解析器本地支持此功能将会很好(我已经查看了DOMXMLReader和其他在this SO question中提到的库,但没有找到方法),否则任何语言/框架都可以。
注意:与this question相关,但不那么局限。

@Gordon,我担心的是DOMNode::getLineNo似乎非常不可靠。如果像该页面所断言的那样是底层libxml2的错误,我可能需要找到一个非基于libxml2的解决方案。另一件事是我需要当前行的偏移量,而不仅仅是行号。 - julien_c
我很好奇你为什么需要那个。解析器的作用是将序列化的XML解析成某种数据结构,然后您可以修改它并将其重新序列化为XML。在原始XML字符串中节点所在的位置似乎无关紧要。至少我没有看到使用情况。 - Gordon
我正在构建一个EPUB阅读系统,其中“句子”(有时跨越多个XML节点)被突出显示,并且它们的位置被存储为HTML文件中起始和结束字符的偏移量。 - julien_c
'7' 是除以 5 再加换行符(1?)和制表符(1?)的结果吗? - Chris
@Chris 是的,我猜你是指(字符数)。 - julien_c
显示剩余3条评论
2个回答

6
也许你可以使用通用XML解析器类(也在github上)。
根据作者的描述:
  • 解析任意XML输入并构建带有所有标记和数据元素结构的数组。
  • 它可以验证和提取整个XML文档中的数据,只需一个函数调用即可。它支持验证常见的标记值数据类型,并可以使用子类执行自定义验证。
  • 可选地,跟踪每个元素的位置,以允许确定可能在上下文中出错的元素的确切位置。
  • 支持解析文件缓存以最小化重复解析相同文件的开销。
  • 优化了简化XML(SML)格式的解析,忽略标记属性。
  • 使用单个函数调用验证和提取整个XML文档中的数据。
我已经使用以下代码进行测试:
<?php

require('xml_parser.php');

$file_name = 'test.xml';
$error = XMLParseFile($parser, $file_name, 1, $file_name.'.cache');

foreach ($parser->structure as $key => $val) {
    if (is_array($val) && isset($val['Tag']) && !strcasecmp($val['Tag'], 'p')) {
        print_r($parser->positions[$key]);
    }
}

?>

test.xml 文件包含了你的示例 HTML 代码片段。
通过从命令行运行脚本,我得到了以下输出:

Array
(
    [Line] => 2
    [Column] => 7
    [Byte] => 12
)
Array
(
    [Line] => 3
    [Column] => 7
    [Byte] => 80
)

因此,Byte字段可能是您要查找的内容。
为了更好地理解其工作原理,请同时查看源代码

谢谢你的回答。我有点担心这个库似乎有点晦涩,我会继续寻找。 - julien_c
你知道这个库是否仍在维护吗?还有其他建议,比如语言等吗? - julien_c
@julien_c 最后一次文档更改日期是2012年9月5日,因此我认为该库仍在维护。该库使用PHP Expat解析器函数。例如,请查看xml_get_current_byte_index函数。 - user1419445

0

如果您不介意使用Java编码(在Java代码之后有PHP解决方案),您可以使用String类中的indexOf方法,获取此标记的偏移量。

以下是一个示例:

class Index {
    public static void main ( String [] args )
    {   
        String token = "<p>";
        String input = "<p> hola </p> <p> adios </a>";
        int beginIdx = -1; 
        while ( (beginIdx = input.indexOf( token, beginIdx + 1 )) != -1 ) {                                                                                                                                         
            System.out.println( "Token at: " + beginIdx );
        }   
    }   
}

输出结果如下:

Token at: 0
Token at: 14

在PHP中有一个类似的函数:

int strrpos ( string $haystack , string $needle [, int $offset = 0 ] )

您可以快速查看有关它的“man”页面(其中包含一些示例):http://php.net/manual/es/function.strrpos.php


1
不是 OP 寻找的。这不使用 XML/HTML 解析器,对于任何未按照 <p> 完全编写的 P 元素(例如具有属性或大写字母),都会失败。 - Gordon
然后使用正则表达式而不是固定字符串。 - arutaku
我怀疑他会找到一个关心输入字符串位置的解析器,因为意图解析器的整个目的就是消除这些问题。 - Rimu Atkinson
使用stripos代替strrpos,因为stripos是不区分大小写的,并且只搜索"<p"而不是"<p>"。 - Rimu Atkinson
@RimuAtkinson 我不只是在寻找 <p> 标签(所有类型的标签) - julien_c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接