HTMLDocument文本中

时间:2018-05-30 10:14:45

标签: java html swing

我正在尝试了解位置/偏移如何在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字符串中空格的影响。

1 个答案:

答案 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;此层次结构中的类:

swing-html-actions

例如<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)JEditorPanedoc使用htmlKit,则只有x为3或更高才会看到插入符号。也许其他人可以对此有所了解......