我正在尝试了解位置/偏移如何在HTMLDocument
中发挥作用。描述位置/偏移语义here。我的解释是,这些是由HTMLDocument
表示的屏幕字符序列中的索引。
考虑来自the HTMLDocument
documentation的示例HTML:
<html>
<head>
<title>An example HTMLDocument</title>
<style type="text/css">
div { background-color: silver; }
ul { color: red; }
</style>
</head>
<body>
<div id="BOX">
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
</body>
</html>
当我在浏览器中打开此HTML时,我只看到“第1段”和“第2段”(并且没有前导空格或换行符)。所以我认为“第1段”从偏移0
开始。
但请考虑以下代码,其中我打印示例HTML中的文本和正文的偏移量:
import java.io.StringReader;
import javax.swing.text.Element;
import javax.swing.text.html.*;
public class Test {
public static void main(String[] args) throws Exception {
String html = " <html>\n"
+ " <head>\n"
+ " <title>An example HTMLDocument</title>\n"
+ " <style type=\"text/css\">\n"
+ " div { background-color: silver; }\n"
+ " ul { color: red; }\n"
+ " </style>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div id=\"BOX\">\n"
+ " <p>Paragraph 1</p>\n"
+ " <p>Paragraph 2</p>\n"
+ " </div>\n"
+ " </body>\n"
+ " </html>\n";
HTMLEditorKit htmlKit = new HTMLEditorKit();
HTMLDocument doc = (HTMLDocument) htmlKit.createDefaultDocument();
htmlKit.read(new StringReader(html), doc, 0);
System.out.println("doc length: " + doc.getLength());
String text = doc.getText(0, doc.getLength());
System.out.println("doc text, surrounded by quotes, with newlines replaced with /: \""
+ text.replace('\n', '/') + "\"");
Element element = doc.getDefaultRootElement().getElement(1);
System.out.println("element name: " + element.getName());
int offset = element.getStartOffset();
System.out.println("offset of body: " + offset);
}
}
输出:
doc length: 26
doc text, surrounded by quotes, with newlines replaced with /: " /Paragraph 1/Paragraph 2"
element name: body
offset of body: 3
基本问题:为什么索引3
的“第1段”(正文的开头)?文本的前三个字符(两个空格和一个换行符)来自哪里?我是否误解了“抵消”意味着什么?
挑战问题:鉴于一些HTML(简单到足以通过检查完全理解),我如何能够手动严格计算出所有DOM元素的偏移?
更多信息:
如果我从HTML中删除style
标记,我会得到相同的结果(3
的正文偏移量)。如果我也删除了title
,我的身体偏移量为1
。如果我最终完全删除head
,我会得到0
的正文偏移(正如预期的那样)。显然style
贡献0,title
贡献2,head
贡献1身体的偏移量?这背后的原因是什么?
这似乎也不受HTML字符串中空格的影响。
答案 0 :(得分:6)
好问题。您可以根据一些规则计算偏移量(以及JEditorPane
中所需的插入位置) - 您已经提到过最重要的规则。
也许一些关键标签是:
<head>
+1 <title>
+2 <meta>
+1 <p>
文字长度+1(对于CR)如果您还没有找到,那么查看偏移列表以及它们如何分解的最简单方法是HTMLDocument.dump(System.out);
。例如。对于上面的示例HTML:
<html
name=html
>
<head
name=head
>
<p-implied
name=p-implied
>
<title
name=title
>
[0,1][ ]
<title
endtag=true
name=title
>
[1,2][ ]
<content
CR=true
name=content
>
[2,3][
]
<body
name=body
>
<div
id=BOX
name=div
>
<p
name=p
>
<content
name=content
>
[3,14][Paragraph 1]
<content
CR=true
name=content
>
[14,15][
]
<p
name=p
>
<content
name=content
>
[15,26][Paragraph 2]
<content
CR=true
name=content
>
[26,27][
]
<bidi root>
<bidi level
bidiLevel=0
>
[0,27][
Paragraph 1
Paragraph 2
]
如果您有兴趣深入挖掘,那么将意味着探索HTML的Swing解析逻辑中的规则。针对不同标记类型有很多规则 - 您可以在source中看到列表。
每个代码都使用&#39; Action&#39;此层次结构中的类:
例如<p>
是ParagraphAction
,<head>
是HeadAction
,这两种类型都是BlockAction
。 <div>
也直接是BlockAction
。
BlockAction
可以添加额外的<content CR...>
元素,以完成阻止,因此偏移上额外+1。通常只有在标签中有直接文本内容时才会这样做。但是对于<head>
,HeadAction
子类会添加您在上面的转储中看到的<p-implied>
,这会导致其中一个额外的偏移。 (在此示例中您无法看到它,但值得注意的是带有文本内容的<div>
还会插入额外的<p-implied>
- 来保存块文本。)
事情从那里变得更加具体。例如。 <title>
(以及<applet>
和<object>
)似乎是非空的&#39; HiddenActions
。这意味着为开始和结束标记插入了一个元素。例如,<meta>
是一个空HiddenAction
,因此只需获取一个元素作为开始标记。
希望对于如何计算任何给定标签的偏移量有足够的解释。如果浏览XxxActions
类的源代码,请查找new ElementSpec(..., 0, 1)
之类的行 - 最后一个参数是长度。
您还提到了被忽略的空格。这在HTML解析中至少是正常的,在浏览器中也是如此。标签之间或文本之前和之后的空格通常被忽略 - 只保留单词之间的空白。然后,将空白序列折叠为单个空格。
尽管如此,我仍然不清楚为什么<head>
和<title>
需要额外的补偿。例如。如果您根据上面的setCaretPosition(x)
和JEditorPane
对doc
使用htmlKit
,则只有x
为3或更高才会看到插入符号。也许其他人可以对此有所了解......