Kỹ thuật phân tích cú pháp XML


11

Tôi luôn thấy XML hơi cồng kềnh khi xử lý. Tôi không nói về việc triển khai trình phân tích cú pháp XML: Tôi đang nói về việc sử dụng trình phân tích cú pháp dựa trên luồng hiện có, như trình phân tích cú pháp SAX, xử lý nút XML theo nút.

Đúng, thật dễ dàng để tìm hiểu các API khác nhau cho các trình phân tích cú pháp này, nhưng bất cứ khi nào tôi nhìn vào mã xử lý XML, tôi luôn thấy nó có phần khó hiểu. Vấn đề cốt yếu dường như là một tài liệu XML được phân tách hợp lý thành các nút riêng lẻ và các loại dữ liệu và thuộc tính thường được tách ra khỏi dữ liệu thực tế, đôi khi bởi nhiều cấp độ lồng nhau. Do đó, khi xử lý bất kỳ nút cụ thể nào, rất nhiều trạng thái bổ sung cần được duy trì để xác định chúng ta đang ở đâuchúng ta cần làm gì tiếp theo.

Ví dụ: được cung cấp một đoạn trích từ một tài liệu XML điển hình:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... Làm cách nào để xác định khi tôi gặp một nút văn bản có chứa tiêu đề sách? Giả sử chúng ta có một trình phân tích cú pháp XML đơn giản hoạt động như một trình vòng lặp, cung cấp cho chúng ta nút tiếp theo trong tài liệu XML mỗi khi chúng ta gọi XMLParser.getNextNode(). Tôi chắc chắn thấy mình viết mã như sau:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

Về cơ bản, quá trình xử lý XML nhanh chóng biến thành một vòng lặp lớn do máy trạng thái điều khiển, với rất nhiều biến trạng thái được sử dụng để chỉ ra các nút cha mà chúng ta đã tìm thấy trước đó. Mặt khác, một đối tượng ngăn xếp cần được duy trì để theo dõi tất cả các thẻ lồng nhau. Điều này nhanh chóng trở nên dễ bị lỗi và khó bảo trì.

Một lần nữa, vấn đề dường như là dữ liệu chúng ta quan tâm không liên quan trực tiếp đến một nút riêng lẻ. Chắc chắn, nó có thể, nếu chúng ta viết XML như:

<book title="Blah blah" author="blah blah" price="15 USD" />

... nhưng đây hiếm khi là cách sử dụng XML trong thực tế. Hầu hết chúng ta có các nút văn bản là con của các nút cha và chúng ta cần theo dõi các nút cha để xác định xem nút văn bản đề cập đến điều gì.

Vậy ... tôi có làm gì sai không? Có cách nào tốt hơn? Tại thời điểm nào, việc sử dụng trình phân tích cú pháp dựa trên luồng XML trở nên quá cồng kềnh, do đó trình phân tích cú pháp DOM đầy đủ trở nên cần thiết? Tôi muốn nghe từ các lập trình viên khác loại thành ngữ nào họ sử dụng khi xử lý XML bằng các trình phân tích cú pháp dựa trên luồng. Phải phân tích cú pháp XML dựa trên luồng luôn biến thành một máy trạng thái khổng lồ?


2
nếu bạn sử dụng ngôn ngữ .net, bạn nên xem linq đến xml aka XLinq.
Muad'Dib

Cảm ơn bạn, tôi nghĩ rằng tôi là người duy nhất có vấn đề này. Thành thật mà nói, tôi thường thấy toàn bộ định dạng XML gây trở ngại nhiều hơn là giúp đỡ. Có, nó cho phép một người lưu trữ nhiều dữ liệu có cấu trúc trong một tệp văn bản nhỏ. Nhưng nếu sau đó bạn cần hơn 20 lớp để giải nén và hiểu ý nghĩa của nó - không có gì đảm bảo rằng bạn không xem xét một cái gì đó quan trọng hơn hoặc ít hơn. Nó giống như chú thỏ trong Chén Thánh của Monty Python.
Elise van Looij

