Parser XML Urgente!!!

Area di discussione libera.

Moderatore: Staff

Regole del forum
1) Rispettare le idee altrui.
2) Evitare le offese dirette.
3) Leggere attentamente le risposte ricevute
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Night_Watch
Linux 2.x
Linux 2.x
Messaggi: 230
Iscritto il: lun 30 gen 2006, 2:30
Località: Martina Franca (TA)

Parser XML Urgente!!!

Messaggio da Night_Watch »

Ciao a tutti.

Ho un piccolo problema. Devono estrarre da un file XML il contenuto di due campi. Il linguaggio che devo usare è Java (sto provando con le API jdom + SAX ma non riesco). Il file XML è: http://www.nlm.nih.gov/databases/dtd/medline_sample.xml

I campi di cui devo estrarre il contenuto sono:

ArticleTitle
AbstractText

Grazie a tutti per l'aiuto.

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Il modo + veloce:

Codice: Seleziona tutto

import java.io.*;
import java.lang.*;
import java.util.*;
public class Prova{

public static void main(String[] args)throws IOException{
BufferedReader f=new BufferedReader(new FileReader("a.xml"));
String s=f.readLine();
StringTokenizer token;
 while(s!=null){
	if(s.startsWith("<ArticleTitle>")){
		System.out.println("Titolo:");
		System.out.println(s.substring(14, s.length()-15));
	}
	if(s.startsWith("<AbstractText>")){
		System.out.println("Abstract:");
		System.out.println(s.substring(14, s.length()-15));
	}
	s=f.readLine();
	}
	f.close();
 }
}
Controlla se e' giusto. L'ho buttato giu' in un paio di minuti.
Credo inoltre che se hai problemi di performance ti conviene usare la classe String.
Avevo letto dei benchmark tempo fa' in cui risultava + efficiente la classe String. Anche se per xml complessi e' meglio usare le classi apposite.

sir_alex
Linux 3.x
Linux 3.x
Messaggi: 735
Iscritto il: lun 21 mar 2005, 0:00
Kernel: 2.6.35-22
Desktop: KDE4
Distribuzione: Ubuntu
Località: Milano - Corbola (RO)
Contatta:

Messaggio da sir_alex »

Per XML invece (necessita di java6 o in alternativa java5+stax):

Codice: Seleziona tutto

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

public class XmlExtractor
{
	private URL address=null;
	private ArrayList<Container> data=null;

	public XmlExtractor(String address) throws MalformedURLException
	{
		this.address=new URL(address);
		data=new ArrayList<Container>();
	}

