2015-08-03 3 views
1

У меня есть XML-файл размером 4.2 ГБ! Очевидно, что разбор всей DOM нецелесообразен. Я смотрел SAX и STAX, чтобы выполнить синтаксический анализ этого гигантского XML-файла. Однако все примеры, которые я видел, просты. Файл XML, с которым я имею дело, вложен в вложенные вложенные. Есть области, где они идут на 10+ уровней.Java Stax for Complex/Large XML

Я нашел этот учебник, но не уверен, что его жизнеспособное решение.

http://www.javacodegeeks.com/2013/05/parsing-xml-using-dom-sax-and-stax-parser-in-java.html (Боттон пример использования Stax)

Я не совсем уверен, как обрабатывать вложенные объекты.

Я создал объекты Java, чтобы имитировать структуру XML. Вот несколько, слишком много для отображения.

Record.java

public class Record implements Serializable { 

    String uid; 
    StaticData staticData; 
    DynamicData dynamicData; 
} 

Summary.java

public class Summary { 

    EWUID ewuid; 
    PubInfo pubInfo; 
    Titles titles; 
    Names names; 
    DocTypes docTypes; 
    Publishers publishers; 
} 

EWUID.java

public class EWUID { 

    String collId; 
    String edition; 
} 

PubInfo.java

public class PubInfo { 

    String coverDate; 
    String hasAbstract; 
    String issue; 
    String pubMonth; 
    String pubType; 
    String pubYear; 
    String sortDate; 
    String volume; 
} 

Это код, который я придумал до сих пор.

public class TRWOSParser { 

    XMLEventReader eventReader; 
    XMLInputFactory inputFactory; 
    InputStream inputStream; 

    public TRWOSParser(String file) throws FileNotFoundException, XMLStreamException { 
     inputFactory = XMLInputFactory.newInstance(); 
     inputStream = new FileInputStream(file); 
     eventReader = inputFactory.createXMLEventReader(inputStream); 
    } 

    public void parse() throws XMLStreamException{ 

     while (eventReader.hasNext()) { 
      XMLEvent event = eventReader.nextEvent(); 

      if (event.isStartElement()) { 
       StartElement startElement = event.asStartElement(); 
       if (startElement.getName().getLocalPart().equals("record")) { 
        Record record = new Record(); 
        Iterator<Attribute> attributes = startElement.getAttributes(); 
        while (attributes.hasNext()) { 
         Attribute attribute = attributes.next(); 
         if (attribute.getName().toString().equals("UID")) { 
          System.out.println("UID: " + attribute.getValue()); 
         } 
        } 
       } 
      } 
     } 
    } 
} 

Update:

Данные в XML лицензируется, поэтому я не могу показать весь файл. Это очень маленький сегмент, в котором я скремблировал данные.

<?xml version="1.0" encoding="UTF-8"?> 
<records> 
    <REC> 
     <UID>WOS:000310438600004</UID> 
     <static_data> 
      <summary> 
       <EWUID> 
        <WUID coll_id="WOS" /> 
        <edition value="WOS.SCI" /> 
       </EWUID> 
       <pub_info coverdate="NOV 2012" has_abstract="N" issue="5" pubmonth="NOV" pubtype="Journal" pubyear="2012" sortdate="2012-11-01" vol="188"> 
        <page begin="1662" end="1663" page_count="2">1662-1663</page> 
       </pub_info> 
       <titles count="6"> 
        <title type="source">JOURNAL OF UROLOGY</title> 
        <title type="source_abbrev">J UROLOGY</title> 
        <title type="abbrev_iso">J. Urol.</title> 
        <title type="abbrev_11">J UROL</title> 
        <title type="abbrev_29">J UROL</title> 
        <title type="item">Something something</title> 
       </titles> 
       <names count="1"> 
        <name addr_no="1 2 3" reprint="Y" role="author" seq_no="1"> 
         <display_name>John Doe</display_name> 
         <full_name>John Doe</full_name> 
         <wos_standard>Doe, John</wos_standard> 
         <first_name>John</first_name> 
         <last_name>Doe</last_name> 
        </name> 
       </names> 
       <doctypes count="1"> 
        <doctype>Editorial Material</doctype> 
       </doctypes> 
       <publishers> 
        <publisher> 
         <address_spec addr_no="1"> 
          <full_address>360 PARK AVE SOUTH, NEW YORK, NY 10010-1710 USA</full_address> 
          <city>NEW YORK</city> 
         </address_spec> 
         <names count="1"> 
          <name addr_no="1" role="publisher" seq_no="1"> 
           <display_name>ELSEVIER SCIENCE INC</display_name> 
           <full_name>ELSEVIER SCIENCE INC</full_name> 
          </name> 
         </names> 
        </publisher> 
       </publishers> 
      </summary> 
     </static_data> 
    </REC> 
