2017-01-31 19 views
5

Tôi đang cố tìm cách xác định chính xác số dòng và vị trí ký tự của cả thẻ và thuộc tính trong khi phân tích cú pháp tài liệu XML. Tôi muốn làm điều này để tôi có thể báo cáo chính xác cho tác giả của tài liệu XML (thông qua giao diện web) nơi tài liệu không hợp lệ.XML/Java: Vị trí chính xác và vị trí ký tự trong khi phân tích cú pháp thẻ và thuộc tính?

Cuối cùng, tôi muốn đặt dấu mũ vào thẻ không hợp lệ hoặc chỉ trong dấu ngoặc kép mở của thuộc tính không hợp lệ. (Tôi không sử dụng Lược đồ XML tại thời điểm này vì định dạng chính xác của các thuộc tính quan trọng theo cách không thể được xác thực bởi lược đồ một mình. Tôi thậm chí có thể muốn báo cáo một số thuộc tính như là một phần không hợp lệ thông qua giá trị của thuộc tính. , một phần thông qua văn bản giữa thẻ bắt đầu và thẻ kết thúc.)

Tôi đã thử sử dụng SAX (org.xml.sax) và giao diện Người định vị. Điều này hoạt động đến một điểm nhưng không đủ tốt. Nó sẽ chỉ báo cáo vị trí đã đọc sau một sự kiện; ví dụ: ký tự ngay sau khi thẻ mở kết thúc, cho startElement(). Tôi không thể trừ đi độ dài của tên thẻ vì các thuộc tính, thẻ tự đóng và/hoặc dòng mới trong thẻ mở sẽ loại bỏ điều này. (Và Locator không cung cấp thông tin về vị trí của các thuộc tính.)

Lý tưởng nhất là tôi đang tìm cách sử dụng phương pháp dựa trên sự kiện, vì tôi đã có trình xử lý SAX đang xây dựng một đại diện giống như DOM hoặc tiếp tục xử lý. Tuy nhiên, tôi muốn biết về bất kỳ thư viện DOM hoặc DOM nào bao gồm thông tin vị trí chính xác cho các yếu tố của mô hình.

Có ai đã giải quyết vấn đề này hay bất kỳ vấn đề nào tương tự, với mức độ chính xác được yêu cầu không?

+0

