2009-10-28 7 views
4

Je dois lire un document XML volumineux du réseau et le scinder en documents XML plus petits. En particulier, le flux j'ai lu à partir du réseau ressemble à ceci:Java: comment diviser un flux XML en petits documents XML? XPath sur l'analyseur XML de streaming?

<a> <b> ... </b> <b> ... </b> <b> ... </b> <b> ... </b> .... </a>

J'ai besoin de briser ce en morceaux de

<a> <b> ... </b> <a>

(je ne fait besoin des <b> .... </b> parties comme Tant que les liaisons d'espace de noms déclarées plus haut (par exemple dans <a>) sont déplacées à <b> si cela est plus facile).

Le fichier est trop gros pour un analyseur de style DOM, il doit être fait en streaming. Existe-t-il une bibliothèque XML capable de faire cela?

[Modifier]

Je pense que je suis à la recherche idéal est quelque chose comme la possibilité de faire des requêtes XPath sur un flux XML dans lequel l'analyseur de flux parse que dans la mesure nécessaire pour retourner l'élément suivant dans la jeu de nœuds de résultats (et tous ses attributs et enfants). Ne doit pas être XPath, mais quelque chose le long de l'idée.

Merci!

Répondre

2

L'API JAXP SAX avec filtre SAX est à la fois rapide et efficace. On peut voir de bons filtres intro here

+0

hmm Je ne comprends pas très bien. Je peux voir comment je peux attraper l'événement lorsque mon tag est analysé, mais je ne vois pas comment obtenir le filtre pour rediriger le flux vers un nouveau document jusqu'à la balise de fin et comment inclure les parents + leurs différents espaces de noms fixations. Y a-t-il une chance que vous puissiez développer un peu? Je suis conscient que je peux le faire simplement par le biais de SAX en attrapant essentiellement toutes sortes d'événements et en gardant la trace des choses et des choses simples à copier, mais j'espérais qu'il y aurait une solution plus facile. – Carsten

+0

Ce n'est pas la solution facile que j'espérais, mais c'est correct et personne n'a eu une meilleure suggestion, donc je vais vous le donner ... – Carsten

0

Il m'arrive d'aimer la bibliothèque XML XOM, car son interface est simple, intuitive et puissante. Pour faire ce que vous voulez avec XML, vous pouvez utiliser votre propre NodeFactory et (par exemple) remplacer la méthode finishMakingElement(). Si c'est l'élément que vous voulez (dans votre cas, <b>), vous le transmettez à ce que vous voulez faire avec.

1

En tant que séparateur XML, VTD-XML est idéal pour cette tâche ... il est également plus efficace en mémoire que DOM. La méthode clé qui simplifie le codage est getElementFragment() ... de VTDNav ci-dessous est le code Java pour split input.xml dans out0.xml et out1.xml

<a> <b> text1 </b> <b> text2 </b> </a> 

en

<a> <b> text1</b> </a> 

et

<a> <b> text2</b> </a> 

utilisant XPath

/a/b 

Le code

import java.io.*; 
import com.ximpleware.*; 

public class split { 
    public static void main(String[] argv) throws Exception{ 
     VTDGen vg = new VTDGen(); 
     if (vg.parseFile("c:/split/input.xml", true)){ 
      VTDNav vn = vg.getNav(); 
      AutoPilot ap = new AutoPilot(vn); 
      ap.selectXPath("https://stackoverflow.com/a/b"); 
      int i=-1,k=0; 
      byte[] ba = vn.getXML().getBytes(); 
      while((i=ap.evalXPath())!=-1){ 
       FileOutputStream fos = new FileOutputStream("c:/split/out"+k+".xml"); 
       fos.write("<a>".getBytes()); 
       long l = vn.getElementFragment(); 
       fos.write(ba, (int)l, (int)(l>>32)); 
       fos.write("</a>".getBytes()); 
       k++; 
      } 
     }  
    } 
} 

Pour en savoir plus, s'il vous plaît visitez http://www.devx.com/xml/Article/36379

+0

Merci pour votre réponse. Cela ressemble à une approche de style DOM pour moi, en demandant l'ensemble du document à analyser avant de faire une requête. Mon flux XML est trop grand pour cela, il doit être fait par un analyseur de streaming. – Carsten

+0

avec la version étendue, il peut faire le chargement partiel par carte de mémoire, mais ceci est seulement disponible dans l'édition prolongée, avec la version standard, 2GB est le plus que vous pouvez charger, il consomme seulement environ 1/5 la mémoire de DOM. –

+0

Ceci fait partie de votre code (méthode VTDGen.parseFile()): fis = new FileInputStream (f); \t octet [] b = nouvel octet [(int) f.length()] ;. Donc, vous chargez tous les fichiers en mémoire. C'est vraiment dégoutant. – Andremoniy

1

aller vieille école

StringBuilder buffer = new StringBuilder(1024 * 50); 
BufferedReader reader = new BufferedReader(new FileReader(pstmtout)); 
String line; 
while ((line = reader.readLine()) != null) { 
    buffer.append(line); 
    if (line.equalsIgnoreCase(endStatementTag)) { 
    service.handle(buffer.toString()); 
    buffer.delete(0, buffer.length()); 
    } 
} 
0

Vous pouvez le faire avec le langage XProc

<?xml version="1.0" encoding="ISO-8859-1"?> 
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="1.0"> 
    <p:load href="in/huge-document.xml"/> 
    <p:for-each> 
    <p:iteration-source select="https://stackoverflow.com/a/b"/> 
    <p:wrap match="/b" wrapper="a"/> 
    <p:store> 
     <p:with-option name="href" select="concat('part', p:iteration-position(), '.xml')"> 
      <p:empty/> 
     </p:with-option> 
    </p:store> 
    </p:for-each> 
</p:declare-step> 

Vous pouvez utiliser QuiXProc (mise en œuvre en streaming XProc: http://code.google.com/p/quixproc/) pour essayer de le diffuser aussi