</records> 
+0

Пара вопросов: есть ли у вас схема для этого файла и существует ли определенный уровень максимального повторения? Он имеет несколько уровней в глубину - это прекрасно, но имеет ли он идентификацию, из которой можно безопасно разобрать все поддерева сразу? – lscoughlin

+0

Я просил XSD, но на данный момент у меня его нет. Я не совсем уверен, насколько глубоко это может произойти, самое большее, что я видел до сих пор, это 11. – greyfox

+0

Ваша проблема заключается не в уровне гнездования, а в скорости повторения. На каком уровне он становится достаточно повторяющимся, чтобы вы могли сразу обрабатывать поддеревья? – lscoughlin

ответ

2

Аналогичное решение ответить lscoughlin является использование DOM4J, который имеет mechanims для решения этого сценария: http://dom4j.sourceforge.net/dom4j-1.6.1/faq.html#large-doc

В моей opionin это более прямой и легче следовать. Однако он может не поддерживать пространства имен.

+0

Я закончил с использованием dom4j. API очень легко работать и решить мою проблему загрузки всего DOM в память. – greyfox

1

Я делаю два предположения 1), что Eсть раннего уровня повторения, и 2), что вы можете сделать что-то значимое с частичным документом.

Предположим, вы можете перемещать некоторый уровень вложенности, а затем обрабатывать документ несколько раз, удаляя узлы на рабочем уровне каждый раз, когда вы «обрабатываете» документ. Это означает, что в любой момент времени в памяти будет только одно рабочее поддерево.

Вот рабочий фрагмент кода:

package bigparse; 

import static javax.xml.stream.XMLStreamConstants.CHARACTERS; 
import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT; 
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; 
import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; 
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; 

import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.io.StringWriter; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.stream.XMLInputFactory; 
import javax.xml.stream.XMLStreamException; 
import javax.xml.stream.XMLStreamReader; 
import javax.xml.transform.OutputKeys; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 

public class BigParse { 

    public static void main(String... args) { 

     XMLInputFactory factory = XMLInputFactory.newInstance(); 
     DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 

     try { 

      XMLStreamReader streamReader = factory.createXMLStreamReader(new FileReader("src/main/resources/test.xml")); 
      DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 

      Document document = documentBuilder.newDocument(); 
      Element rootElement = null; 
      Element currentElement = null; 

      int branchLevel = 0; 
      int maxBranchLevel = 1; 

      while (streamReader.hasNext()) { 
       int event = streamReader.next(); 
       switch (event) { 
       case START_DOCUMENT: 
        continue; 
       case START_ELEMENT: 

        if (branchLevel < maxBranchLevel) { 
         Element workingElement = readElementOnly(streamReader, document); 

         if (rootElement == null) { 
          document.appendChild(workingElement); 
          rootElement = document.getDocumentElement(); 
          currentElement = rootElement; 
         } else { 
          currentElement.appendChild(workingElement); 
          currentElement = workingElement; 
         } 

         branchLevel++; 
        } else { 

         workingLoop(streamReader, document, currentElement); 

        } 

        continue; 
       case CHARACTERS: 
        currentElement.setTextContent(streamReader.getText()); 
        continue; 

       case END_ELEMENT: 
        if (currentElement != rootElement) { 
         currentElement = (Element) currentElement.getParentNode(); 
         branchLevel--; 
        } 

        continue; 

       case END_DOCUMENT: 
        break; 
       } 

      } 

     } catch (ParserConfigurationException 
       | FileNotFoundException 
       | XMLStreamException e) { 
      throw new RuntimeException(e); 
     } 

    } 

