2 回答
TA贡献1811条经验 获得超4个赞
不是答案,但评论太长了。以下可能在某种程度上起作用:
使用 a
Tokenizer
并一步一步地遍历每个元素。将您的输入包装到自定义读取器中,该读取器在 Tokenizer 读取时记录行和列偏移量。
在调用 Next() 之前和之后查询您的自定义阅读器的位置,以记录您需要的大致位置信息。
这有点痛苦,而且不太准确,但可能是您能做的最好的。
TA贡献1946条经验 获得超3个赞
我想出了一个解决方案,我们扩展(如果有另一种方法,请修复我)原始 HTML 包以及custom.go带有新导出功能的附加文件。此函数能够访问 的未导出data属性Tokenizer,该属性准确保存当前 的开始和结束位置Node。我们必须在每次读取缓冲区后调整位置。见globalBufDif。
我真的不喜欢我只需要 fork 包才能访问几个属性,但似乎这是一种 Go 方式。
func parseWithIndexes(p *parser) (map[*Node][2]int, error) {
// Iterate until EOF. Any other error will cause an early return.
var err error
var globalBufDif int
var prevEndBuf int
var tokenIndex [2]int
tokenMap := make(map[*Node][2]int)
for err != io.EOF {
// CDATA sections are allowed only in foreign content.
n := p.oe.top()
p.tokenizer.AllowCDATA(n != nil && n.Namespace != "")
t := p.top().FirstChild
for {
if t != nil && t.NextSibling != nil {
t = t.NextSibling
} else {
break
}
}
tokenMap[t] = tokenIndex
if prevEndBuf > p.tokenizer.data.end {
globalBufDif += prevEndBuf
}
prevEndBuf = p.tokenizer.data.end
// Read and parse the next token.
p.tokenizer.Next()
tokenIndex = [2]int{p.tokenizer.data.start + globalBufDif, p.tokenizer.data.end + globalBufDif}
p.tok = p.tokenizer.Token()
if p.tok.Type == ErrorToken {
err = p.tokenizer.Err()
if err != nil && err != io.EOF {
return tokenMap, err
}
}
p.parseCurrentToken()
}
return tokenMap, nil
}
// ParseFragmentWithIndexes parses a fragment of HTML and returns the nodes
// that were found. If the fragment is the InnerHTML for an existing element,
// pass that element in context.
func ParseFragmentWithIndexes(r io.Reader, context *Node) ([]*Node, map[*Node][2]int, error) {
contextTag := ""
if context != nil {
if context.Type != ElementNode {
return nil, nil, errors.New("html: ParseFragment of non-element Node")
}
// The next check isn't just context.DataAtom.String() == context.Data because
// it is valid to pass an element whose tag isn't a known atom. For example,
// DataAtom == 0 and Data = "tagfromthefuture" is perfectly consistent.
if context.DataAtom != a.Lookup([]byte(context.Data)) {
return nil, nil, fmt.Errorf("html: inconsistent Node: DataAtom=%q, Data=%q", context.DataAtom, context.Data)
}
contextTag = context.DataAtom.String()
}
p := &parser{
tokenizer: NewTokenizerFragment(r, contextTag),
doc: &Node{
Type: DocumentNode,
},
scripting: true,
fragment: true,
context: context,
}
root := &Node{
Type: ElementNode,
DataAtom: a.Html,
Data: a.Html.String(),
}
p.doc.AppendChild(root)
p.oe = nodeStack{root}
p.resetInsertionMode()
for n := context; n != nil; n = n.Parent {
if n.Type == ElementNode && n.DataAtom == a.Form {
p.form = n
break
}
}
tokenMap, err := parseWithIndexes(p)
if err != nil {
return nil, nil, err
}
parent := p.doc
if context != nil {
parent = root
}
var result []*Node
for c := parent.FirstChild; c != nil; {
next := c.NextSibling
parent.RemoveChild(c)
result = append(result, c)
c = next
}
return result, tokenMap, nil
}
- 2 回答
- 0 关注
- 319 浏览
添加回答
举报