Home > OS >  XSLT to parse XML and write out a flat file with a line feed after each parent segment
XSLT to parse XML and write out a flat file with a line feed after each parent segment

Time:05-17

I’m new to xslt and want to use it to just write out a flat file from the xml input below.

I also need a line feed after each parent segment

So this:

<?xml version="1.0" encoding="UTF-8"?>
<ns0:test xmlns:ns0="urn:mynamespace.com:test">
   <Header>
      <OderId>9876</OderId>
      <CustomerNo>Cust123</CustomerNo>
      <Item>
         <Product>N1234565</Product>
         <SubItem>
            <DelDate>20220601</DelDate>
            <Quantity>10</Quantity>
         </SubItem>
         <SubItem>
            <DelDate>20220602</DelDate>
            <Quantity>5</Quantity>
         </SubItem>
      </Item>
      <Item>
         <Product>N54321</Product>
         <SubItem>
           <DelDate>20220701</DelDate>
           <Quantity>3</Quantity>
         </SubItem>
         <SubItem>
            <DelDate>20220702</DelDate>
            <Quantity>17</Quantity>
         </SubItem>
      </Item>
   </Header>
</ns0:test>

Needs to produce this:

9876Cust123
N1234565
2022060110
202206025
N54321
202207013
2022070217

I’ll have way more fields than that but need to just write out everything within each parent and don’t want to specify each and every field.

Thanks Richard

CodePudding user response:

AFAICT, you want to do:

XSLT 2.0

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

<xsl:template match="/">
    <xsl:for-each select="//*[*/text()]">
        <xsl:value-of select="*/text()"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Note that this requires a processor that supports XSLT 2.0 or higher.
In XSLT 1.0, you could do something like:

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

<xsl:template match="/">
    <xsl:for-each select="//*[*/text()]">
        <xsl:for-each select="*/text()">
            <xsl:value-of select="."/>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Not sure what this format of jumbling unrelated data together is good for.

CodePudding user response:

You can use the following XSLT-1.0 stylesheet which uses the "text" output method:

<?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" omit-xml-declaration="yes" indent="no"/>
    <xsl:strip-space elements="*" />

    <xsl:template match="*[*]">
        <xsl:value-of select="'&#xa;'" />
        <xsl:apply-templates select="node()|@*" />
    </xsl:template>
    
</xsl:stylesheet>

The output still contains some empty lines, but these can be removed by piping the result through sed with

sed -e '/^$/d'

or some other command that removes empty lines from the output.

  • Related