代码之家  ›  专栏  ›  技术社区  ›  k_ssb

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

  •  12
  • k_ssb  · 技术社区  · 6 年前

    我想了解位置/偏移是如何工作的 HTMLDocument . 描述了位置/偏移语义 here . 我的解释是,这些是由 HTMLdocument文件 .

    考虑下面的示例html the HTMLDocument documentation :

     <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元素的偏移量?


    更多信息:

    如果我移除 style 标签,我得到相同的结果(body offset of )如果我也删除 title ,我得到了 1 . 如果我最终移除 head 完全,我得到了 (如预期)。很明显 风格 贡献0, 标题 贡献2,和 对身体的偏移量贡献1?这背后的原因是什么?

    这似乎也不受html字符串中空白的影响。

    1 回复  |  直到 6 年前
        1
  •  6
  •   df778899    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 .

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

    swing-html-actions

    例如 <P & GT; 是一个 ParagraphAction <头部> 是一个 HeadAction ,这两种类型都是 BlockAction . 一 <div> 也是直接的 阻滞作用 .

    可以加上额外的 <content CR...> 元素,以完成块,因此偏移量上额外的+1。它通常只在标签中有直接的文本内容时才这样做。为了 <头部> 不过, 头部动作 子类添加 <p-implied> 您可以在上面的转储中看到,这导致了一个额外的偏移。(在本例中看不到,但值得注意的是 <分区> 在文本内容中还插入 <p-隐含的> -保存块文本)。

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

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

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


    尽管如此,我仍然不清楚为什么需要额外的补偿 <头部> <标题> . 例如,如果您使用 setCaretPosition(x) 反对 吉迪托邦 基于 doc htmlKit 上面,只有在 x 是3个或更多。也许其他人可以解释一下…