Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11

Discussione: Parsing file .gpx

  1. #1

    Parsing file .gpx

    In futuro dovrò realizzare un app per android in cui avrò necessità di aprire i file con estensione gpx e farne il parsing. I file gpx sono file xml che contengono latitudine, longitudine e altitudine di una sequenza di locazioni. Devo farne il parsing per potermi salvare le locazioni a coppie (o triple con l'altitudine) da cui tracciare il disegno su google maps.

    Esempio di file gpx:

    codice:
    <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
    <gpx xmlns="http://www.topografix.com/GPX/1/1" creator="CompeGPS" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
      <metadata>
        <link href="http://www.compegps.com">
          <text>CompeGPS TEAM, SL</text>
        </link>
        <time>2007-06-30T21:27:42Z</time>
        <bounds maxlat="40.132004" maxlon="15.831839" minlat="40.117588" minlon="15.801740"/>
      </metadata>
      <trk>
        <name>Monte Sirino-Papa - Discesa</name>
        <desc>Discesa Monte Sirino-Papa</desc>
        <trkseg>
          <trkpt lat="40.132004" lon="15.831839">
            <ele>1974.2</ele>
            <time>2007-06-20T13:00:00Z</time>
          </trkpt>
          <trkpt lat="40.131973" lon="15.831815">
            <ele>1971.8</ele>
            <time>2007-06-20T13:00:07Z</time>
          </trkpt>
          <trkpt lat="40.131897" lon="15.831679">
            <ele>1969.4</ele>
            <time>2007-06-20T13:00:32Z</time>
          </trkpt>
          <trkpt lat="40.131798" lon="15.831541">
            <ele>1967.0</ele>
            <time>2007-06-20T13:01:01Z</time>
          </trkpt>
    ....
    ....
    ....
    Per questo scopo mi conviene usare DOM o SAX? I file gpx possono essere molto lunghi, ma non sono profondi, quindi io direi che il DOM dovrebbe andare bene, però un parere da qualcuno più esperto potrebbe essere utile
    Ho sentito parlare anche di JSON ma non ho idea di cosa sia..

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    Per questo scopo mi conviene usare DOM o SAX? I file gpx possono essere molto lunghi, ma non sono profondi, quindi io direi che il DOM dovrebbe andare bene
    Dipende appunto da quanti dati ci sono. Se anche ci fossero 100 ... 200 ... 500 di quei <trkpt>, allora DOM potrebbe ancora andare bene.
    Se invece ce ne sono es. 20000, 50000, allora meglio SAX.

    Altra alternativa è usare un framework di data binding tra classi e XML (la API JAXB, la libreria Castor o altro). Ma bisogna vedere cosa usano "sotto" (se DOM, SAX o StAX).

    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    Ho sentito parlare anche di JSON ma non ho idea di cosa sia..
    JSON non centra nulla con XML, è un formato text-based che permette di rappresentare valori e strutture dati basilati utilizzando una sintassi che deriva da Javascript.
    La serializzazione in JSON è spesso una alternativa alla serializzazione in XML.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Leggo che si hanno problemi con il DOM quando i file xml cominciano a pesare qualche mb. Fino ad ora i file gpx che ho visto a stento raggiungono i 100 kb. Punto a favore per il DOM. Allo stesso tempo mi pare di capire che tramite il SAX è piuttosto semplice scartare gli elementi che non servono e considerare solo quelli che servono. Tra l'altro a me serve solo estrapolare le informazioni e non modificarle.

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    Leggo che si hanno problemi con il DOM quando i file xml cominciano a pesare qualche mb. Fino ad ora i file gpx che ho visto a stento raggiungono i 100 kb. Punto a favore per il DOM. Allo stesso tempo mi pare di capire che tramite il SAX è piuttosto semplice scartare gli elementi che non servono e considerare solo quelli che servono. Tra l'altro a me serve solo estrapolare le informazioni e non modificarle.
    Con SAX è facile scartare (o al contrario considerare) certi elementi, presi a sé stanti. Ma è più difficile gestire e tenere un "contesto" che fornisca informazioni tipo: a che livello di profondità si è arrivati, se un certo nodo è seguito da un altro nodo ben preciso, ecc... Perché sono cose da gestire espressamente "a mano" (SAX su questi aspetti non aiuta!).

    Con DOM hai semplicemente un ... albero e puoi "navigarci" dentro come vuoi, avanti, indietro, in profondità, ecc.... Ma appunto devi navigarci, cioè dovresti partire dal nodo radice, prendere la lista dei figli, dire es.: se un nodo figlio è <metadata> magari entri in un tuo metodo che scansiona e gestisce i suoi figli specifici, ecc....

    Altrimenti con DOM puoi usare XPath, che permette di "indirizzare" velocemente certi nodi usando una apposita espressione. A questo punto può essere utile (anzi è meglio..) fare un esempio. Anche perché nel tuo caso, nel documento .gpx c'è un inghippo un pochino rognoso: ovvero i namespace. Vedi che all'inizio c'è:

    <gpx xmlns="http://www.topografix.com/GPX/1/1" ....

    Vuol dire che c'è un namespace di "default" e tutti i tag gpx, metadata, link, trk, ecc... sono associati a questo namespace. E nella espressione XPath bisogna considerare i namespace: o direttamente (ma la espressione diventa mooolto complessa) o attraverso un prefisso, che però va "mappato" (con XPath di JAXP c'è la interfaccia NamespaceContext che non ha purtroppo implementazioni predefinite e bisogna farne una esplicita).

    Bene, dato il tuo file .gpx (per la mia prova ho solo chiuso i tag aperti, visto che non l'hai postato completo), ho scritto questo:

    codice:
    import java.util.*;
    import javax.xml.XMLConstants;
    import javax.xml.namespace.*;
    import javax.xml.parsers.*;
    import javax.xml.xpath.*;
    import org.w3c.dom.*;
    import org.xml.sax.*;
    
    public class LetturaGpx {
        public static void main(String[] args) {
            try {
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                DocumentBuilder builder = dbf.newDocumentBuilder();
    
                Document document = builder.parse("prova.gpx");
    
                XPathFactory xpf = XPathFactory.newInstance();
                XPath xpath = xpf.newXPath();
                xpath.setNamespaceContext(new GpxNamespaceContext());
    
                Object result = xpath.evaluate("/gpx:gpx/gpx:trk/gpx:trkseg/gpx:trkpt/gpx:time/text()",
                        document, XPathConstants.NODESET);
    
                NodeList list = (NodeList) result;
    
                for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
    
                    System.out.println(node.getNodeValue());
                }
            } catch (Exception e) {
                System.err.println(e);
            }
        }
    }
    
    
    class GpxNamespaceContext implements NamespaceContext {
        public String getNamespaceURI(String prefix) {
            if (prefix == null) {
                throw new IllegalArgumentException("prefix cannot be null");
            } else if (prefix.equals("gpx")) {
                return "http://www.topografix.com/GPX/1/1";
            } else {
                return XMLConstants.NULL_NS_URI;
            }
        }
    
        public String getPrefix(String namespaceURI) {
            return null;   // getPrefix non serve in questo caso
        }
    
        public Iterator getPrefixes(String namespaceURI) {
            return null;   // getPrefixes non serve in questo caso
        }
    }
    L'output è:
    2007-06-20T13:00:00Z
    2007-06-20T13:00:07Z
    2007-06-20T13:00:32Z
    2007-06-20T13:01:01Z


    Ovvero: ho selezionato tutti i nodi di "testo" che sono quelli contenuti nei <time> sotto <trkpt>.
    Ultima modifica di andbin; 14-10-2013 a 22:42
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Capito! Questo XPath sembra molto utile. Quindi se io volessi estrapolare solo gli attributi degli elementi <trkpt> (latitudine e longitudine) E l'elevazione dentro <ele> dovrei andare a modificare questa riga prima di tutto:

    codice:
    Object result = xpath.evaluate("/gpx:gpx/gpx:trk/gpx:trkseg/gpx:trkpt/gpx:time/text()",
                        document,XPathConstants.NODESET);
    
    Aggiornamento:

    Si a quanto pare

    codice:
    import java.util.*;
    import javax.xml.XMLConstants;
    import javax.xml.namespace.*;
    import javax.xml.parsers.*;
    import javax.xml.xpath.*;
    import org.w3c.dom.*;
    
    
    public class Main {
        
        public static void main(String [] args) {
            
            try {
                
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                DocumentBuilder builder = dbf.newDocumentBuilder();
    
    
                Document document = builder.parse("prova.gpx");
    
    
                XPathFactory xpf = XPathFactory.newInstance();
                XPath xpath = xpf.newXPath();
                xpath.setNamespaceContext(new GpxNamespaceContext());
    
    
                Object result = xpath.evaluate("/gpx:gpx/gpx:trk/gpx:trkseg/gpx:trkpt",
                        document, XPathConstants.NODESET);
                
                NodeList list = (NodeList) result;
    
    
                for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    NamedNodeMap nnm = node.getAttributes();
                    System.out.println(nnm.item(0) + " " + nnm.item(1));
                }
            }
            
            catch (Exception e) {
                System.err.println(e);
            }
        }
    }
    
    
    class GpxNamespaceContext implements NamespaceContext {
        public String getNamespaceURI(String prefix) {
            if (prefix == null) {
                throw new IllegalArgumentException("prefix cannot be null");
            } else if (prefix.equals("gpx")) {
                return "http://www.topografix.com/GPX/1/1";
            } else {
                return XMLConstants.NULL_NS_URI;
            }
        }
    
    
        public String getPrefix(String namespaceURI) {
            return null;   // getPrefix non serve in questo caso
        }
    
    
        public Iterator getPrefixes(String namespaceURI) {
            return null;   // getPrefixes non serve in questo caso
        }
    }
    Così ottengo questo output:

    codice:
    lat="40.132004" lon="15.831839"
    lat="40.131973" lon="15.831815"
    lat="40.131897" lon="15.831679"
    lat="40.131798" lon="15.831541"
    lat="40.131794" lon="15.831545"
    lat="40.131699" lon="15.831446"
    lat="40.131588" lon="15.831304"
    lat="40.131523" lon="15.831274"
    lat="40.131458" lon="15.831181"
    lat="40.131420" lon="15.831067"
    lat="40.131325" lon="15.830970"
    lat="40.131233" lon="15.830803"
    lat="40.131088" lon="15.830819"
    lat="40.131023" lon="15.830804"
    lat="40.131016" lon="15.830626"
    lat="40.131020" lon="15.830546"
    lat="40.131023" lon="15.830420"
    lat="40.131008" lon="15.830357"
    lat="40.130939" lon="15.830152"
    lat="40.130798" lon="15.829922"
    lat="40.130768" lon="15.829756"
    lat="40.130703" lon="15.829603"
    lat="40.130653" lon="15.829369"
    ...
    ...
    ...
    L'unica cosa ora è come dire nel path di prendere anche l'elevazione. Devo creare un altro oggetto Object result2 = xpath.evaluate..?
    Ultima modifica di Javino89; 15-10-2013 a 09:33

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    codice:
                for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    NamedNodeMap nnm = node.getAttributes();
                    System.out.println(nnm.item(0) + " " + nnm.item(1));
                }
            }
    Tecnicamente è corretto, poiché il node è realmente un org.w3c.dom.Element (hai selezionato i tag <trkpt>) e quindi getAttributes() restituisce la mappa (altrimenti, come da documentazione, se non è un Element restituisce null).

    Però non prendere gli attributi per indice (non c'è garanzia di un ordine preciso) ma per nome.

    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    L'unica cosa ora è come dire nel path di prendere anche l'elevazione. Devo creare un altro oggetto Object result2 = xpath.evaluate..?
    Sì, per ogni trkpt (quindi nel for), puoi fare un ulteriore evaluate specificando:
    - come nodo di "contesto" (2° parametro di evaluate) il node del trkpt
    - come espressione il tag ele, nota senza slash '/' perché parti già dal nodo del trkpt (se vuoi puoi prendere subito il testo con text() )
    - come tipo, se prendi subito il testo puoi usare XPathConstants.STRING, l'Object che ottieni è già il contenuto di <ele>
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Non ho capito molto il secondo parametro.

    Ho scritto questo:

    codice:
    for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    Object localResult = xpath.evaluate("ele", node , XPathConstants.STRING);
                    NamedNodeMap nnm = node.getAttributes();
                    //System.out.println(nnm.getNamedItem("lat") + " " + nnm.getNamedItem("lon"));
                    String altitudine = localResult.toString();
                    System.out.println(altitudine);
                }
    Ma non mi stampa nulla..

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    Non ho capito molto il secondo parametro.
    codice:
    for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    Object localResult = xpath.evaluate("ele", node , XPathConstants.STRING);
                    NamedNodeMap nnm = node.getAttributes();
                    //System.out.println(nnm.getNamedItem("lat") + " " + nnm.getNamedItem("lon"));
                    String altitudine = localResult.toString();
                    System.out.println(altitudine);
                }
    Il secondo parametro l'hai messo corretto, è appunto il node (Element) del <trkpt> che fa da "contesto" di partenza. Quello che non è corretto è la espressione, solo "ele" non basta (anche perché vuoi prendere il text dentro <ele>):

    "gpx:ele/text()"

    gpx: perché c'è sempre di mezzo il namespace, e text() perché così (anche grazie al XPathConstants.STRING) prendi subito il testo (String) piuttosto che il nodo di testo.

    Per lat/lon ricorda che getNamedItem("lat") restituisce il node dell'attributo (org.w3c.dom.Attr) non un java.lang.String ! Quindi devi prendere il value del nodo Attr.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    Fatto!

    codice:
     for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    NamedNodeMap nnm = node.getAttributes();
                    Node latitudine = nnm.getNamedItem("lat");
                    Node longitudine = nnm.getNamedItem("lon");
                    Object altitudine = xpath.evaluate("gpx:ele/text()", node , XPathConstants.STRING);
                    System.out.println(latitudine.getNodeValue() + " " + longitudine.getNodeValue() + " " + altitudine);
                }
    Così dovrebbe andar bene. Chiedo solo un'altra cosa. Per creare poi il percorso, mi conviene creare una classe che so, Posizione, che contiene latitudine, longitudine ed altitudine, inserire tutte le posizioni in una lista, e scorrere la lista prelevando le posizioni a coppie in modo da disegnare una linea fra i due punti? E' giusto come approccio?

  10. #10
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Javino89 Visualizza il messaggio
    Per creare poi il percorso, mi conviene creare una classe che so, Posizione, che contiene latitudine, longitudine ed altitudine, inserire tutte le posizioni in una lista, e scorrere la lista prelevando le posizioni a coppie in modo da disegnare una linea fra i due punti? E' giusto come approccio?
    Sì, se quelle 3 informazioni rappresentano appunto una "entità" precisa (un "punto") che dovrai riusare altrove, meglio modellare la cosa con una classe apposita. Di cui ovviamente puoi avere poi un array, lista, quello che vuoi.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.