9
votes

Comment transformer énormément de fichiers XML en Java?

Comme le titre le dit, j'ai un énorme fichier XML (GBS) xxx

et je voudrais le transformer en un peu plus petit qui ne conserve que quelques-uns des éléments .
Mon analyseur devrait faire ce qui suit:
1. Analyser le fichier jusqu'à ce qu'un élément pertinent commence.
2. Copiez l'élément pertinent complet (avec enfants) dans le fichier de sortie. Aller à 1.

L'étape 1 est facile avec sax et impossible pour Dom-anal-anal.
L'étape 2 est agaçante avec saxo, mais facile avec le DOM-Parser ou XSLT.

Alors quoi? - Y a-t-il un moyen creux de combiner sax et dom-anal d'analyseur pour faire la tâche?


0 commentaires

7 Réponses :


10
votes

Stax semblerait être une solution évidente: c'est un analyseur de tir plutôt que le "Push" de sax ou le "tampon tout ce qui est" "approche de dom. Je ne peux pas dire que je l'ai utilisé cependant. Un "Tutoriel Stax" La recherche peut être utile :)


1 commentaires

+1 Stax est plus facile à utiliser que Sax si vous n'avez pas été exposé à la gestion des fichiers XML auparavant. En outre, il permet également d'écrire XML (contrairement à saxo).



9
votes

Oui, écrivez simplement un gestionnaire de contenu SAX, et lorsqu'il rencontre un certain élément, vous construisez un arbre DOM sur cet élément. Je l'ai fait avec de très gros fichiers et ça fonctionne très bien.

C'est en fait très facile: dès que vous rencontrez le début de l'élément souhaité, vous définissez un drapeau dans votre gestionnaire de contenu et à partir de là, vous transmettez tout au constructeur DOM. Lorsque vous rencontrez la fin de l'élément, vous définissez le drapeau sur FALSE et écrivez le résultat.

(Pour des cas plus complexes avec des éléments imbriqués du même nom d'élément, vous devez créer une pile ou un compteur, mais c'est toujours assez facile à faire.)


0 commentaires

2
votes

Jetez un coup d'œil à Stax , cela pourrait être ce dont vous avez besoin. Il y a une bonne introduction sur Développeur IBM fonctionne . < / p>


0 commentaires

0
votes

Vous pouvez le faire assez facilement avec un XMLEVENTReader et plusieurs xmleventwriter S du package Javax.xml.stream.


0 commentaires

3
votes

Puisque vous parlez de GB, je préférerais hiérarchiser l'utilisation de la mémoire dans la considération. SAX a besoin d'environ 2 fois la mémoire que le document BIG est, tandis que DOM en a besoin pour être au moins 5 fois. Donc, si votre fichier XML est de 1 Go BIG, alors DOM nécessiterait un minimum de 5 Go de mémoire libre. Ce n'est plus drôle. SO SAX (ou une variante sur celle-ci, comme Stax) est la meilleure option ici.

Si vous souhaitez l'approche la plus efficace de la mémoire, regardez VTD-XML . Il ne nécessite que un peu plus de mémoire que le fichier grand est.


2 commentaires

Bon point, la mémoire est absolument cruciale ici. BTW, SAX n'a ​​même pas nécessairement besoin de deux fois la taille du document - car il s'agit d'une API en streaming, vous pouvez constamment des ordures collecter des parties précédentes du document, dès que vous n'en avez plus besoin.


Vrai, mais cela dépend des exigences fonctionnelles. Il pourrait par exemple avoir besoin d'avoir la totalité de XML en mémoire avant de pouvoir rassembler les informations souhaitées.



2
votes

Pour un tel document XML, quelque chose avec une architecture en streaming, comme Omnimark serait idéal.

Il n'aurait pas besoin d'être complexe non plus. Un script omnimark comme ce qui est ci-dessous pourrait vous donner ce dont vous avez besoin: P>

process

submit #main-input

macro upto (arg string) is
    ((lookahead not string) any)*
macro-end

find (("<keep") upto ("</keep>") "</keep>")=>keep
    output keep

find any


0 commentaires

5
votes

J'ai fait de bonnes expériences avec STX ( Transformations de streaming pour XML forte>). Fondamentalement, il s'agit d'une version streamée de XSLT, bien adaptée à l'analyse d'énormes quantités de données avec une empreinte de mémoire minimale. Il a une implémentation dans Java nommée JOOST .

Il devrait être facile de trouver une transformation STX qui ignore tous les éléments jusqu'à ce que l'élément correspond à un XPath donné, copie cet élément et tous ses enfants (à l'aide d'un modèle d'identité dans un groupe de gabarits) et continue d'ignorer les éléments jusqu'à la correspondance suivante. P>

Mise à jour forte> p>

J'ai piraté une transformation STX qui fait ce que je comprends que vous voulez. Il dépend surtout des fonctionnalités STX uniquement telles que des groupes de modèles et des modèles par défaut configurables. P>

<?xml version="1.0" encoding="UTF-8"?>
<child attribute="value1">
            text1<b>bold</b>
        </child><child attribute="value2">
            text2
            <x:childX xmlns:x="http://x.example.com/x">
            <!-- comment -->
                yet more<b i="i" x:i="x-i" />
            </x:childX>
        </child>


3 commentaires

ça a l'air bien. Puis-je simplement écrire une feuille de styles xslt et ensuite l'exécuter avec STX?


Non, ce n'est pas possible. Tandis que XSLT utilise des modes pour distinguer les modèles pour la même correspondance dans différentes situations (mode de saut V. Mode Copie, dans votre cas), STX utilise des groupes de modèles. La syntaxe dans les modèles est similaire à XSLT, mais différente en détail. J'ajoute un exemple de transformer à ma réponse.


Notez que, dans le XPath pour correspondre à un modèle, seuls les nœuds que vous pouvez accéder sont le nœud actuel, ses nœuds parents et leurs attributs. Vous ne pouvez pas correspondre à aucun autre nœud précédent ou suivant, en raison de la nature en streaming de la transformation. Si vous avez besoin de ce type de correspondance, vous pouvez définir des variables (qui sont mutables) et les utiliser dans STX: si tests. Mais ceci est délicat et ressemble à mettre en œuvre un gestionnaire de contenu dans XML.