Problem with repeat sub-node to transform a XML to a CSV with XSL

Viewed 21

I'm working on a transformation of a XML file to a CSV file.

See a piece of the XML :

<bota_form_v_20200610 xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:orx="http://openrosa.org/xforms" xmlns:odk="http://www.opendatakit.org/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:jr="http://openrosa.org/javarosa" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="fm_bota_2020" version="2020061000">
<start>2021-04-20T09:27:24.295+02:00</start>
<end>2021-04-20T10:18:51.038+02:00</end>
<deviceid>collect:JZUeuhzIlUe38qIl</deviceid>
<parcelle>
<identifier>Ab</identifier>
<sample_date>2021-04-20</sample_date>
<proto>farmland</proto>
<yes_no_parcelle_hza>no</yes_no_parcelle_hza>
<md_parcelle>18710002</md_parcelle>
<md_carre/>
<md_hauteur_vegetation>25</md_hauteur_vegetation>
<search_text_culture>Blé</search_text_culture>
<md_culture>Blé</md_culture>
<ocs>41</ocs>
</parcelle>
<quadrat_repeat>
<yes_no_md_numero_waypoint>no</yes_no_md_numero_waypoint>
<nom_gps>T12</nom_gps>
<md_numero_waypoint>264</md_numero_waypoint>
<md_sampling>in</md_sampling>
<point_sampling>in1</point_sampling>
<type_bordure>haie</type_bordure>
<zone>C1-H0-N0</zone>
<md_densite>12</md_densite>
<sous_quadrat_repeat_count>4</sous_quadrat_repeat_count>
<sous_quadrat_repeat>
<md_subquadrat>a</md_subquadrat>
<yes_no_diff_esp_plt>yes</yes_no_diff_esp_plt>
<esp_plt_rpt>
<search_text_plante_latin_rpt>Vero</search_text_plante_latin_rpt>
<md_plante_latin_rpt>Veronica-hederifolia</md_plante_latin_rpt>
<md_code_bayer_rpt>VERHE</md_code_bayer_rpt>
<md_abondance>2</md_abondance>
<md_stade_pheno>v</md_stade_pheno>
</esp_plt_rpt>

but with many 'quadrat_repeat' node which has each one many 'sous_quadrat_repeat' node and each of this node has some 'esp_plt_rpt' node.

I need one line for each 'esp_plt_rpt' sub node. And each of this line need to have all the attribute of their father (attribute of 'sous_quadrat_repeat', of 'quadra_repeat' and of parcelle"). like this :

Attr_Parc1    Attr_Parc2    Quadra_repeat1 ...   quadra_repeatN ... sous_quadrat_repeatN


And here my XSL (1.0) :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable name="sep" select="';'" />
  <xsl:variable name="nl" select="'&#xa;'" />

  <xsl:template match="bota_form_v_20200610">
<!--    <xsl:apply-templates select="quadrat_repeat/sous_quadrat_repeat"/> 
-->
<xsl:apply-templates select="quadrat_repeat"/> 
 </xsl:template>

  <xsl:template match="esp_plt_rpt">
    <xsl:value-of select="md_abondance" />
    <xsl:value-of select="$nl" />
  </xsl:template>




  <xsl:template match="sous_quadrat_repeat">
    <xsl:variable name="tmp">
      <xsl:value-of select="ancestor::bota_form_v_20200610/@id" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="ancestor::bota_form_v_20200610/quadrat_repeat/nom_gps" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="ancestor::bota_form_v_20200610/quadrat_repeat/md_sampling" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="ancestor::bota_form_v_20200610/quadrat_repeat/zone" />
      <xsl:value-of select="$sep" />

      <xsl:value-of select="ancestor::bota_form_v_20200610/quadrat_repeat/md_densite"/>
      <xsl:value-of select="$sep" />
    </xsl:variable>


    <xsl:for-each select="ancestor::bota_form_v_20200610/quadrat_repeat/sous_quadrat_repeat/esp_plt_rpt">
      <xsl:copy-of select="$tmp"/>

      <xsl:value-of select="ancestor::bota_form_v_20200610/quadrat_repeat/sous_quadrat_repeat/md_subquadrat"/>
      <xsl:value-of select="$sep" />
      <xsl:value-of select="md_plante_latin_rpt" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="md_stade_pheno" />
      <xsl:value-of select="$sep" />

      <xsl:apply-templates select="." />
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

This code don't take a new 'sous_quadrat_repeat' when he go to a new esp_pt_rpt. So all my line have the attribute of the first sous_quadrat_repeat node.

1 Answers

Your xslt was not far off. Good approach to store that repeatable data into a variable. I adjusted it a little to this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:variable name="sep" select="';'" />
  <xsl:variable name="nl" select="'&#xa;'" />
  
  <xsl:template match="bota_form_v_20200610">
    <xsl:apply-templates select="quadrat_repeat/sous_quadrat_repeat"/> 
  </xsl:template>
   
  <xsl:template match="sous_quadrat_repeat">
    <xsl:variable name="tmp">
      <xsl:value-of select="ancestor::bota_form_v_20200610/@id" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="parent::quadrat_repeat/nom_gps" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="parent::quadrat_repeat/md_sampling" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="parent::quadrat_repeat/zone" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="parent::quadrat_repeat/md_densite"/>
      <xsl:value-of select="$sep" />
      <xsl:value-of select="md_subquadrat"/>
      <xsl:value-of select="$sep" />
    </xsl:variable>    
    
    <xsl:for-each select="esp_plt_rpt">
      <xsl:value-of select="$tmp"/>
      <xsl:value-of select="md_plante_latin_rpt" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="md_stade_pheno" />
      <xsl:value-of select="$sep" />
      <xsl:value-of select="md_abondance" />
      <xsl:value-of select="$nl" />
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
Related