Câu trả lời:


9

Đối với tôi, câu hỏi là cách khác. Tại thời điểm nào thì Tài liệu XML trở nên cồng kềnh đến mức bạn phải bắt đầu sử dụng SAX thay vì DOM?

Tôi sẽ chỉ sử dụng SAX cho một luồng dữ liệu rất lớn, không xác định; hoặc nếu hành vi mà XML dự định gọi là thực sự hướng đến sự kiện và do đó giống như SAX.

Ví dụ bạn đưa ra trông rất giống DOM đối với tôi.

  1. Tải XML
  2. Trích xuất (các) nút tiêu đề và "làm điều gì đó với chúng".

EDIT: Tôi cũng sẽ sử dụng SAX cho các luồng có thể không đúng định dạng, nhưng nơi tôi muốn đưa ra dự đoán tốt nhất về việc lấy dữ liệu ra.


2
Tôi nghĩ rằng đây là một điểm tốt. Nếu bạn đang phân tích cú pháp các tài liệu quá lớn đối với DOM thì bạn cần xem xét liệu bạn có phân tích cú pháp các tài liệu quá lớn đối với XML hay không
Dean Harding

1
+1: Đưa ra tùy chọn, tôi sẽ luôn đi với DOM. Thật không may, có vẻ như các yêu cầu thiết kế của chúng tôi luôn bao gồm "khả năng xử lý bất kỳ kích thước tài liệu nào" và "phải có hiệu suất", điều này loại trừ khá nhiều giải pháp dựa trên DOM.
TMN

3
@TMN, trong một thế giới lý tưởng, các yêu cầu sẽ loại trừ XML ngay từ đầu.
SK-logic

1
@TMN, nghe có vẻ như là một trong những yêu cầu ảo đó: "Tất nhiên tất cả các tài liệu của chúng tôi chỉ khoảng 100KB, và lớn nhất chúng tôi thấy là 1MB, nhưng bạn không bao giờ biết tương lai sẽ giữ gì, vì vậy chúng tôi nên giữ các tùy chọn của mình mở và xây dựng cho các tài liệu vô cùng lớn "
Paul Butcher

@Paul Đồ tể, bạn không bao giờ biết. Ý tôi là, một đống Wikipedia giống như 30 GB XML.
Kênh72

7

Tôi không làm việc với XML quá nhiều, theo ý kiến ​​của tôi, có lẽ một trong những cách tốt nhất để phân tích cú pháp XML bằng thư viện là sử dụng XPath.

Thay vì đi ngang qua cây để tìm một số nút cụ thể, bạn đưa ra một đường dẫn đến nó. Trong trường hợp ví dụ của bạn (bằng mã giả), nó sẽ giống như:

Books = Parent.xpath ("/ book") // Điều này sẽ cung cấp cho bạn tất cả các nút sách
cho mỗi cuốn sách trong sách
    title = book.xpath ("/ title / text ()")
    tác giả = book.xpath ("/ tác giả / văn bản ()")
    price = book.xpath ("/ price / text ()")

    // Làm mọi thứ với dữ liệu

XPath mạnh hơn thế nhiều, bạn có thể tìm kiếm bằng các điều kiện (cả về giá trị và thuộc tính), chọn một nút cụ thể trong danh sách, di chuyển các cấp qua cây. Tôi khuyên bạn nên tìm kiếm thông tin về cách sử dụng nó, nó được triển khai trong rất nhiều thư viện phân tích cú pháp (tôi sử dụng phiên bản .Net Framework và lxml cho Python)


Điều đó tốt nếu bạn có thể biết và tin tưởng trước cách thức cấu trúc xml. Nếu bạn không biết liệu chiều rộng của một phần tử sẽ được chỉ định là thuộc tính của nút hoặc là nút thuộc tính bên trong nút kích thước của phần tử, thì XPath sẽ không giúp ích nhiều.
Elise van Looij

5

