XML-ből adatok kinyerése (shell) - updated

Sziasztok,

tudom, nem újdonság a kérdés, de elakadtam...
Röviden: van sok, nagy xml-em molbiol adatokkal, és ebből szeretnék néhány adatot kiemelni (most nagyon kellenének), és felfedeztem, hogy van xsltproc-om.
Egy egyszerű xslt-vel az adatok egy részét ki tudom szedni, de a továbblépés nem megy.

Ez volna az (egyik/példa) xml file:
http://pastebin.com/cbiNcpmg

Ez az az xslt, ami megy:
http://pastebin.com/XDr3tkyG

És itt jön, ami nem megy - az xsltproc hibával elszáll


xsltproc locus2.xsl WFS1\ \-\ 7466.xml                                          
locus2.xsl:20: parser error : Opening and ending tag mismatch: stylesheet line 1 and template
   </xsl:template>
                  ^
locus2.xsl:22: parser error : Extra content at the end of the document
   <xsl:template match="INSDFeature"/>
   ^
cannot parse locus2.xsl

Ez pedig - eddig - ez lenne:
http://pastebin.com/8QG6wCTy

A bajom az (és lehet, hogy a programé is), hogy egy szinten több azonos tag van (nyilván más névvel).
Egyrészt ezeket sem tudom, hogyan kell kiválasztani, másrészt a hibával sem boldogulok.

Ami nekem kéne, az a gén neve, az, hogy melyik kromoszómán található, meg a transzkript variánsok száma, meg helye ("join").

Elvesztem, segítséget kérnék!
Lakik erre XML guru? :)

köszönöm,
a

Hozzászólások

Oké, pici haladás :)
Azt még mindig nem tudom kiválasztani, hogy melyik azonos nevű, de más tartalmú tag-re lenne szükségem, de legalább megtaláltam, hogy miért nem ment a második script...

pl.


   {xsl:template match="INSDFeature"> 

nálam


   {xsl:template match="INSDFeature"/> 

volt, azaz a tag le volt zárva...
(elöl zárójelcsere, mert lenyelte a drupal a sort...)

Basszus... :)

Viszont a fenti kérdésre/problémára ha tud valaki okosat (akár link is jó!), azt megköszönném! :)

<-------
You can't grep on dead trees.

Szia,

a megoldás így saccra nem nehéz. Szívesen segítek, ha tudok. Ehhez azonban egy megjegyzés és egy kérés tartozik.

A megjegyzés az, hogy farigcsálhatsz éppen kézzel XSL-t, de ha parancssorból kell XML-t feldolgozni, akkor helyből xmlstarlet.

A kérés pedig: ahhoz, hogy meg tudjam csinálni a "szűrő" XPath kifejezéseket meg a kimenetet, kénytelen leszel programozói szintre lefordítani a kérdést, és leírni, hogy milyen elemeket akarsz kibányászni, mit mivel akarsz összekötni, és így tovább. Kicsit nagy nekem az ugrás a "transzkript variáns" és a tag-ek neve között.

Az xmlstarlet-re egy példa:


xmlstarlet sel -T \
  -t -m /INSDSet/INSDSeq \
    -v INSDSeq_locus \
    -o ' / '\
    -v INSDSeq_definition \
    -o ' / ' \
    -v INSDSeq_organism \
    -n \
pelda.xml 

Kimenet:


WFS1 - 7466 / WFS1: Wolfram syndrome 1 (wolframin) / Homo sapiens

Az xmlstarlet persze XSL-t generál belül; ezt meg is lehet jeleníteni, ha a -T kapcsoló helyett a -C-t adjuk meg, és elhagyjuk a feldolgozandó file-t:


xmlstarlet sel -C \
  -t -m /INSDSet/INSDSeq \
    -v INSDSeq_locus \
    -o ' / '\
    -v INSDSeq_definition \
    -o ' / ' \
    -v INSDSeq_organism \
    -n

A kimenet:


<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:exslt="http://exslt.org/common"
 xmlns:math="http://exslt.org/math"
 xmlns:date="http://exslt.org/dates-and-times"
 xmlns:func="http://exslt.org/functions"
 xmlns:set="http://exslt.org/sets"
 xmlns:str="http://exslt.org/strings"
 xmlns:dyn="http://exslt.org/dynamic"
 xmlns:saxon="http://icl.com/saxon"
 xmlns:xalanredirect="org.apache.xalan.xslt.extensions.Redirect"
 xmlns:xt="http://www.jclark.com/xt"
 xmlns:libxslt="http://xmlsoft.org/XSLT/namespace"
 xmlns:test="http://xmlsoft.org/XSLT/"
 extension-element-prefixes="exslt math date func set str dyn saxon xalanredirect xt libxslt test"
 exclude-result-prefixes="math str">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:param name="inputFile">-</xsl:param>
