Нормализация в DOM-анализе с помощью java - как это работает?
Я видел строку ниже в коде для DOM-парсера в этом учебнике.
doc.getDocumentElement().normalize();
Почему мы делаем эту нормализацию?
Я прочитал docs, но я не мог понять ни слова.
Помещает все текстовые узлы на всю глубину поддерева под этим Node
Хорошо, тогда кто-нибудь может показать мне (желательно с изображением), как выглядит это дерево?
Может ли кто-нибудь объяснить мне, зачем нужна нормализация?
Что произойдет, если мы не нормализуемся?
Ответы
Ответ 1
Остальная часть предложения:
где только структура (например, элементы, комментарии, инструкции по обработке, разделы CDATA и ссылки на сущности) отделяет текстовые узлы, то есть нет ни смежных текстовых узлов, ни пустых текстовых узлов.
В основном это означает, что следующий элемент XML
<foo>hello
wor
ld</foo>
может быть представлен таким образом в денормализованном node:
Element foo
Text node: ""
Text node: "Hello "
Text node: "wor"
Text node: "ld"
При нормализации, node будет выглядеть следующим образом:
Element foo
Text node: "Hello world"
И то же самое касается атрибутов: <foo bar="Hello world"/>
, комментарии и т.д.
Ответ 2
В простой, нормализация - сокращение избыточности.
Примеры избыточности:
a) пробелы вне тегов root/document (... <document> </document> )
b) белые пробелы в начале тега (<... > ) и конечный тег (</... > )
c) пробелы между атрибутами и их значениями (т.е. пробелы между ключевым именем и = ")
d) объявления избыточного пространства имен
e) разрывы строк/пробелы в текстах атрибутов и тегов
f) комментарии и т.д.
Ответ 3
В качестве расширения для ответа @JBNizet для более технических пользователей, как выглядит реализация интерфейса org.w3c.dom.Node
в com.sun.org.apache.xerces.internal.dom.ParentNode
, дает вам представление о том, как это работает на самом деле.
public void normalize() {
// No need to normalize if already normalized.
if (isNormalized()) {
return;
}
if (needsSyncChildren()) {
synchronizeChildren();
}
ChildNode kid;
for (kid = firstChild; kid != null; kid = kid.nextSibling) {
kid.normalize();
}
isNormalized(true);
}
Он пересекает все узлы рекурсивно и вызывает kid.normalize()
Этот механизм переопределяется в org.apache.xerces.dom.ElementImpl
public void normalize() {
// No need to normalize if already normalized.
if (isNormalized()) {
return;
}
if (needsSyncChildren()) {
synchronizeChildren();
}
ChildNode kid, next;
for (kid = firstChild; kid != null; kid = next) {
next = kid.nextSibling;
// If kid is a text node, we need to check for one of two
// conditions:
// 1) There is an adjacent text node
// 2) There is no adjacent text node, but kid is
// an empty text node.
if ( kid.getNodeType() == Node.TEXT_NODE )
{
// If an adjacent text node, merge it with kid
if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
{
((Text)kid).appendData(next.getNodeValue());
removeChild( next );
next = kid; // Don't advance; there might be another.
}
else
{
// If kid is empty, remove it
if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) {
removeChild( kid );
}
}
}
// Otherwise it might be an Element, which is handled recursively
else if (kid.getNodeType() == Node.ELEMENT_NODE) {
kid.normalize();
}
}
// We must also normalize all of the attributes
if ( attributes!=null )
{
for( int i=0; i<attributes.getLength(); ++i )
{
Node attr = attributes.item(i);
attr.normalize();
}
}
// changed() will have occurred when the removeChild() was done,
// so does not have to be reissued.
isNormalized(true);
}
Надеюсь, это сэкономит вам некоторое время.