2013-02-19 2 views
0

Я разбираю документ, который я не могу изменить из Интернета с помощью SAX Parser. Он работал очень хорошо, когда документы пришли отформатированы как таковые:Анализ XML без начала и конца документа

<outtertag> 
    <innertag>data</innertag> 
    <innerag>moreData</innertag> 
</outtertag> 

Однако, есть определенные вызовы я делаю, когда XML отформатирован без внешних тегов, так что я в основном получить только список данных, как например :

<innertag>data</innertag> 
    <innerag>moreData</innertag> 

Это кажется глупым, но я не получаю, чтобы выбрать способ форматирования XML и не может быть изменен на данный момент. Проблема заключается в том, что кажется, что SAX Parser попадает в событие endDocument, как только он попадает в первый закрывающий innertag.

У меня есть довольно хакерское решение для преобразования InputStream в String, метания тегов вокруг него и последующее преобразование его в InputStream. На самом деле он отлично разбирается. Но, конечно, есть лучший способ. Я бы предпочел не писать целый парсер. Большинство тегов одинаковы в стороне от отсутствия открывающих и закрывающих тегов.

Просто для этого я отправлю код, но это довольно стандартный SAX Parser. Оригинал фактически разбор около 30 некоторых тегов:

 SAXParserFactory factory = SAXParserFactory.newInstance(); 
     SAXParser saxParser = factory.newSAXParser(); 
     XMLReader xmlReader = saxParser.getXMLReader(); 

     MyHandler handler = new MyHandler(); 
     xmlReader.setContentHandler(handler); 

     InputSource inputSource = new InputSource(url.openStream()); 
     xmlReader.parse(inputSource); 
    } 

    catch (SAXException e) { e.printStackTrace(); } 
    catch (ParserConfigurationException e) { e.printStackTrace(); } 
    catch(Exception e) { e.printStackTrace(); } 
} 

private class MyHandler extends DefaultHandler { 
    private StringBuilder content; 

    public MyHandler() { 
     content = new StringBuilder(); 
    } 
    public void startElement(String uri, String localName, String qName, 
      Attributes atts) throws SAXException { 
     content = new StringBuilder(); 
     if(localName.equalsIgnoreCase("innertag")) { 
      //Doing stuff 
     } 

    } 
    public void endElement(String uri, String localName, String qName) 
      throws SAXException { 

     //Doing stuff 
    } 
    public void characters(char[] ch, int start, int length) 
      throws SAXException { 
     content.append(ch, start, length); 
    } 
    public void endDocument() throws SAXException { 
       //When parsing the second type of document, hits this event almost immediately after parsing first tag 



    } 
} 

И, если это имеет значение, вот мой Hacky код, я использую, но просто чувствует себя неправильно, но это работает:

BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); 
     StringBuilder sb = new StringBuilder("<tag>"); 
     String line = null; 

     while ((line = reader.readLine()) != null) { 
      sb.append(line); 
     }   
     sb.append("</tag>"); 
     String xml =sb.toString(); 

     InputStream is = new ByteArrayInputStream(xml.getBytes()); 
     InputSource source = new InputSource(is); 
     xmlReader.parse(source); 
+5

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

+0

Любые идеи по анализу второго набора данных, отличных от XML? – s3kt0r

+1

Я не очень разбираюсь в Java, поэтому я не уверен, есть ли какое-то конкретное решение, но при работе с подобными ситуациями на других языках я сделал именно то, что вы делаете. – psubsee2003

ответ

1

Я я скажу, что ты сейчас делаешь, так же хорошо, как и ты. Единственное, что нужно рассмотреть, это преобразование потока stream -> string ->, особенно если документы большие. Вы можете использовать что-то вроде Guava's ByteStreams.join(), которое позволяет объединять потоки вместе вместо строк. Что-то вроде следующего:

import com.google.common.io.*; 
import java.io.*; 

public class ConcatenateStreams { 
    public static void main(String[] args) throws Exception { 
     InputStream malformedXmlContent = externalXmlStream(); 
     InputSupplier<InputStream> joined = ByteStreams.join(
       inputSupplier("<root>"), 
       inputSupplier(malformedXmlContent), 
       inputSupplier("</root>")); 
     ByteStreams.copy(joined, System.out); 
    } 

    private static InputStream externalXmlStream() { 
     return new ByteArrayInputStream("<foo>5</foo><bar>10</bar>".getBytes()); 
    } 

    private static InputSupplier<InputStream> inputSupplier(final String text) { 
     return inputSupplier(new ByteArrayInputStream(text.getBytes())); 
    } 

    private static InputSupplier<InputStream> inputSupplier(final InputStream inputStream) { 
     return new InputSupplier<InputStream>() { 
      @Override 
      public InputStream getInput() throws IOException { 
       return inputStream; 
      } 
     }; 
    } 
} 

, который выводит:

<root><foo>5</foo><bar>10</bar></root> 
+1

yep, просто нужно убедиться, что кодировки соответствуют всем потокам. – jtahlborn

0

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

<!DOCTYPE doc [ 
<!ENTITY e SYSTEM "data.xml"> 
]> 
<doc>&e;</doc> 

где data.xml ваш XML, и передать этот документ в XML-парсер вместо оригинала. Beats записывают десятки строк кода Java.

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