<xsl:template match="/">
  <xsl:call-template name="t1"/>
</xsl:template>
<xsl:template name="t1">
  <xsl:for-each select="/INSDSet/INSDSeq">
    <xsl:value-of select="INSDSeq_locus"/>
    <xsl:value-of select="' / '"/>
    <xsl:value-of select="INSDSeq_definition"/>
    <xsl:value-of select="' / '"/>
    <xsl:value-of select="INSDSeq_organism"/>
    <xsl:value-of select="'&#10;'"/>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Aha, bambiztam még egy kicsit a példa XML-t, így megsejtettem, mit akarsz. Alkalmunk nyílik az XPath predikátumokat használni.


xmlstarlet sel -T -t -m /INSDSet/INSDSeq/INSDSeq_feature-table \
  -o 'gen=' \
  -m INSDFeature[INSDFeature_key="'gene'"]/INSDFeature_quals/INSDQualifier[INSDQualifier_name="'gene'"] \
      -v INSDQualifier_value -b \
  -o ' kromoszoma=' \
  -m INSDFeature[INSDFeature_key="'source'"]/INSDFeature_quals/INSDQualifier[INSDQualifier_name="'chromosome'"] \
      -v INSDQualifier_value -b \
  -o ' mRNA_join#=' \
  -v "count(INSDFeature[INSDFeature_key='mRNA' and INSDInterval_operator='join'])" \
  -n \
  -m "INSDFeature[INSDFeature_key='mRNA' and INSDInterval_operator='join']" \
    -o '  mRNA_join[' -v "position()"  -o ']=' -v INSDFeature_location -n -b \
pelda.xml

Itt a kimenet:


gen=WFS1 kromoszoma=4 mRNA_join#=2
  mRNA_join[1]=join(1..165,7602..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..33416)
  mRNA_join[2]=join(1..165,7606..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..33416)

Az érdemi XSLT-k:


<xsl:template match="/">
  <xsl:call-template name="t1"/>
</xsl:template>
<xsl:template name="t1">
  <xsl:for-each select="/INSDSet/INSDSeq/INSDSeq_feature-table">
    <xsl:value-of select="'gen='"/>
    <xsl:for-each select="INSDFeature[INSDFeature_key='gene']/INSDFeature_quals/INSDQualifier[INSDQualifier_name='gene']">
      <xsl:value-of select="INSDQualifier_value"/>
    </xsl:for-each>
    <xsl:value-of select="' kromoszoma='"/>
    <xsl:for-each select="INSDFeature[INSDFeature_key='source']/INSDFeature_quals/INSDQualifier[INSDQualifier_name='chromosome']">
      <xsl:value-of select="INSDQualifier_value"/>
    </xsl:for-each>
    <xsl:value-of select="' mRNA_join#='"/>
    <xsl:value-of select="count(INSDFeature[INSDFeature_key='mRNA' and INSDInterval_operator='join'])"/>
    <xsl:value-of select="'&#10;'"/>
    <xsl:for-each select="INSDFeature[INSDFeature_key='mRNA' and INSDInterval_operator='join']">
      <xsl:value-of select="'  mRNA_join['"/>
      <xsl:value-of select="position()"/>
      <xsl:value-of select="']='"/>
      <xsl:value-of select="INSDFeature_location"/>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:for-each>
</xsl:template>

Aha.
Köszönöm!
Tényleg nagyon elegáns és szép az xmlstarlet. Igazából azért nyúltam az xsltproc-hoz, mert Solaris/Gnome alatt ez garantáltan ott van. Most néztem a linket, az xmlstarlet-et meg is néztem, de xml-előképzettség nélkül bonyinak tűnt :) (- Mondjuk az xslt is :)), viszont Sol alá le kéne fordítani (OpenCSW-t nem használok)

Minden estre indulásnak nagyon nagy segítséget kaptam, ezúton is nagyon köszönöm!

Még egy apróság (-nak tűnő dolog, de lehet, hogy nem az...):
Ha egyelőre maradok az xslt-nél: hogyan lehet megoldani, hogy a ne egy fajta tag-et listázzon, majd a következőt, hanem az infókat "struktúráljam".
A fenti példánál maradva:
Ez az alábbi kód működik:
http://pastebin.com/eyzkmFpx