Phương pháp tiếp cận dựa trên sự kiện? Giống như [XMLEventReader] (http://docs.oracle.com/javase/8/docs/api/javax/xml/stream/XMLEventReader.html) và [XMLEvent.getLocation] (http://docs.oracle. com/javase/8/docs/api/javax/xml/luồng/sự kiện/XMLEvent.Phương thức html # getLocation--)? – VGR

+0

Tôi đã thử sử dụng không phải XMLEventReader, nhưng XMLStreamReader. Tuy nhiên các vị trí báo cáo này là vị trí cuối cùng của mỗi sự kiện. Ví dụ: sau START_ELEMENT vị trí được chỉ định ngay sau khi đóng thẻ bắt đầu (chú thích - thẻ bắt đầu, không phải phần tử). Dường như không có cách đáng tin cậy để xác định vị trí bắt đầu của thẻ. Ngoài ra, tôi không bao giờ nhận được bất kỳ sự kiện ATTRIBUTE nào cả vì những sự kiện này được kết hợp thành một sự kiện START_ELEMENT duy nhất: vì vậy tôi không thể nhận được bất kỳ chính xác hơn nữa về vị trí thuộc tính. – Paul

+0

Hãy giải thích ý của bạn khi bạn nói rằng bạn * không sử dụng Lược đồ XML tại thời điểm này vì định dạng chính xác của các thuộc tính quan trọng theo cách không thể được xác thực bởi lược đồ. * – kjhughes

Trả lời

0

Tôi đã viết một tệp xml nhanh có số dòng và ném ngoại lệ trong trường hợp thuộc tính không mong muốn và cung cấp văn bản nơi lỗi được ném.

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.util.Stack; 


import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 

import org.apache.log4j.Logger; 
import org.w3c.dom.Document; 
import org.xml.sax.Attributes; 
import org.xml.sax.Locator; 
import org.xml.sax.SAXException; 
import org.xml.sax.helpers.DefaultHandler; 



public class LocatorTestSAXReader { 
private static final Logger logger =  Logger.getLogger(LocatorTestSAXReader.class); 

    private static final String XML_FILE_PATH = "lib/xml/test-instance1.xml"; 

public Document readXMLFile(){ 

    Document doc = null; 
    SAXParser parser = null; 

    SAXParserFactory saxFactory = SAXParserFactory.newInstance(); 
    try { 
     parser = saxFactory.newSAXParser(); 
     DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 
     doc = docBuilder.newDocument(); 

    } catch (ParserConfigurationException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (SAXException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


    StringBuilder text = new StringBuilder(); 
    DefaultHandler eleHandler = new DefaultHandler(){ 
     private Locator locator; 

     @Override 
     public void characters(char[] ch, int start, int length){ 
      String thisText = new String(ch, start, length); 
      if(thisText.matches(".*[a-zA-z]+.*")){ 
       text.append(thisText); 
       logger.debug("element text: " + thisText); 
      } 

     } 



     @Override 
     public void setDocumentLocator(Locator locator){ 
      this.locator = locator; 
     } 

     @Override 
     public void startElement(final String uri, final String localName, final String qName, 
       final Attributes attributes) 
        throws SAXException { 
      int lineNum = locator.getLineNumber(); 
      logger.debug("I am now on line " + lineNum + " at element " + qName); 

      int len = attributes.getLength(); 
      for(int i=0;i<len;i++){ 
       String attVal = attributes.getValue(i); 
       String attName = attributes.getQName(i); 

       logger.debug("att " + attName + "=" + attVal); 

       if(attName.startsWith("bad")){ 
        throw new SAXException("found attr : " + attName + "=" + attVal + " that starts with bad! at line : " + 
       locator.getLineNumber() + " at element " + qName + "\nelement occurs below text : " + text); 
       } 
      } 

     } 




    }; 

    try { 
     parser.parse(new FileInputStream(new File(XML_FILE_PATH)), eleHandler); 
    } catch (FileNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (SAXException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return doc; 
    } 


} 

liên quan đến văn bản, tùy thuộc vào vị trí trong tệp xml xảy ra lỗi, có thể không có bất kỳ văn bản nào. Vì vậy, với xml này:

<?xml version="1.0"?> 
<root> 
    <section> 
    <para>This is a quick doc to test the ability to get line numbers via the Locator object. </para> 
    </section>  
    <section bad:attr="ok"> 
    <para>another para.</para> 
    </section> 
</root> 

nếu phần tử xấu ở phần tử đầu tiên, văn bản sẽ trống. Trong trường hợp này, ngoại lệ được ném là:

org.xml.sax.SAXException: found attr : bad:attr=ok that starts with bad! at line : 6 at element section 
element occurs below text : This is a quick doc to test the ability to get line numbers via the Locator object. 

Khi bạn nói bạn đã thử sử dụng đối tượng Locator, vấn đề chính xác là gì?

+0

Tôi muốn biết (sử dụng ví dụ của bạn) vị trí cột và cột chính xác của 'b' của "bad: attr". Hoặc - nếu giá trị của thuộc tính là vấn đề - hoặc là báo giá mở hoặc 'o' của "ok". – Paul

+0

Nhưng trong các trường hợp khác, nó có thể là vị trí chính xác của "

" nếu, ví dụ:
không phải là thành phần hợp lệ bên trong . Hoặc 'a' của "một đoạn khác." nếu, nói, "một đoạn khác." không phải là một chuỗi hợp lệ được tìm thấy giữa . Nói chung, tôi muốn biết vị trí dòng và cột chính xác của thẻ bắt đầu/kết thúc, chạy văn bản, tên thuộc tính và giá trị thuộc tính. – Paul

2

Trình phân tích cú pháp XML sẽ (và phải) mượt mà trên những thứ nhất định như khoảng trắng bổ sung, vì vậy việc ánh xạ chính xác trở lại luồng ký tự là không khả thi.

Bạn nên xem xét việc nhận lexer hoặc 'trình tạo luồng mã thông báo' để tăng chi tiết, nói cách khác, hãy chuyển đến cấp độ chi tiết bên dưới trình phân tích cú pháp XML.

Có một vài khung chung để viết lexers trong java. This Trang dựa trên ANTLR 3 có một cái nhìn tổng quan về lexer vs parser và section one một số ví dụ về XML Lexer rudimentory.

Tôi cũng muốn nhận xét rằng đối với người dùng có giao diện web, có thể bạn nên xem xét giải pháp phía máy khách thuần túy (ví dụ: javascript).

+0

Cảm ơn. Tôi đã sử dụng ANTLR trước đây nhưng tôi không phải là một fan hâm mộ. Tôi đi xung quanh với ý tưởng rằng tôi có thể phải viết một lexer bản thân mình. – Paul

+0

Giao diện JavaScript tương tác là một ý tưởng dài hạn tốt. Ngay bây giờ, mặc dù tôi đang cố gắng tạo ra một tính năng chỉnh sửa wiki hiệu quả bằng cách sử dụng các hòn đảo XML được nhúng để đánh dấu phức tạp hơn - và chúng cần phân tích cú pháp và xác thực khi người dùng lưu. – Paul

+0

Đừng tự viết, thay vì hack một cái gì đó như https://github.com/FasterXML/aalto-xml/blob/master/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java – ThomasRS

Các vấn đề liên quan