Пытаюсь понять, как работают позиции / смещения в HTMLDocument. Семантика положения / смещения описывается здесь. Я считаю, что это индексы в последовательности экранных символов, представленных HTMLDocument.
Рассмотрим пример HTML из документация HTMLDocument:
<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 из HTML, я получу тот же результат (смещение тела 3). Если я также удалю title, я получу смещение тела 1. Если я наконец полностью удалю head, я получу смещение тела 0 (как и ожидалось). Таким образом, очевидно, что style вносит вклад в 0, title вносит вклад в 2, а head вносит вклад в 1 в смещение тела? Что за этим стоит?
На это также не влияет пробел в строке HTML.




Хороший вопрос. Вы можете вычислить смещения (и, следовательно, необходимые позиции каретки в 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
]
Если вы хотите углубиться в детали, это будет означать изучение правил в логике синтаксического анализа Swing для HTML. Для разных типов тегов существует множество правил - вы можете увидеть список в источник.
Каждый тег использует класс Action в этой иерархии:
Например, <p> - это ParagraphAction, а <head> - это HeadAction, и оба они являются типами BlockAction. <div> также напрямую является BlockAction.
BlockAction может добавить этот дополнительный элемент <content CR...>, чтобы закончить блок, отсюда и дополнительный +1 на смещении. Обычно это происходит только в том случае, если в теге было прямое текстовое содержимое. Однако для <head> подкласс HeadAction добавляет <p-implied>, который вы можете видеть в дампе выше, что вызывает одно из дополнительных смещений. (Вы не можете увидеть это в этом примере, но стоит отметить, что <div> с текстовым содержимым также вставляет этот дополнительный <p-implied> - для хранения текста блока).
С этого момента все становится более конкретным. Например. <title> (вместе с <applet> и <object>) кажется «непустым» HiddenActions. Это означает, что элемент вставлен как для начального, так и для конечного тегов. <meta>, например, является пустым HiddenAction, поэтому для начального тега будет только один элемент.
Надеюсь, этого достаточно для объяснения того, как вычислить смещение для любого заданного тега. При просмотре источника классов XxxActions ищите строки вроде new ElementSpec(..., 0, 1) - последний параметр - длина.
Вы также упомянули, что пробелы игнорируются. По крайней мере, это нормально при разборе HTML, в браузерах тоже. Пробелы между тегами или до и после текста обычно игнорируются - сохраняется только пробел между словами. А затем последовательности пробелов сворачиваются до одного пробела.
Тем не менее, я все еще не понимаю, зачем нужны дополнительные смещения для <head> и <title>. Например. если вы используете setCaretPosition(x) против JEditorPane, основанного на приведенных выше doc и htmlKit, вы увидите курсор, только если x равен 3 или больше. Возможно, кто-нибудь еще сможет пролить свет на это ...