    private static Element readElementOnly(XMLStreamReader streamReader, Document document) { 

     Element workingElement = document.createElement(streamReader.getLocalName()); 

     for (int attributeIndex = 0; attributeIndex < streamReader.getAttributeCount(); attributeIndex++) { 
      workingElement.setAttribute(
        streamReader.getAttributeLocalName(attributeIndex), 
        streamReader.getAttributeValue(attributeIndex)); 

     } 
     return workingElement; 
    } 

    private static void workingLoop(final XMLStreamReader streamReader, final Document document, final Element fragmentRoot) 
      throws XMLStreamException { 

     Element startElement = readElementOnly(streamReader, document); 
     fragmentRoot.appendChild(startElement); 

     Element currentElement = startElement; 

     while (streamReader.hasNext()) { 
      int event = streamReader.next(); 
      switch (event) { 
      case START_DOCUMENT: 
       continue; 
      case START_ELEMENT: 

       Element workingElement = readElementOnly(streamReader, document); 
       currentElement.appendChild(workingElement); 
       currentElement = workingElement; 

       continue; 
      case CHARACTERS: 
       currentElement.setTextContent(streamReader.getText()); 
       continue; 

      case END_ELEMENT: 
       if (currentElement != startElement) { 
        currentElement = (Element) currentElement.getParentNode(); 
        continue; 

       } else { 

        handleDocument(document, startElement); 

        fragmentRoot.removeChild(startElement); 
        startElement = null; 
        return; 
       } 

      } 

     } 

    } 

    // THIS FUNCTION DOES SOMETHING MEANINFUL 
    private static void handleDocument(Document document, Element startElement) { 

     System.out.println(stringify(document)); 
    } 

    private static String stringify(Document document) { 

     try { 
      Transformer transformer = TransformerFactory.newInstance().newTransformer(); 
      transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 

      StreamResult result = new StreamResult(new StringWriter()); 
      DOMSource source = new DOMSource(document); 

      transformer.transform(source, result); 

      String xmlString = result.getWriter().toString(); 
      return xmlString; 

     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

} 

EDIT: Я сделал невероятно глупую ошибку. Теперь это исправлено. Это работает, но несовершенно - должно быть достаточно, чтобы привести вас в полезном направлении.

+0

У меня возникли проблемы с этим, и предложение dom4j выглядело как более удобный API, но я сделал +1 для уровня детализации, спасибо – greyfox

1

Рассмотрит с использованием XSLT-3.0 потокового преобразования вида:

<xsl:template name="main"> 
    <xsl:stream href="bigInput.xml"> 
    <xsl:for-each select="copy-of(/records/REC)"> 
     <!-- process one record --> 
    </xsl:for-each> 
    </xsl:stream> 
</xsl:template> 

Вы можете обработать это с помощью саксонского-EE 9.6.

Логика «обработка одной записи» может использовать расширение Saxon SQL или вызвать функцию расширения: узлом контекста будет элемент REC с содержащимся в нем деревом, полностью доступным в поддереве, но без возможности перейдите за пределы обрабатываемого элемента REC.

+0

Не могли бы вы указать мне на учебник, который использует это? – greyfox

+0

Нет, извините. Это кровоточащий край, все еще работающий черновик W3C, так что вы немного по своему усмотрению. У Dimitre Novatchev есть ряд учебников XSLT 3.0 по адресу http://www.pluralsight.com/courses/xslt-3-0-whats-new-part1?gclid=CLajm6T4jscCFSb3wgodfkYN1A, но я не уверен, что он охватывает потоковое вещание. Существует ряд примеров потока xsl: stream в спецификации по адресу http://www.w3.org/TR/xslt-30/#stream-examples, а функция copy-of() описана в http: // www.w3.org/TR/xslt-30/#func-copy-of –

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