2017-01-31 58 views
5

Я пытаюсь найти способ точно определить номер строки и расположение символов как тегов, так и атрибутов при анализе XML-документа. Я хочу сделать это, чтобы я мог точно сообщить автору документа XML (через веб-интерфейс), где документ недействителен.XML/Java: Точные позиции строк и символов при анализе тегов и атрибутов?

В конечном счете, я хочу, чтобы каретка была в недействительном теге или просто внутри открытой цитаты недействительного атрибута. (Я не использую схему XML в этот момент, потому что точный формат атрибутов имеет значение, которое не может быть проверено только схемой. Возможно, мне даже захочется сообщить некоторые атрибуты как недопустимые частичные значения атрибута. Или аналогично , частично через текст между стартовым и конечным тегом.)

Я пробовал использовать SAX (org.xml.sax) и интерфейс Locator. Это работает до определенной степени, но не достаточно хорошо. Он сообщит только позицию чтения после событие; например, символ сразу после окончания открытого тега, для startElement(). Я не могу просто отчислить длину имени тега, потому что атрибуты, самозакрывающиеся теги и/или новые строки в открытом теге выкинут. (И Locator не предоставляет никакой информации о позиции атрибутов вообще.)

В идеале я хотел использовать подход, основанный на событиях, так как у меня уже есть обработчик SAX, который создает собственное DOM-представление или дальнейшая обработка. Тем не менее, мне было бы интересно узнать о любой DOM или DOM-подобной библиотеке, которая включает в себя точную информацию о местоположении для элементов модели.

Неужели кто-либо решил эту проблему или любой другой, с требуемым уровнем точности?

+0

Подход, основанный на событиях? Как [XMLEventReader] (http://docs.oracle.com/javase/8/docs/api/javax/xml/stream/XMLEventReader.html) и [XMLEvent.getLocation] (http://docs.oracle. ком/JavaSE/8/документы/API/javax/XML/поток/события/XMLEvent.html # getLocation--) метод? – VGR

+0

Я пробовал использовать XMLEventReader, но XMLStreamReader. Однако позиции этих отчетов являются конечной позицией каждого события. Так, например, после START_ELEMENT позиция указана сразу после закрытия стартового тега (note - start tag, а не элемент). Кажется, нет надежного способа определить положение начала тега. Кроме того, я никогда не получаю никаких событий ATTRIBUTE вообще, поскольку они объединены в одно событие START_ELEMENT: поэтому я не могу получить дальнейшую точность в позициях атрибутов. – Paul

+0

Пожалуйста, объясните, что вы имеете в виду, когда говорите, что не используете XML-схему в этот момент, потому что точный формат атрибутов имеет значение, которое не может быть проверено только схемой. * – kjhughes

ответ

0

Я написал быстрый xml-файл, который получает номера строк и генерирует исключение в случае нежелательного атрибута и дает текст, в котором была выброшена ошибка.

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


} 

в отношении текста, в зависимости от того, где в файле xml происходит ошибка, не может быть никакого текста. Таким образом, с этим xml:

<?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> 

Если плохой attr находится в первом элементе, текст будет пустым. В этом случае исключение составляло:

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. 

Когда вы говорите, что пытались использовать объект Locator, в чем же была проблема?

+0

Я хочу узнать (используя ваш пример) точную позицию строки и столбца «b» «bad: attr». Или - если значение атрибута является проблемой - либо открытой цитатой, либо «o» для «ok». – Paul

+0

Но в других случаях это может быть точное положение «

», если, например,
недействительный элемент внутри . Или «а» «другого пара». если, скажем, «другой пункт». не была допустимой строкой, находящейся между . В общем, я хочу знать точную позицию строки и столбца стартовых/конечных тегов, пробелы текста, имена атрибутов и значения атрибутов. – Paul

2

Анализаторы XML будут (и должны) сглаживать определенные вещи, такие как дополнительные пробелы, поэтому точное отображение обратно в поток символов не представляется возможным.

Вы должны изучить возможность получения лексера или генератора токенов для увеличения детализации, другими словами перейти на уровень детализации ниже XML-парсеров.

Существует несколько общих рамок для написания лексеров в java. This На странице, основанной на ANTLR 3, есть хороший обзор lexer vs parser и section one некоторых примеров XML-примера Rudimentory.

Я также хотел бы прокомментировать, что для пользователя с веб-интерфейсом, возможно, вам стоит рассмотреть решение на стороне клиента (например, javascript).

+0

Спасибо. Раньше я использовал ANTLR, но я не поклонник. Я прихожу к идее, что мне, возможно, придется написать сам лексер. – Paul

+0

Интерактивный интерфейс JavaScript - хорошая долгосрочная идея. Прямо сейчас, хотя я пытаюсь создать то, что фактически является функцией редактирования вики, используя встроенные острова XML для более сложной разметки, - и они нуждаются в анализе и проверке, когда пользователь сохраняет. – Paul

+0

Не пишите свои собственные, а взломайте что-то вроде https://github.com/FasterXML/aalto-xml/blob/master/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java – ThomasRS

 Смежные вопросы

  • Нет связанных вопросов^_^