Chuẩn hóa trong phân tích cú pháp DOM với java - nó hoạt động như thế nào?


240

Tôi đã thấy dòng dưới đây trong mã cho trình phân tích cú pháp DOM tại hướng dẫn này .

doc.getDocumentElement().normalize();

Tại sao chúng ta làm điều này bình thường hóa?
Tôi đọc tài liệu nhưng tôi không thể hiểu một từ.

Đặt tất cả các nút Văn bản ở độ sâu đầy đủ của cây con bên dưới Nút này

Được rồi, sau đó ai đó có thể chỉ cho tôi (tốt nhất là với một hình ảnh) cây này trông như thế nào?

Bất cứ ai có thể giải thích cho tôi tại sao bình thường hóa là cần thiết?
Điều gì xảy ra nếu chúng ta không bình thường hóa?


Bất kể câu hỏi của bạn là gì, vui lòng đọc ghi chú trong ví dụ: "DOM Parser chậm và sẽ tiêu tốn rất nhiều bộ nhớ khi tải tài liệu XML chứa nhiều dữ liệu. Vui lòng xem xét trình phân tích SAX làm giải pháp cho nó, SAX nhanh hơn hơn DOM và sử dụng ít bộ nhớ hơn. " .
wulfgarpro

3
@ wulfgar.pro - Tôi hiểu những gì bạn nói. Nhưng, tôi muốn hiểu những thứ tôi đã hỏi trong câu hỏi. Tôi cũng sẽ làm phân tích SAX sớm.
Máy xay táo

Tìm kiếm trên google cho "bình thường hóa xml" đã cho một số kết quả có vẻ hữu ích. Nó trông giống như nó bình thường hóa trong cơ sở dữ liệu.
Máy xay táo

2
@EJP - umm ... vẫn chưa rõ vì tôi không biết sâu về xml và tôi chỉ đọc một vài trang giới thiệu về nó. BTW, đừng hiểu sai ý tôi, bạn đã làm chính xác những gì tác giả của tài liệu đã làm - sử dụng các từ phức tạp thay vì tiếng Anh đơn giản (đơn giản như một nhân viên pike = dễ hiểu). Từ đơn giản đầu tiên và biệt ngữ sau hoạt động tốt hơn đối với tôi.
Máy xay táo

7
Khi viết bài này, trang web được tham chiếu đang tham khảo bài viết SO này. Bộ não của tôi chỉ ném một lỗi phụ thuộc.
cờ vua

Câu trả lời:


366

Phần còn lại của câu là:

trong đó chỉ có cấu trúc (ví dụ: phần tử, nhận xét, hướng dẫn xử lý, phần CDATA và tham chiếu thực thể) phân tách các nút Văn bản, nghĩa là không có nút Văn bản liền kề cũng không có nút Văn bản trống.

Điều này về cơ bản có nghĩa là phần tử XML sau

<foo>hello 
wor
ld</foo>

có thể được biểu diễn như thế này trong một nút không chuẩn hóa:

Element foo
    Text node: ""
    Text node: "Hello "
    Text node: "wor"
    Text node: "ld"

Khi được chuẩn hóa, nút sẽ trông như thế này

Element foo
    Text node: "Hello world"

Và tương tự với các thuộc tính : <foo bar="Hello world"/>, bình luận, v.v.


2
Aha! bây giờ nó rõ ràng hơn nhiều. Tôi không biết về cấu trúc dữ liệu (???) và các nút. Nhưng tôi đã có một cái nhìn nhanh về cấu trúc cây và, tôi đoán rằng một máy tính có thể lưu trữ "thế giới xin chào" theo cách bạn đề xuất. Có đúng không ?
Máy xay táo

9
Bạn cần học những điều cơ bản về DOM. Có, DOM biểu thị một tài liệu XML dưới dạng cây. Và trong một cây, bạn có một nút gốc có nút con, mỗi nút con cũng có các nút con, v.v ... Đó là một cây. Phần tử là một loại nút và TextNode là một loại nút khác.
JB Nizet

7
Cảm ơn JB Nizet. Không thể cho bạn biết tôi cảm thấy nhẹ nhõm như thế nào sau khi nhận được một số hướng.
Máy xay táo

2
@ user2043553, các dòng mới thực sự là điểm ở đó. Nếu không có dòng mới, bạn sẽ không thấy sự khác biệt. Nếu bạn không nên hiểu: Chuẩn hóa "sửa" XML để một thẻ được hiểu là một thành phần. Nếu bạn không làm điều đó, có thể xảy ra rằng những dòng rất mới này được hiểu là các dấu phân cách giữa một số thành phần cùng loại (tương ứng trong cùng một thẻ).
Stacky

1
@Stacky, trong ví dụ có hai dòng mới, chúng không được hiển thị sau khi bình thường hóa trong ví dụ có thể khiến mọi người tin rằng không còn ở đó nữa. Nút văn bản kết quả có dòng mới được hiển thị sẽ trông giống như: "Xin chào \ nwor \ nld" Chuẩn hóa không xóa dòng mới.
Christian

10

Nói một cách đơn giản, Chuẩn hóa là Giảm các khoản thừa.
Ví dụ về các khoản thừa:
a) khoảng trắng bên ngoài thẻ gốc / thẻ tài liệu ( ... <document> </ document> ... )
b) khoảng trắng trong thẻ bắt đầu (< ... >) và thẻ kết thúc (</> ... >)
c) khoảng trắng giữa các thuộc tính và giá trị của chúng (ví dụ: khoảng trắng giữa tên khóa= " )
d) khai báo không gian tên không cần thiết
e) ngắt dòng / khoảng trắng trong văn bản thuộc tính và thẻ
f) bình luận, v.v.


7

Là một phần mở rộng cho câu trả lời của @ JBNizet cho những người dùng kỹ thuật nhiều hơn ở đây, việc triển khai org.w3c.dom.Nodegiao diện com.sun.org.apache.xerces.internal.dom.ParentNodetrông như thế nào, cho bạn ý tưởng về cách nó thực sự hoạt động.

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);
}

Nó đi qua tất cả các nút theo cách đệ quy và gọi kid.normalize()
Cơ chế này được ghi đè trongorg.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);
 } 

Hy vọng điều này sẽ giúp bạn tiết kiệm thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.