Search code examples
xmlstx

STX: How to process elements that have a more higher level than a matched element has?


...or maybe somehow get child's content?

Hi guys, I'm using STX because I've got huge XML files.

I have some input

<?xml version="1.0" encoding="UTF-8"?>
<ME>
  <DataContainer id="1">
    <attributes>
      <DataType>vsDataF</DataType>
      <vsDataF>
        <label>lable-F</label>
        <zzz>100</zzz>
      </vsDataF>
    </attributes>
    <DataContainer id="1">
      <attributes>
        <DataType>vsData1</DataType>
        <vsData1>
          <label>lable-1</label>
          <zzz>1000</zzz>
        </vsData1>
      </attributes>
    </DataContainer>
    <DataContainer id="1">
      <attributes>
        <DataType>vsData2</DataType>
        <vsData2>
          <label>lable-2</label>
          <zzz>2000</zzz>
        </vsData2>
      </attributes>
    </DataContainer>
  </DataContainer>
  <DataContainer id="2">
    <attributes>
      <DataType>vsDataG</DataType>
      <vsDataG>
        <label>lable-G</label>
        <zzz>200</zzz>
      </vsDataG>
    </attributes>
</ME>

and I need to get such output

<?xml version="1.0" encoding="UTF-8"?>
<main>
  <vsDataF>
    <id>1</id>
    <label>lable-F</label>
    <zzz>100</zzz>
    <vsData1>
      <id>1</id>
      <label>lable-1</label>
      <zzz>1000</zzz>
    </vsData1>
    <vsData2>
      <id>1</id>
      <label>lable-2</label>
      <zzz>2000</zzz>
    </vsData2>
  </vsDataF>
  <vsDataG>
    <id>2</id>
    <label>lable-G</label>
    <zzz>200</zzz>
  </vsDataG>
</main>

I wrote a transform that does it partly

<stx:transform
  version="1.0"
  xmlns:stx="http://stx.sourceforge.net/2002/ns"
  output-method="xml">

  <stx:variable name="table_name"/>

  <stx:template match="/">
    <main>
      <stx:process-children/>
    </main>
  </stx:template>

  <!-- DataContainters -->
  <stx:template match="ME/DataContainer/attributes/DataType">
    <stx:assign name="table_name" select="."/>
    <stx:element name="{$table_name}">
      <id>
        <stx:value-of select="../../@id"/>
      </id>
    </stx:element>
  </stx:template>

</stx:transform>

I know, there are few stx:process, for example stx:process-children, stx:process-self, stx:process-siblings, but this case it's does not work.


Solution

  • I've solved this problem. I learned how stx:group and stx:buffer work, it was difficult for me, but I managed to do it.

    <stx:transform
      version="1.0"
      xmlns:stx="http://stx.sourceforge.net/2002/ns"
      output-method="xml">
    
      <stx:variable name="table_name"/>
      <stx:buffer name="columns"/>
    
      <stx:template match="/">
        <main>
          <stx:process-children/>
        </main>
      </stx:template>
    
      <stx:group name="copy-all" pass-through="all"/>
    
      <!-- Columns -->
      <stx:template match="DataContainer/attributes/*[2]/*">
        <stx:element name="{local-name()}">
          <stx:value-of select="."/>
        </stx:element>
      </stx:template>
    
      <!-- DataType --> 
      <stx:template match="DataContainer/attributes/*[2]">
        <stx:assign name="table_name" select="local-name()"/>
        <stx:result-buffer name="columns" clear="yes">
          <stx:process-children/>
        </stx:result-buffer>
      </stx:template>
    
      <!-- DataContainer -->
      <stx:template match="DataContainer/*[1]" priority="2">
        <stx:process-self/>
        <stx:element name="{$table_name}">
          <id>
            <stx:value-of select="../@id"/>
          </id>
          <stx:process-buffer name="columns" group="copy-all"/>
          <stx:process-siblings/>
        </stx:element>
      </stx:template>
    
    </stx:transform>