IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Format d'échange (XML, JSON...) Java Discussion :

Stackoverflow fonction récursive [JDOM]


Sujet :

Format d'échange (XML, JSON...) Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 16
    Points
    16
    Par défaut Stackoverflow fonction récursive
    Bonjour à tous ,

    Contexte :

    pour extraire certaines information d'un fichier xml ( en EAD) ,il me faut parcourir la globalité de plusieurs fichier xml , de taille assez conséquente (entre 10 et 4098 ko).
    Les règles d'extractions étant très complexe je suis donc parti dans un premier lieu dans un listing de toutes les balises.

    J’initialise mon fichier à traiter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilder = documentBuilderFactory.newDocumentBuilder();
    document = documentBuilder.parse(xmlInputFile)
    Je lance ma fonction récursive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getEADxmlInformation(document,0,"");
    Dont voici le code note que le 3ieme param ne sert à rien, je voulais voir si mon souci venait de la déclaration de ma str)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public static String getEADxmlInformation(Node node,int deep, String Inf) {
    		//compteur de profondeur
    		int cptdeep=deep;
    		//str avec le nom du noeud
    		Inf=node.getNodeName();
    		//si "nouveau noeud" affiche le nom avec la bonne profondeur
    		if(Inf!="#text"){
    			for(int i=0;i<cptdeep;i++){
    				System.out.print("#");
    			}
    			System.out.println(Inf);
    		}
    		else{
    			//souci avec les retours "retour chariot" qui me donne des "#text"
    			//System.out.println("wtf");
    		}
    		//appel récursif si fils
    		if (node.hasChildNodes()){
    			getEADxmlInformation(node.getFirstChild(),cptdeep+1,"");
    		}
    		//sinon appel récursif si(et sur) noeud suivant 
    		else if(node.getNextSibling()!=null)
    		{
    			getEADxmlInformation(node.getNextSibling(),cptdeep,"");
    		}
    		//sinon appel récursif si(et sur) noeuf suivant du parent
    		else if(node.getParentNode().getNextSibling()!=null ){
    			getEADxmlInformation(node.getParentNode().getNextSibling(),cptdeep-1,"");
    		}
    		return Inf;
    	}
    résultats:

    #document
    #ead
    #ead
    ##eadheader
    ###eadid
    ###filedesc
    ####titlestmt
    #####titleproper
    #####author
    #####sponsor
    ####publicationstmt
    #####publisher
    etc
    très bien, c'est ce que je voulais


    ps : si je décote le syso"wtf"
    #document
    #ead
    #ead
    wtf
    ##eadheader
    wtf
    ###eadid
    wtf
    wtf
    ###filedesc
    wtf
    ####titlestmt
    wtf



    problèmes:

    lorsque la taille des fichiers augmentes ( au delà de 200K) , j'obtiens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    xception in thread "main" java.lang.StackOverflowError
    	at java.nio.Buffer.<init>(Buffer.java:170)
    	at java.nio.CharBuffer.<init>(CharBuffer.java:259)
    	at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:52)
    	at java.nio.CharBuffer.wrap(CharBuffer.java:350)
    	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:246)
    	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
    	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
    	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
    	at java.io.PrintStream.write(PrintStream.java:476)
    	at java.io.PrintStream.print(PrintStream.java:619)
    	at JDOM.DPICGM.getEADxmlInformation(DPICGM.java:167)
    	at JDOM.DPICGM.getEADxmlInformation(DPICGM.java:179)
    	at JDOM.DPICGM.getEADxmlInformation(DPICGM.java:181)
    ... etc

    généralement j'ai environ 1020 "JDOM.DPICGM.getEADxmlInformation(DPICGM.java:1XX)

    Questions:

    -Pourquoi ? Étant donné que pour des petits fichiers cela fonctionne (est-ce que c'est une limite d'appel récursif ?, mémoire ?)
    - J'ai l'impression de quand même de réinventé la roue, est-ce qu'il n'y a pas plus simple ?

    -"Bonus"- les "wtf", quelqu'un à une idée ?


    Voilà merci d'avance à ceux qui me liront, qui m'aideront.


    Pegaz

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Alors pas mal de choses :
    - Je ne vois pas de JDOM là-dedans.
    - Tu traites les parents deux fois par appel : la première en tant que voisin de l'élément qui le précède, la deuxième en tant que voisin du parent d'un élément. En récursif cela va forcément faire une explosion combinatoire.
    - Oui, il y a une limite d'appels récursif. Oui, c'est dû à la taille mémoire de la pile (et accessoirement c'est pas désagréable de planter quand on part en boucle infinie involontaire.)
    - Pour imprimer le contenu d'un fichier XML, il y a plus simple, en effet. Il suffit d'écrire ce fichier XML sur la sortie au lieu de le faire dans un fichier. Il est aussi possible de n'aller chercher que les éléments qui nous intéressent, soit parcourant les éléments par leurs noms, soit en utilisant XPath. Mais il arrive parfois que les infos qu'on cherche soient trop compliquées à aller chercher autrement que de manière récursive. Dans ce cas, bah oui, il faut faire du récursif, mais il suffit de traiter chaque nœud et ses enfants, quel intérêt d'aller voir les voisins et parents ?
    - Je ne vois pas ce qui t'ennuie avec les "wtf".
    - Pour voir si un node est un élément, il suffit de vérifier if(node.getNodType() == Node.ELEMENT_NODE). Les comparaisons douteuses avec "#text" sont dispensables.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 16
    Points
    16
    Par défaut
    Déjà , merci de ta réponse

    et voilà des précisions:

    Alors pas mal de choses :
    - Je ne vois pas de JDOM là-dedans.
    =>le DOcument est en JDOM non ? j'utiliserais les composants JDOM plus tard, pour extraire mes infos , mais oui cette fonction n'as pas en jdom.
    - Tu traites les parents deux fois par appel : la première en tant que voisin de l'élément qui le précède, la deuxième en tant que voisin du parent d'un élément. En récursif cela va forcément faire une explosion combinatoire.
    => ok donc c'est probablement la mon souci pourtant pour balayer tout je ne vois pas d'autres solutions
    1)fils
    2)suivant , si pas de fils
    3)remonter , si pas de fils, et pas de suivant
    d'autant plus que j'ai vérifié sur des petits fichiers, j'ai le bon nombre de résultats....


    - Oui, il y a une limite d'appels récursif. Oui, c'est dû à la taille mémoire de la pile (et accessoirement c'est pas désagréable de planter quand on part en boucle infinie involontaire.)
    =>ok, est-ce que cette limite est paramétrable ? ( option de lancement java, ou dans eclipse ?)
    ou alors est-il possible de "nettoyer la pile" ?

    - Pour imprimer le contenu d'un fichier XML, il y a plus simple, en effet. Il suffit d'écrire ce fichier XML sur la sortie au lieu de le faire dans un fichier. Il est aussi possible de n'aller chercher que les éléments qui nous intéressent, soit parcourant les éléments par leurs noms, soit en utilisant XPath. Mais il arrive parfois que les infos qu'on cherche soient trop compliquées à aller chercher autrement que de manière récursive. Dans ce cas, bah oui, il faut faire du récursif, mais il suffit de traiter chaque nœud et ses enfants, quel intérêt d'aller voir les voisins et parents ?
    => j'ai besoin, pour des questions de parenté des composants et d'héritage d'attributs, de pouvoir récup certaines informations , au niveau N et d'autre au niveau N+1 , et encore ...sous certaine condition
    - Je ne vois pas ce qui t'ennuie avec les "wtf".
    - Pour voir si un node est un élément, il suffit de vérifier if(node.getNodType() == Node.ELEMENT_NODE). Les comparaisons douteuses avec "#text" sont dispensables.
    => ok.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par pegazuss5 Voir le message
    =>le DOcument est en JDOM non ?
    Non, c'est clairement un org.w3c.dom.Document. pas de trace de JDOM.

    Citation Envoyé par pegazuss5 Voir le message
    d'autant plus que j'ai vérifié sur des petits fichiers, j'ai le bon nombre de résultats....
    En effet, je dis des bêtises, j'ai mal lu. La méthode n'est appelée qu'une fois par nœud et il n'y a pas d'explosion combinatoire.

    Par contre, elle est appelée à un niveau de récursion de plus pour chaque nœud, c'est-à-dire que la récursion sera aussi profonde que la taille de ton document. Il faut vraiment que le document soit gros pour que ça soit un problème, mais à la base, c'est complètement absurde comme façon de faire. Les appels récursifs ne doivent se faire que sur les enfants.

    Citation Envoyé par pegazuss5 Voir le message
    pourtant pour balayer tout je ne vois pas d'autres solutions
    1)fils
    2)suivant , si pas de fils
    3)remonter , si pas de fils, et pas de suivant
    1) fils numéro 1.
    2) fils numéro 2.
    3) fils numéro 3.
    4) fils numéro 4.
    ... Et ainsi de suite, pour tous les fils -_-°.
    Il n'y a aucun besoin de regarder les voisins ou les parents. Un élément sera géré par son propre parent, puisque le parent gère tous ses fils.

    Citation Envoyé par pegazuss5 Voir le message
    =>ok, est-ce que cette limite est paramétrable ? ( option de lancement java, ou dans eclipse ?)
    Holà stop. Un jour, quand tu seras un grand ingénieur d'intégration sur des machines complexes gérant des technologies cutting-edge, que tu inventeras des algorithmes de génie qui défient la logique du secteur telle qu'on la concevait avant toi, tu te retrouveras peut-être face à des stack dont la taille est insuffisante pour ton système génial. Ce jour-là, tu te demanderas sans doute s'il n'y a pas moyen de configurer la taille de la stack en Java*.

    D'ici là, quand tu te retrouves avec StackOverflowError, considère que ton système est mal fait : soit il part en récurrence infinie, soit, cas plus rare, il empile trop les choses et il fallait faire autrement. En partant du principe que tu as fait une erreur et que ce n'est pas les autres qui proposent des stack trop petites, tu ne tromperas jamais.

    * et tu verras que oui, on peut.

    Citation Envoyé par pegazuss5 Voir le message
    ou alors est-il possible de "nettoyer la pile" ?
    Oui, c'est ce qui se passe quand une récursion remonte au lieu de descendre...

    Citation Envoyé par pegazuss5 Voir le message
    => j'ai besoin, pour des questions de parenté des composants et d'héritage d'attributs, de pouvoir récup certaines informations , au niveau N et d'autre au niveau N+1 , et encore ...sous certaine condition
    Mais ça ce n'est pas une question de parcours. Si t'as besoin d'aller chercher ce qui est au niveau N+1 ou dans un voisin au niveau N, tu le feras à ce moment-là. Pour parcourir l'ensemble du document, par contre, il suffit de parcourir tous les enfants.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 16
    Points
    16
    Par défaut
    Okay, j'ai compris, en fait je m'infliger la gestion du dépilage, j'ai modifier grâce à tes conseils c'est bon ça passe.
    je suis passé sur des Element et du jdom/sax également.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Element racinedoc;
    SAXBuilder sxb = new SAXBuilder();
    document = sxb.build(xmlInputFile);
    racinedoc = document.getRootElement();
    getElementInformation(racinedoc,0,"");
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    private static void getElementInformation(Element element, int i,String string) 
    	{
    		List listItem = element.getContent();
    		Iterator i1 = listItem.iterator();
    		int cpt=0;
    		while(i1.hasNext())
    		{
    			try{
    				Element Item= (Element)i1.next();
    				/*for(int j=0;j<i;j++){System.out.print("#");}System.out.println(Item.getName());*/
                                    // Traitement d'extraction sous condition				
    				getElementInformation(Item,i+1,Item.getName()); 
     
    			}catch (java.lang.ClassCastException e) {
    					//catch vide quand l'élement n'est pas un element.... j'ai un Element sur deux ( l'autres c'est du Text) 
    			}
    		}
    	}
    c'est pas jojo, surtout au niveau du catch vide... mais c'est pour un one shot , pour l'instant ça conviendra, j'ai tout le traitement à faire à coté.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Fais plutôt comme ça -_-° :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    private static void getElementInformation(Element element, int i,String string) 
    {
      for(Element child : element.getChildren())
      {
        // Traitement d'extraction sous condition				
        getElementInformation(child, i+1, child.getName());
      }
    }
    Je sais que c'est pas très logique que quand on fait getChildren(), JDOM ne renvoient que des éléments. Alors que tout ce qui a un parent est enfant de ce parent : éléments, texte, processing instruction et autres.
    Mais c'est le choix de JDOM. Il suffit de s'en servir.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 16
    Points
    16
    Par défaut
    c'est plus/moins ce que que j'ai essayé d'écrire a ma deuxième tentative surtout que c'est plus jolie sans l'itérator
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     for(Element Item : element.getChildren())
    mais j'avais une erreur de conversion d'Objet en Element dans le for ...
    du coup je suis repassé sur un itérator , est j'ai du testé des choses et laissé getcontent au lieux de getchildren ..

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Ah bah oui, c'est logique quand on a une erreur de conversion -_-°. Il suffisait de ne pas avoir de conversion et remplacer Element item par Object o et faire un cast ensuite.

    Mais bon, éliminons l'erreur elle-même : je suppose que tu utilises JDOM 1. Utilise plutôt JDOM 2. Cette erreur venait du fait que JDOM 1 ne gère pas les génériques et ne pouvait donc pas renvoyer une List<Element>. JDOM 2 le fait.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 16
    Points
    16
    Par défaut
    Nickel tout fonctionne (comme j'ai parcouru un peu les topics /xml du forum et, j'ai vu/entendu parlé du jdom2 que tu conseilles souvent et je me suis dit, peut être que c'est pour le jdom2 … mais je l'avais pas dans mon repo et la boucle avec itérateur moche fonctionné et je voulais avancer sur la suite de mon extraction)

    Bref du coup là j'ai fait l'import du jdom2 dans mon Repo et j'ai fait la jolie boucle avec le for et tout fonctionne nickel !

    Vraiment merci, tu m'as aidé et j'ai bien appris !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. fonction récursive: erreur
    Par calla29 dans le forum Débuter
    Réponses: 3
    Dernier message: 16/05/2006, 11h51
  2. [VB6] XML, fonction récursive de recherche
    Par kboo dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 24/04/2006, 21h27
  3. [XSLT] fonction récursive à N niveaux
    Par Mike35 dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 10/03/2006, 12h30
  4. Fonction récursive renvoi sur page d'erreur
    Par peck dans le forum Langage
    Réponses: 1
    Dernier message: 23/12/2005, 10h08
  5. Problème de fonction récursive avec un TcxDBTreeList
    Par isachat666 dans le forum Composants VCL
    Réponses: 1
    Dernier message: 05/12/2005, 13h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo