2010-11-07 40 views
6

Tôi gặp một số khó khăn khi hiểu phân tích cấu trúc XML bằng SAX. Giả sử có XML sau:SAX: Cách lấy nội dung của một phần tử

<root> 
    <element1>Value1</element1> 
    <element2>Value2</element2> 
</root> 

và biến chuỗi myString.

Chỉ cần thực hiện các phương thức startElement, endElement() và ký tự() rất dễ dàng. Nhưng tôi không hiểu làm thế nào tôi có thể đạt được những điều sau đây:

Nếu phần tử hiện tại bằng element1 lưu giá trị của nó value1 trong myString. Theo như tôi hiểu có gì giống như là:

if (qName.equals("element1")) myString = qName.getValue(); 

Guess Tôi chỉ suy nghĩ quá phức tạp :-)

Robert

Trả lời

6

Với SAX bạn cần duy trì ngăn xếp của riêng mình. Bạn có thể làm điều gì đó như thế này để xử lý rất cơ bản:

void startElement(...) { 
    if (name.equals("element1")) { 
     inElement1 = true; 
     element1Content = new StringBuffer(); 
    } 
} 

void characters(...) { 
    if (inElement1) { 
     element1Content.append(characterData); 
    } 
} 

void endElement(...) { 
    if (name.equals("element2")) { 
     inElement1 = false; 
     processElement1Content(element1Content.toString()); 
    } 
} 

Nếu bạn muốn mã như trong ví dụ của mình thì bạn cần sử dụng mô hình DOM thay vì SAX. DOM dễ mã hóa hơn nhưng thường chậm hơn và tốn nhiều bộ nhớ hơn SAX.

Tôi khuyên bạn nên sử dụng thư viện của bên thứ ba thay vì thư viện Java XML cài sẵn cho thao tác DOM. Dom4J có vẻ khá tốt nhưng cũng có thể có nhiều thư viện khác.

+0

Cảm ơn Cameron, đó là những gì tôi đã mong đợi :-) Khi ứng dụng của tôi chạy trên điện thoại thông minh Android, tôi nghĩ nó tốt hơn khi sử dụng trong trình phân tích cú pháp SAX thay vì chuyển sang DOM. –

+0

Có lẽ sử dụng StringBuilder được ưu tiên –

6

Bạn nên ghi rõ nội dung thông qua characters(), thêm vào sau một StringBuilder cho mỗi lệnh gọi và chỉ lưu trữ giá trị được ghép nối khi cuộc gọi endElement().

Tại sao? Bởi vì characters() có thể được gọi là nhiều lần cho nội dung phần tử - mỗi cuộc gọi tham chiếu một chuỗi liên tiếp của phần tử văn bản đó.

9

Giải pháp này hoạt động cho một phần tử đơn lẻ có nội dung văn bản. Khi element1 có nhiều phần tử con thì cần thêm một số công việc nữa. Nhận xét của Brian là một nhận xét rất quan trọng. Khi bạn có nhiều yếu tố hoặc muốn có một giải pháp chung chung hơn, điều này có thể giúp bạn. Tôi đã thử nghiệm nó với một tập tin xml 300 + MB và nó vẫn còn rất nhanh:

final StringBuilder builder=new StringBuilder(); 
XMLReader saxXmlReader = XMLReaderFactory.createXMLReader(); 

DefaultHandler handler = new DefaultHandler() { 
    boolean isParsing = false; 

    public void startElement(String uri, String localName, String qName, Attributes attributes) { 
     if ("element1".equals(localName)) { 
      isParsing = true; 
     } 
     if (isParsing) { 
      builder.append("<" + qName + ">"); 
     } 
    } 

    @Override 
    public void characters(char[] chars, int i, int i1) throws SAXException { 
     if (isParsing) { 
      builder.append(new String(chars, i, i1)); 
     } 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) throws SAXException { 
     if (isParsing) { 
      builder.append("</" + qName + ">"); 
     } 
     if ("element1".equals(localName)) { 
      isParsing = false; 
     } 
    } 
}; 

saxXmlReader.setContentHandler(handler); 
saxXmlReader.setErrorHandler(handler); 

saxXmlReader.parse(new InputSource(new FileInputStream(input))); 
Các vấn đề liên quan