ez a kimenete:
http://pastebin.com/XJ10y0v8

viszont a db_xref sorok nem kellenek (ami egyébként ugye egy olyan tag-ben van, aminek a tartalma amúgy máshol kell), és szeretném alájuk betenni az INSDInterval_from és INSDInterval_to tagek értékét.
Tehát valami olyasmi kimenetet szeretnék, hogy:


	      WFS1: Wolfram syndrome 1 (wolframin) 
              Homo sapiens 
              1..33416 
              mol_type  |  genomic DNA 
              chromosome  |  4 
               
              1..33416 
              gene  |  WFS1 
              note  |  Derived by automated computational analysis using gene prediction method: BestRefseq. 

               
              join(1..165,7602..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..33416) 
              product  |  Wolfram syndrome 1 (wolframin), transcript variant 1 
              note  |  Derived by automated computational analysis using gene prediction method: BestRefseq. 
 		from=1 to=165
		from=7602 to=7838
		from=17244 to=17326
		.
		.
		from= ... to= ...
               
              join(1..165,7606..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..33416) 
              product  |  Wolfram syndrome 1 (wolframin), transcript variant 2 
              note  |  Derived by automated computational analysis using gene prediction method: BestRefseq. 
              	from=1 to=165
		from=7606 to=7838
		from=17244 to=17326
		.
		.
		from= ... to= ...
               
              join(7607..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..32619) 
              note  |  Derived by automated computational analysis using gene prediction method: BestRefseq. 
		from=7607 to=7838
		from=17244 to=17326
		.
		.
		from= ... to= ...
               
              join(7607..7838,17244..17326,19138..19282,21348..21518,22068..22148,25192..25340,30808..32619) 
              note  |  Derived by automated computational analysis using gene prediction method: BestRefseq. 
		from=7607 to=7838
		from=17244 to=17326
		.
		.
		from= ... to= ...

Ezzel már shellből is elboldogulok (egrep rulz :)), tehát nem nagy tragédia, de nyilván nem teljesen jól csinálom (~4 óra xml-tanulás után ennyire fussa... :)).

Sikerült _csak_ a from és to mezőket is kiszedni (igaz, az xsl-em nem tökéletes, ekkor csak ezek jelennek meg...), ekkor a lista ilyesmi lesz:


FS1: Wolfram syndrome 1 (wolframin) 
              Homo sapiens 
              1 - 33416 
               -    
              1 - 33416 
               -    
              1 - 165 
              7602 - 7838 
              17244 - 17326 
              19138 - 19282 
              21348 - 21518 
              22068 - 22148 
              25192 - 25340 
              30808 - 33416 
               -    
              1 - 165 
              7606 - 7838 
              17244 - 17326 
              19138 - 19282 
              21348 - 21518 
              22068 - 22148 
              25192 - 25340 
              30808 - 33416 
               -    
              7607 - 7838 
              17244 - 17326 
              19138 - 19282 
              21348 - 21518 
              22068 - 22148 
              25192 - 25340 
              30808 - 32619 
               -    
              7607 - 7838 
              17244 - 17326 
              19138 - 19282 
              21348 - 21518 
              22068 - 22148 
              25192 - 25340 
              30808 - 32619 

Ez az xslt pedig ez:
http://pastebin.com/hAdMtQrt

Uhh... szép hosszú post lett...

Köszönöm még egyszer a rám szánt időt és energiát! :)
a

<-------
You can't grep on dead trees.

hogyan lehet megoldani, hogy a ne egy fajta tag-et listázzon, majd a következőt, hanem az infókat "struktúráljam"

Ehhez most négy dolog jut eszembe. Semmi biztos, csak tippek: (1) az xmlstarlet "sel" módjának van --indent kapcsolója, (2) az xmlstarlet-ben van "fo" mód (Formatting XML documents), (3) az XSL template-nek XPath kifejezéssel lehet megadni, a match attribútumban, hogy mire ugorjon. Például ha match="//*", akkor azt a template-et az XSL feldolgozó minden node-ra rá fogja húzni. (A sorrendre most nem emlékszem a W3C TR-ből.) (4) Te magad is megcsinálhatod kézzel, ahogy fent én is "tabuláltam" a lista elemeit.

http://xmlstar.sourceforge.net/doc/UG/xmlstarlet-ug.html

http://www.w3.org/TR/xslt#section-Processing-Model