HTML文档中的位置或偏移量的含义文档文本

2022-09-04 22:38:32

我试图了解位置/偏移量在 中是如何工作的。此处描述了位置/偏移语义。我的解释是,这些是由.HTMLDocumentHTMLDocument

请考虑 HTMLDocument 文档中的示例 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

基本问题:为什么“第1段”(正文的开头)在索引处?文本的前三个字符(两个空格和一个换行符)来自哪里?我是否误解了“偏移”的含义?3

挑战问题:给定一些HTML(简单到可以通过检查完全理解),我如何手动严格计算出所有DOM元素的偏移量?


更多信息:

如果我从 HTML 中删除标记,我会得到相同的结果(正文偏移量 )。如果我也去掉 ,我得到一个身体偏移。如果我最终完全移除,我会得到一个身体偏移(如预期)。所以显然贡献0,贡献2,并贡献1的身体偏移?这背后的原因是什么?style3title1head0styletitlehead

这似乎也不受 HTML 字符串中空格的影响。


答案 1

问得好。您可以根据一些规则找出偏移量(以及因此在a中必要的脱字符号位置) - 您已经提到了最重要的偏移量。JEditorPane

也许有几个关键标签是:

  • <head>+1
  • <title>+2
  • <meta>+1
  • <p>文本长度 +1(对于 CR)

如果您还没有找到它,那么查看该偏移量列表以及它们如何分解的最简单方法是 。例如,对于上面的示例 HTML:HTMLDocument.dump(System.out);

<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解析逻辑中的规则。对于不同的标签类型有很多规则 - 您可以在中看到列表。

每个标记都在此层次结构中使用一个“操作”类:

swing-html-actions

例如 是 ,并且是 一个 ,这两个类型都是 。A 也直接是 .<p>ParagraphAction<head>HeadActionBlockAction<div>BlockAction

A 可以添加该额外元素以完成块,因此偏移量上的额外 +1。通常,仅当标记中有直接文本内容时,它才会这样做。但是,子类添加了您可以在上面的转储中看到的,这会导致一个额外的偏移。(您在此示例中看不到它,但值得注意的是,带有文本内容也插入了额外的 - 以保持块文本)。BlockAction<content CR...><head>HeadAction<p-implied><div><p-implied>

事情从那里变得越来越具体。例如: (以及 和 ) 似乎是“非空的”。这意味着为开始标记和结束标记插入元素。 虽然,例如,是一个空的,所以只为开始标记获取一个元素。<title><applet><object>HiddenActions<meta>HiddenAction

希望这足以解释如何计算出任何给定标签的偏移量。如果浏览类的源代码,请查找类似 - 最后一个参数是长度的行。XxxActionsnew ElementSpec(..., 0, 1)

您还提到空格被忽略。这至少在HTML解析中是正常的,在浏览器中也是如此。标签之间或文本之前和之后的空格通常被忽略 - 仅保留单词之间的空格。然后,空白序列被折叠成单个空格。


总而言之,我仍然不清楚为什么和需要额外的偏移量。例如,如果您使用基于及以上的 a,则只能看到 3 或更多时的插入符号。也许其他人可以对此有所了解...<head><title>setCaretPosition(x)JEditorPanedochtmlKitx


答案 2