Newsgroup: it.comp.os.linux.iniziare
Titolo: Conversione da XML a CSV

... O meglio, a "TSV", "tab separated values".
Dunque, ho un file XML in cui sono archiviati dei dati, in cui ogni singolo
record è strutturato così:
  <entry>
   <title>titolo</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
Ho bisogno di convertirlo in un file di testo con un record per riga, e con
i valori separati da tabulazione, più o meno così:
titolo  valore 1        valore 2        valore 3
Non mi serve prelevare tutti i valori, ma solo alcuni (per intenderci, non
mi interessa value4). 
È la prima volta che mi trovo a fare qualcosa del genere, e non so che
strategie adottare, sapete darmi qualche dritta? Cosa posso usare?
Mi so orientare piuttosto bene con i tool standard unix come bash, awk, sed
e simili, e conosco un pochino di PHP e un pochino di meno di python.
grazie a chiunque sappia orientarmi un po'.
ciao
gerlos
-- 
"Solo lo scienziato è vero poeta: ci dà la luna, ci promette le stelle,
 ci farà un nuovo universo se sarà il caso."
                 < 
http://gerlos.altervista.org
 >
 gerlos  +- - - >  gnu/linux registred user #311588

 sed e simili, e conosco un pochino di PHP e un pochino di meno di python.
Se il formato e' esattamente quello che mostri, un breve script awk puo'
fare al caso tuo, esempio:
awk '/<\/entry>/ {print line;line=sep="";p=0}
    p {gsub(/(^[[:space:]]*)?<[^>]*>|/,"");line = line sep $0; sep="\t"}
    /<entry>/ {p=1}' file.xml
Questa puo' essere una base di partenza (prende tutti i valori), assumendo
che la struttura del file sia esattamente come tu mostri. Modificando la
seconda riga, puoi perfezionarlo.

 Cosa posso usare?
Con xsltproc e un semplice file XSLT dovrebbe essere possibile.
Y.

 
manda questo script così : 
./script.py nomefile.xml
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import xml.sax,sys
import pprint
class BookHandler(xml.sax.handler.ContentHandler):
	def __init__(self):
		self.buffer = ""
	def startElement(self, name, attributes):
		pass
	def characters(self, data):
		if len(data.strip(" \t\n\r")):
			if data.strip(" \t\n\r") =="valore 4" : return
 
			self.buffer += data.strip(" \t\n\r")+"\t"
	def endElement(self, name):
		if name == "entry":
			print self.buffer.strip('\t')
			self.buffer=""
if __name__ == '__main__':
	parser = xml.sax.make_parser(  )
	handler = BookHandler(  )
	parser.setContentHandler(handler)
	parser.parse(sys.argv[1])
	"""
	esempio di file xml
	<main>
	<entry>
   <title>titolo</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
	<entry>
   <title>titolo 2</title>
   <value1>valore 12</value1>
   <value2>valore 13</value2>
   <value3>valore 13</value3>
   <value4>valore 14</value4>
  </entry>
	</main>
	"""

 XSLT
Wow, non lo conoscevo!!! Spettacolare!!! Sono riuscito ad ottenere quel che
mi serviva, ma ora che ho "assaggiato" la cosa mi si è acceso l'appetito, e
magari faccio un'altra domanda, mentre leggo la documentazione...
Dunque, per essere più precisi, la struttura del mio file xml è un pelino
più complessa di quel che ho detto prima (non credevo fosse così facile
manipolarli!). In particolare, i record sono raggruppati in
diversi "gruppi" o meglio, categorie:
<group>
  <title>Titolo gruppo 1</title>
  <entry>
   <title>titolo</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
  <entry>
        ...
  </entry>
</group>
<group>
  <title>Titolo gruppo 2</title>
  <entry>
        ...
  </entry>
</group>
Con questo file XLT "primitivo" ho ottenuto quel che mi serviva
originariamente:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform
">
<xsl:template match="/">
        <xsl:for-each select=group/entry">
                <xsl:value-of
