9
votes

Comment analyser efficacement des documents XML concaténés à partir d'un fichier

J'ai un fichier composé de documents XML valides concaténés. Je souhaite séparer efficacement des documents XML individuels.

Le contenu du fichier concaténé ressemblera à ceci, le fichier concaténé n'est donc pas un document XML valide. P>

<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>
<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>
<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>


2 commentaires

Supposons-nous que le codage du personnage reste le même pour chacun? Sinon, cela devient considérablement plus difficile :-)


Tous les fichiers utilisent le même codage que le document lui-même utilise. Peu importe s'ils disent qu'ils sont UTF-8. Si le document concatisé est formaté comme UTF-16, ils sont tous UTF-16.


5 Réponses :


3
votes

Étant donné que vous n'êtes pas sûr que la déclaration sera toujours présente, vous pouvez supprimer toutes les déclarations (une regex tel que <\? xml version. * \?> peut les trouver), prépendez < Code> , APPENDER , telle que la chaîne résultante sera un document XML valide. Dans ce cas, vous pouvez récupérer les documents séparés en utilisant (par exemple) la requête XPath / doc-collection / * . Si le fichier combiné peut être suffisamment grand que la consommation de mémoire devient un problème, vous devrez peut-être utiliser un analyseur de streaming tel que sax, mais le principe reste le même.

Dans un scénario similaire que j'ai rencontré, je lisai simplement le document concaténé directement à l'aide d'un analyseur XML: bien que le fichier concaténé peut ne pas être un document XML valide , il s'agit d'un XML Fragment (sauf les déclarations répétées) - Donc, une fois que vous dépassez les déclarations, si votre analyseur prend en charge des fragments d'analyse, vous pouvez également simplement lire le résultat directement. Tous les éléments de niveau supérieur seront alors les éléments racines des documents concaténés.

En bref, si vous supprimez toutes les déclarations, vous aurez un fragment XML valide qui est trivialement paresible directement ou en l'entourant avec une balise.


0 commentaires

4
votes

Ne pas diviser! Ajoutez une grosse balise autour de là! Ensuite, il devient un fichier XML à nouveau:

<BIGTAG>
<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>
<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>
<?xml version="1.0" encoding="UTF-8"?>
<someData>...</someData>
</BIGTAG>


7 commentaires

Les instructions de traitement commençant par "XML" ou "XML" sont réservées aux normes XML, donc les utiliser comme "personnalisé", comme celui-ci n'est pas vraiment valide.


Je pense que cela est en grande partie correct que les instructions de traitement


Cela ne fonctionnera pas si tous les documents XML n'utilisent pas le même codage.


Vous devrez dépenser ces . Pourrait être possible dans le "Dump XML" -Stage.


C'est pourquoi j'ai suggéré de scinder à la place - c'est plus simple, éventuellement plus rapide et pas difficile à bien avoir raison.


@Amon, la scission est plus difficile si ces instructions de traitement ne sont pas toujours incluses. En outre, ces instructions n'ont pas de sens puisqu'elles n'utiliseront tous le même codage que le grand document. Java est assez bon à des expressions régulières, donc avec une expression simple que vous pourriez supprimer toutes ces instructions et que le reste deviendrait pure XML si vous le contenez dans une supertag.


@ Juha S., le codage est déjà invalide car tout est situé dans un seul fichier texte, il utilise ainsi le même codage.



3
votes

Comme Eamon dit, si vous connaissez la chose sera toujours là, rompre simplement sur cela.

omettre cela, recherchez l'étiquette de niveau de fin du document. Autrement dit, numérisez le texte comptant le nombre de niveaux que vous êtes profond. Chaque fois que vous voyez une balise qui commence par "<" mais pas "", ajoutez 1 au nombre de profondeurs. Chaque fois que vous voyez une balise qui commence "


4 commentaires

Pourquoi pas seulement chercher ?


Et encore une fois, pourquoi ne pas supprimer les instructions de traitement, en ajoutant tout le reste dans une étiquette plus grande? L'instruction de traitement n'est plus utile que tous les fichiers utilisent le même codage que le grand document. Avec eux parti, y compris une super-balise vient de le transformer en XML valide à nouveau.


Cela dépend de la nécessité ultime. La question a été indiquée comme, comment puis-je les diviser ?, Voilà ce que j'essayais de répondre. Sans savoir ce que l'affiche originale essaie de faire avec la sortie, je ne sais pas si vous les enveloppez tous dans une grande balise est une solution viable ou non. Si c'est bien, allez-y. Il pourrait y avoir d'autres solutions potentielles dans cette direction. Comme si les fichiers partagent tous une étiquette commune de niveau supérieur, vous pouvez peut-être les combiner tous sous une seule tag de ce type, c'est-à-dire jeter les balises de démarrage sur toutes les étiquettes sauf et finales de tous sauf le dernier.


J'ai fini par casser les éléments racines de départ.



0
votes

Je n'ai pas de réponse Java, mais voici comment j'ai résolu ce problème avec c #.

J'ai créé une classe nommée XMLFileStreams pour analyser le document source de la déclaration de document XML et la casser logiquement dans plusieurs documents: xxx

à utiliser xmlfiletreams: xxx

Il y a quelques mises en garde.

  1. Il lit le fichier entier en mémoire pour le traitement. Cela pourrait être un problème si le fichier est vraiment grand.
  2. Il utilise une recherche de force brute simple pour rechercher les limites du document XML.

0 commentaires

1
votes

Ceci est ma réponse à la version C #. Code très laid qui fonctionne: - \

public List<T> ParseMultipleDocumentsByType<T>(string documents)
    {
        var cleanParsedDocuments = new List<T>();
        var serializer = new XmlSerializer(typeof(T));
        var flag = true;
        while (flag)
        {
            if(documents.Contains(typeof(T).Name))
            {
                var startingPoint = documents.IndexOf("<?xml");
                var endingString = "</" +typeof(T).Name + ">";
                var endingPoing = documents.IndexOf(endingString) + endingString.Length;
                var document = documents.Substring(startingPoint, endingPoing - startingPoint);
                var singleDoc = (T)XmlDeserializeFromString(document, typeof(T));
                cleanParsedDocuments.Add(singleDoc);
                documents = documents.Remove(startingPoint, endingPoing - startingPoint);
            }
            else
            {
                flag = false;
            }
        }


        return cleanParsedDocuments;
    }

    public static object XmlDeserializeFromString(string objectData, Type type)
    {
        var serializer = new XmlSerializer(type);
        object result;

        using (TextReader reader = new StringReader(objectData))
        {
            result = serializer.Deserialize(reader);
        }

        return result;
    }


0 commentaires