	public static void main(String[] args)
	{
		try
		{
			XmlExtractor ext=new XmlExtractor("http://www.nlm.nih.gov/databases/dtd/medline_sample.xml");
			ext.parse();
			for(Object o: ext.getData())
				System.out.println(o);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private ArrayList<Container> getData()
	{
		return data;
	}

	private void parse() throws IOException, XMLStreamException
	{
		Container c=null;
		String temp1=null, temp2=null;
		URLConnection conn=address.openConnection();
		InputStream in=conn.getInputStream();
		XMLStreamReader doc=XMLInputFactory.newInstance().createXMLStreamReader(in);
		for(int event=doc.next(); event!=XMLStreamConstants.END_DOCUMENT; event=doc.next())
		{
			switch(event)
			{
				case XMLStreamConstants.START_ELEMENT:
					temp1=doc.getLocalName();
					if("ArticleTitle".equals(temp1))
					{
						c=new Container();
					}
					break;
				case XMLStreamConstants.CHARACTERS:
					temp2=doc.getText();
					if("ArticleTitle".equals(temp1) && !"\n".equals(temp2))
					{
						c.setArticleTitle(temp2);
					}
					else if("AbstractText".equals(temp1) && !"\n".equals(temp2))
					{
						c.setArticleAbstract(temp2);
					}
					// else da non specificare
					break;
				case XMLStreamConstants.END_ELEMENT:
					if("AbstractText".equals(doc.getLocalName()))
					{
						data.add(c);
					}
					break;
				// default da non specificare
			}
		}
	}
	
	private static class Container
	{
		private String articleTitle=null;
		private String articleAbstract=null;
		
		public Container()
		{
		}

		public Container(String articleTitle, String articleAbstract)
		{
			this.articleTitle = articleTitle;
			this.articleAbstract = articleAbstract;
		}
		
		public String getArticleTitle()
		{
			return articleTitle;
		}
		public void setArticleTitle(String articleTitle)
		{
			this.articleTitle = articleTitle;
		}
		public String getArticleAbstract()
		{
			return articleAbstract;
		}
		public void setArticleAbstract(String articleAbstract)
		{
			this.articleAbstract = articleAbstract;
		}
		
		public String toString()
		{
			return "Title: "+articleTitle+"\nAbstract: "+articleAbstract;
		}
		
	}
}

Night_Watch
Linux 2.x
Linux 2.x
Messaggi: 230
Iscritto il: lun 30 gen 2006, 2:30
Località: Martina Franca (TA)

Messaggio da Night_Watch »

Grazie tanto per le risposte.

x stan:

Il codice non dà errori in compilazione ma il problema è che la linea viene letta come:

Codice: Seleziona tutto

<ArticleTitle>Transcription regulation of the nir gene cluster encoding nitrite reductase of Paracoccus denitrificans involves NNR and NirI, a novel type of membrane protein.</ArticleTitle>
e quindi non riesce a rilevare il tag <ArticleTitle> o gli altri. Di conseguenza gli if non sono mai veri.

x sir_alex:

Il file lo scarico in locale.

Ma con le API jdom non sarebbe più semplice??
Il mio problema è che non riesco a far funzionare bene l'iterator e non riesco ad accedere ai nodi più interni. Per chiarezza posto il codice che sto provando:

Codice: Seleziona tutto

public class MedlineParser {

	public static void main(String[] args) {
		Document documento = null;
		SAXBuilder saxBuilder = new SAXBuilder();

		 try
		 {
		   documento = saxBuilder.build(new File("C://medline/medsamp2007.xml")); 
				 
		   Element e = documento.getRootElement();
		   Iterator itr = e.getChild("MedlineCitation").getChildren("Article").iterator();
		  
		   int i=0;
		   while (itr.hasNext()) {
		   		i++;
		   		System.out.println("Elemento n°: " +i);
		   		e = (Element) itr.next();
		   		String title = e.getChildText("ArticleTitle");
		   		System.out.println(title);
		   		String abstracttext = e.getChildText("Abstract");		 	
		 			
		 	OperazioniDB inserimento = new OperazioniDB();
		 	inserimento.inserisci(title, abstracttext);
		   }
		 }
		 catch (NullPointerException exc) {
		 	exc.printStackTrace();
       }		 
		 catch (Exception exc){
		 	exc.printStackTrace();
		 }
	}
}
Questo codice mi estrae solo un elemento cioè il contenuto del primo ArticleTitle e poi basta.

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Night_Watch ha scritto:Grazie tanto per le risposte.

x stan:

Il codice non dà errori in compilazione ma il problema è che la linea viene letta come:

Codice: Seleziona tutto

<ArticleTitle>Transcription regulation of the nir gene cluster encoding nitrite reductase of Paracoccus denitrificans involves NNR and NirI, a novel type of membrane protein.</ArticleTitle>
e quindi non riesce a rilevare il tag <ArticleTitle> o gli altri. Di conseguenza gli if non sono mai veri.
Non ho capito che intendi.
Io ho provato a scaricare il file.xml (ho salvato il page source del link che ci hai passato).
Ho compilato e lanciato. Mi sembra ok. :roll:

Night_Watch
Linux 2.x
Linux 2.x
Messaggi: 230
Iscritto il: lun 30 gen 2006, 2:30
Località: Martina Franca (TA)

Messaggio da Night_Watch »

Scusami hai ragione funziona!!!

Il problema è che stavo provando con un altro XML che sembra strutturato nello stesso modo e non funziona!!! Come è possibile??

Il file XML in questione è:

http://www.nlm.nih.gov/databases/dtd/medsamp2007.xml

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Beh si,
ad esempio se fai :

Codice: Seleziona tutto

if(s.startsWith("<ArticleTitle>")){
      System.out.println("Titolo:");
        String a=s.substring(14, s.length()-15);
      System.out.println(a);
   }
Che poi e' quello scritto qua:
http://java.sun.com/docs/books/tutorial ... types.html
In Java puoi fare:

Codice: Seleziona tutto

 String myString="Questa e' una stringa interessantissima";
L'oggetto di tipo String probabilmente non puo' memorizzare stringhe troppo lunghe.
Forse e' quello il tuo problema? Beh, in quel caso, magari puoi creare una collezione di Stringhe (usando la classe Vector e la classe Iterator, con opportuni cast, memorizzi e recuperi sottostringhe).
Boh, comunque quello che ti ho postato prima a me funge...quindi non saprei...[/code]

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Night_Watch ha scritto:Scusami hai ragione funziona!!!

Il problema è che stavo provando con un altro XML che sembra strutturato nello stesso modo e non funziona!!! Come è possibile??

Il file XML in questione è:

http://www.nlm.nih.gov/databases/dtd/medsamp2007.xml
Credo non funzioni perche' questo xml e' indentato. ;)

Night_Watch
Linux 2.x
Linux 2.x
Messaggi: 230
Iscritto il: lun 30 gen 2006, 2:30
Località: Martina Franca (TA)

Messaggio da Night_Watch »

Grazie veramente tanto stan per l'aiuto. Sei stato grande!!! ;)
stan ha scritto:Credo non funzioni perche' questo xml e' indentato.
Avresti una soluzione a livello di codice??

Cioè si potrebbe adattare quello che mi hai passato per farlo funzionare anche con questo tipo di XML??

O comunque cambiarlo quando mi serve in base al tipo di XML?? Infatti mi serve solo perchè devo mettere il contenuto dei due campi in un database MySQL e quindi in base all'esigenza commento e decommento le linee di codice che mi servono.

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Beh,
la prima cosa che mi viene in mente e':
Da Konsole fai:

Codice: Seleziona tutto

grep "<ArticleTitle>" a.xml |head -1
e poi conti a mano gli spazi che precedono <ArticleTitle> (professionale eh? :lol: )
Una volta contati editi Prova.java.
Supponiamo che conti 8 spazi:
Allora Prova.java diventa da cosi':

Codice: Seleziona tutto

if(s.startsWith("<ArticleTitle>")){
      System.out.println("Titolo:");
        String a=s.substring(14, s.length()-15);
      System.out.println(a);
   }
a cosi':

Codice: Seleziona tutto