Phải phân tích cú pháp XML dựa trên luồng luôn biến thành một máy trạng thái khổng lồ?

Thông thường nó có, có.

Đối với tôi, việc chỉ ra sử dụng trình phân tích cú pháp DOM đầy đủ là khi tôi cần bắt chước các phần của hệ thống phân cấp tệp trong bộ nhớ, ví dụ để có thể giải quyết các tham chiếu chéo trong tài liệu.


+1: Bắt đầu với DOM. Tránh SAX.
S.Lott

hoặc với vtd-xml
vtd-xml-tác giả

4

Phân tích cú pháp nói chung chỉ đơn giản là điều khiển một máy trạng thái và phân tích cú pháp XML không khác nhau. Phân tích cú pháp dựa trên luồng luôn là một rắc rối, tôi luôn luôn xây dựng một nhóm sắp xếp để theo dõi các nút tổ tiên và xác định rất nhiều sự kiện và một loại trình điều khiển sự kiện kiểm tra thẻ hoặc sổ đăng ký đường dẫn và kích hoạt một sự kiện nếu một trận đấu Mã lõi khá chặt chẽ, nhưng tôi kết thúc với một bộ xử lý sự kiện khổng lồ , chủ yếu bao gồm việc gán giá trị của nút văn bản sau cho một trường trong cấu trúc ở đâu đó. Nó có thể có được nhiều lông nếu bạn cũng cần kết hợp logic kinh doanh trong đó.

Tôi sẽ luôn sử dụng DOM trừ khi các vấn đề về kích thước hoặc hiệu suất được quy định khác.


1

Không hoàn toàn không biết ngôn ngữ, nhưng tôi thường giải thích XML thành các đối tượng hơn là nghĩ về phân tích cú pháp. Chỉ có thời gian để lo lắng về các chiến lược phân tích cú pháp mỗi lần là nếu bạn có vấn đề về tốc độ.


Điều đó rơi vào phân tích cú pháp. Trừ khi XML trong câu hỏi là đầu ra của tuần tự hóa đối tượng và bạn có một thư viện giải nén được xây dựng sẵn. Nhưng sau đó, câu hỏi này không xuất hiện.

Nhiều ngôn ngữ / ngăn xếp đã sẵn sàng xây dựng thư viện khử lưu huỳnh.
Wyatt Barnett

Vâng, vậy thì sao? Quan điểm của tôi vẫn được giữ vững - không phải tất cả các tệp XML trong định dạng đều có định dạng như vậy và nếu bạn có một tệp như vậy, bạn không hỏi câu hỏi này khi bạn chỉ sử dụng thư viện khử lưu huỳnh đó và không tự phân tích bất cứ điều gì , từ các luồng hoặc cách khác.

0

Nó trở nên ít cồng kềnh hơn nếu bạn có thể sử dụng XPath. Và trong .Net Land LINQ to XML trừu tượng rất nhiều thứ ít hấp dẫn hơn. ( Chỉnh sửa - tất nhiên những điều này đòi hỏi một cách tiếp cận DOM)

Về cơ bản, nếu bạn đang thực hiện một cách tiếp cận dựa trên luồng (vì vậy bạn không thể sử dụng các tóm tắt đẹp hơn yêu cầu DOM) Tôi nghĩ rằng nó sẽ luôn khá cồng kềnh và tôi không chắc có cách nào khác không.


Nếu bạn đang sử dụng XPath, bạn đang sử dụng DOM (trừ khi bạn đang sử dụng nó với trình đánh giá XPath tại nhà).
TMN

vâng, do đó, nhận xét của tôi về các khái niệm trừu tượng cần DOM ... nhưng tôi sẽ làm rõ, cảm ơn!
Steve

0

Nếu bạn có thể tìm thấy một trình phân tích cú pháp cung cấp cho bạn một trình vòng lặp, bạn đã nghĩ đến việc coi nó như là một từ vựng và sử dụng một trình tạo máy trạng thái chưa?

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.