2013-02-28 3 views
11

J'ai le problème suivant:Parsing gros documents XML en JAVA

J'ai un fichier XML (environ 1 Go), et doivent itérer et vers le bas (non séquentielle, l'un après l'autre) afin pour obtenir les données requises et faire quelques opérations dessus. Initialement, j'ai utilisé le paquet DOM Java, mais évidemment, tout en analysant le fichier XML, la JVM atteint son espace de tas maximum et s'arrête. Afin de surmonter ce problème, l'une des solutions que j'ai trouvées consistait à trouver un autre analyseur qui itère chaque élément dans le XML, puis je stocke son contenu dans une base de données SQLite temporaire sur mon disque dur. Ainsi, le tas de la JVM n'est pas dépassé et, une fois toutes les données remplies, j'ignore le fichier XML et continue mes opérations sur la base de données SQLite temporaire.

Existe-t-il une autre façon de résoudre mon problème?

+1

utilisation JAXB parser xml – Biswajit

+1

Comme d'autres ont dit que vous devez utiliser un analyseur SAX au lieu d'un analyseur DOM, il fera exactement ce dont vous avez besoin. Lisez ceci: http://stackoverflow.com/questions/6828703/difference-about-sax-and-dom – cowls

+0

Si vous ne pouvez pas tenir l'ensemble arbre DOM, vous devez trouver un moyen de faire votre traitement de manière séquentielle. Est-ce possible? Pouvez-vous montrer un XSLT qui fait ce dont vous avez besoin? –

Répondre

12

SAX (Simple API for XML) vous aidera ici.

Contrairement à l'analyseur DOM, l'analyseur SAX ne crée pas en mémoire représentation du document XML et est donc plus rapide et utilise moins de mémoire . Au lieu de cela, l'analyseur syntaxique SAX informe les clients de la structure de document XML en appelant des rappels, c'est-à-dire en invoquant des méthodes sur une instance org.xml.sax.helpers.DefaultHandler fournie à l'analyseur.

Voici un exemple d'implémentation:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); 
DefaultHandler handler = new MyHandler(); 
parser.parse("file.xml", handler); 

Où dans MyHandler vous définissez les actions à prendre lorsque des événements comme début/fin du document/élément sont générés.

class MyHandler extends DefaultHandler { 

    @Override 
    public void startDocument() throws SAXException { 
    } 

    @Override 
    public void endDocument() throws SAXException { 
    } 

    @Override 
    public void startElement(String uri, String localName, String qName, 
      Attributes attributes) throws SAXException { 
    } 

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

    // To take specific actions for each chunk of character data (such as 
    // adding the data to a node or buffer, or printing it to a file). 
    @Override 
    public void characters(char ch[], int start, int length) 
      throws SAXException { 
    } 

} 
+2

Si vous avez déjà effectué l'analyse SAX, vous savez probablement que la méthode 'characters()' est également très importante, et vous devez effectuer un ** buffering ** des données de caractères car il n'est pas garanti qu'une donnée de contenu est traitée dans un bloc (c'est-à-dire que deux appel 'character()' peuvent être faits immédiatement). Je pense qu'il vaut la peine de mentionner. – gaborsch

+1

Je ne voulais pas dire que ma solution était complète. Ce n'était qu'une implémentation élémentaire. Merci d'avoir signalé. Je vais mettre à jour ma réponse avec ça. –

+0

Bon, merci, comme ça c'est +1 – gaborsch

3

Si vous ne voulez pas être lié par les limites de la mémoire , je recommande certainement vous d'utiliser votre approche actuelle, et stocker tout dans la base de données.

L'analyse du fichier XML doit être effectuée par un SAX parser, comme tout le monde l'a recommandé (y compris moi). De cette façon, vous pouvez créer un objet à la fois, et vous pouvez immédiatement le conserver dans la base de données.

Pour le post-traitement (résolution des références croisées), vous pouvez utiliser SELECT depuis la base de données, créer des clés primaires, des index, etc. Vous pouvez utiliser ORM (Eclipselink, Hibernate) si vous vous sentez à l'aise avec ça .

En fait, je ne recommande pas vraiment SQLite, il est plus facile de configurer un serveur MySQL et d'y stocker les données. Plus tard, vous pouvez même réutiliser les données XML (si vous ne les supprimez pas).

+0

Je me demande comment quelqu'un peut croire qu'il est plus facile d'installer un serveur de base de données complet au lieu d'utiliser une base de données intégrée, où il suffit d'inclure un fichier JAR sans rien installer. Je pense que pour cette utilisation, un serveur de base de données séparé serait exagéré. Peut-être qu'il existe d'autres bonnes raisons d'utiliser un serveur de base de données, mais plus facile à installer? Vraiment? – vanje

+0

@vanje Je ne voulais pas dire Oracle :) nous parlons de MySQL. Sérieusement, je ne peux pas croire que ce serait un problème pour un développeur de mettre en place un serveur MySQL. – gaborsch

+0

Je pense que chaque développeur devrait être en mesure d'effectuer une installation de base d'Oracle et de MySQL. Et je suis d'accord avec vous que Oracle est beaucoup plus complexe que MySQL. Mais ce n'est pas le point. Vous avez comparé MySQL avec SQLite et déclaré que MySQL serait plus facile à configurer. Mais vous n'avez pas mentionné ce qui est le plus facile à votre avis. – vanje

1

Si vous souhaitez utiliser une approche de plus haut niveau que SAX, ce qui peut être très difficile à programmer, vous pouvez regarder les transformations XSLT en streaming en utilisant une version récente de Saxon-EE. Cependant, vous avez été trop vague sur le traitement précis que vous faites pour savoir si cela fonctionnera pour votre cas particulier.

0

si vous avez besoin d'une ressource approche conviviale pour gérer très grand xml, essayez ceci: http://www.xml2java.net/xml-to-java-data-binding-for-big-data/ il vous permet de traiter les données d'une manière SAX, mais avec l'avantage d'obtenir des événements de haut niveau (données xml mappés sur java) et être capable de travailler directement avec ces objets dans votre code.il combine donc la commodité de jaxb et la convivialité des ressources SAX.