   if(s.startsWith("        <ArticleTitle>")){
      System.out.println("Titolo:");
        String a=s.substring(22, s.length()-15);
      System.out.println(a);
   }
come vedi ho aggiunto degli spazi (nell'esempio 8 ) al metodo startsWith.
Ho poi modificato l 1o param di substring(14+8=22).
Ricordarti di fare tutto quello che ti ho scritto qua sopra anche x <AbstractText>.
Poi ricompili e lanci.

sir_alex
Linux 3.x
Linux 3.x
Messaggi: 735
Iscritto il: lun 21 mar 2005, 0:00
Kernel: 2.6.35-22
Desktop: KDE4
Distribuzione: Ubuntu
Località: Milano - Corbola (RO)
Contatta:

Messaggio da sir_alex »

Bè magari si fa prima, tra l'altro con DOM puoi fare il parsing dato che è un XML piccolo... c'è da dire che io nell'ultimo anno ho sempre usato SAX, quindi mi ricordo quello adesso come adesso!
La mia soluzione penso funzioni anche su XML simili, in fondo io cerco solo quei 2 tag, basta assicurarsi che venga prima il titolo dell'abstract! ;-)

Night_Watch
Linux 2.x
Linux 2.x
Messaggi: 230
Iscritto il: lun 30 gen 2006, 2:30
Località: Martina Franca (TA)

Messaggio da Night_Watch »

Ciao a tutti.

x sir_alex

Sapresti risolvere il mio problema modificando il pezzo di codice che ho postato in modo da usare SAX e JDOM??

Grazie.

sir_alex
Linux 3.x
Linux 3.x
Messaggi: 735
Iscritto il: lun 21 mar 2005, 0:00
Kernel: 2.6.35-22
Desktop: KDE4
Distribuzione: Ubuntu
Località: Milano - Corbola (RO)
Contatta:

Messaggio da sir_alex »

Night_Watch ha scritto:Ciao a tutti.

x sir_alex

Sapresti risolvere il mio problema modificando il pezzo di codice che ho postato in modo da usare SAX e JDOM??

Grazie.
Stasera ci guardo per dom...

[edit] Ma perchè bisogna per forza usare un jar esterno? Ma usare le librerie standard nel jdk no? :-)

Avatar utente
stan
Linux 3.x
Linux 3.x
Messaggi: 524
Iscritto il: lun 25 dic 2006, 11:55
Slackware: 12.1
Kernel: 2.6.xx
Desktop: Kde3
Località: Bs

Messaggio da stan »

Puoi anche prendere il mio codice e aggiungerci il codice per rimuovere l'indentazione.
Guarda le classi String e StringTokenizer.

Rispondi