select="title"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value1"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value2"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value3"/><xsl:text>&#10;</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Il risultato ha la forma desiderata:
titolo  valore 1        valore 2        valore 3
Adesso mi piacerebbe aggiungere il titolo del gruppo in ultima colonna,
così:
titolo  valore 1        valore 2        valore 3        gruppo
Come posso fare? Se la risposta è (giustamente) rtfm, potete almeno darmi un
link utile?
Io in questo momento sto gironzolando tra i tutorial di
http://www.w3schools.com
grazie ancora




intanto dovresti cambiare i tag che così non sono corretti 
 <main>
<group>
  <grouptitle>Titolo gruppo 1</grouptitle>
  <entry>
   <title>titolo</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
  <entry>
   <title>titolo 2</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
</group>
<group>
  <grouptitle>Titolo gruppo 2</grouptitle>
  <entry>
   <title>titolo 3</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
  <entry>
   <title>titolo 4</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
</group>
</main>
poi modificare lo script che ti ho dato così:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import xml.sax,sys
import pprint
class BookHandler(xml.sax.handler.ContentHandler):
	def __init__(self):
		self.buffer = ""
 
self.gt
=0
	def startElement(self, name, attributes):
		if name == "grouptitle":
 
self.gt
=1
		pass
	def characters(self, data):
		if 
self.gt
:
			self.grouptitle=data.strip(" \t\n\r")
 
self.gt
=0
			return
		if len(data.strip(" \t\n\r")):
			if data.strip(" \t\n\r") =="valore 4" : return
 
			self.buffer += data.strip(" \t\n\r")+"\t"
	def endElement(self, name):
		if name == "entry":
			print self.buffer+self.grouptitle
			self.buffer=""
if __name__ == '__main__':
	parser = xml.sax.make_parser(  )
	handler = BookHandler(  )
	parser.setContentHandler(handler)
	parser.parse(sys.argv[1])
	"""
	esempio di file xml
	<main>
	<entry>
   <title>titolo</title>
   <value1>valore 1</value1>
   <value2>valore 2</value2>
   <value3>valore 3</value3>
   <value4>valore 4</value4>
  </entry>
	<entry>


    <title>titolo</title>
[CUT]
Dimenticavo di aggiungere che l'elemento <database> è l'elemento "genitore"
di tutti gli altri, dunque la struttura tipo è:
<database>
<group>
        <title>Titolo gruppo</title>
        <entry>
                <title>Titolo entry</title>
                <value1>Valore 1</value1>
                ...
        </entry>
</group>
<group>
        ...
</group>
</database>
Leggendo la documentazione ho trovato la soluzione: parent::group/title
Ecco il file xlt:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform
">
<xsl:template match="/">
        <xsl:for-each select=database/group/entry">
                <xsl:value-of
select="title"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value1"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value2"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="value3"/><xsl:text>&#9;</xsl:text><xsl:value-of
select="parent::group/title"/><xsl:text>&#10;</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Con il comando
xsltproc data2tsv.xsl data.xml > data.tsv
Ottengo il risultato desiderato (in realtà gli devo tagliar via la prima
riga, ma è facile da fare).
@RedWiz: Grazie per il tuo contributo, ora lo provo! Purtroppo non conosco
un gran ché python (ma è nella mia lista di cose da imparare!), e di solito
preferisco arrabbattarmi con quel che conosco o riesco a capire con quel
poco che conosco.
Scusa l'ignoranza (sto cercando di imparare), perché dici che i tag non sono
corretti? Purtroppo la strada "correggili" non è proprio immediata, nel
file originale ci sono alcune centinaia di righe... :-(
grazie a tutti


 immediata, nel file originale ci sono alcune centinaia di righe... :-(
con una semplice modifica allo script si puo' ovviare al poblema (se hai
intenzione di usarlo chiedimi quale), in ogni caso in generale , in futuro
cerca di stare attento a cose del genere quando sei in fase di creazione
del flusso (sempre che sa tu ad usarlo)

> import pprint
questa riga non serve, toglila pure
mi era rimasta dall'esempio che ho usato