tarka
tarka

Reputation: 5587

Combining items using XSLT Transform

I have the following XML structure:

<row>
  <item>Controller</item>
</row>
<row>
  <item>****************</item>
</row>
<row>
  <item>Serial Number</item>
  <item>Name</item>
  <item>Controller index</item>
  <item>Firmware Version</item>
  <item> Product Rev.</item>
  <item>Mode</item>
  <item>Type</item>
  <item>ExtName</item>
  <item>Comment</item>
</row>
<row>
  <item>#0A384D3</item>
  <item>=&#34;AdventistBolingbrook&#34;</item>
  <item>0</item>
  <item>=&#34;7.0/2.1&#34;</item>
  <item>A00</item>
  <item>MA 1000 &amp; 2000</item>
  <item>Master</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>Base Unit</item>
</row>
<row>
  <item>****************</item>
</row>
<row>
  <item>Serial Number</item>
  <item>Name</item>
  <item>Controller Index</item>
  <item>Port Index</item>
  <item>Slot Index</item>
  <item>Firmware Version</item>
  <item>Product Rev.</item>
  <item>DL Input Power Status</item>
  <item>DL Power Interface Type</item>
  <item>DL AGC Status</item>
  <item>DL AGC Atten. Value</item>
  <item>DL DCA Manual Override</item>
  <item>DL Power</item>
  <item>UL Atten. Value</item>
  <item>ExtName</item>
  <item>Comment</item>
</row>
<row>
  <item>#0A3651B</item>
  <item>VZW BU              </item>
  <item>0</item>
  <item>1</item>
  <item>1</item>
  <item>=&#34;4.1&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>6</item>
  <item>6</item>
  <item>-21</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>#0A3651B</item>
  <item>VZW BU              </item>
  <item>0</item>
  <item>1</item>
  <item>2</item>
  <item>=&#34;4.1&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>7</item>
  <item>7</item>
  <item>-27</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>#50772EC</item>
  <item>                    </item>
  <item>0</item>
  <item>4</item>
  <item>1</item>
  <item>=&#34;5.3&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>2</item>
  <item>2</item>
  <item>-22</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>#50772EC</item>
  <item>                    </item>
  <item>0</item>
  <item>4</item>
  <item>2</item>
  <item>=&#34;5.3&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>3</item>
  <item>3</item>
  <item>-18</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>

And I need to transform it to:

<row>
  <item>Controller</item>
  <item>#0A384D3</item>
  <item>=&#34;AdventistBolingbrook&#34;</item>
  <item>0</item>
  <item>=&#34;7.0/2.1&#34;</item>
  <item>A00</item>
  <item>MA 1000 &amp; 2000</item>
  <item>Master</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>Base Unit</item>
  <item>#0A3651B</item>
  <item>VZW BU              </item>
  <item>0</item>
  <item>1</item>
  <item>1</item>
  <item>=&#34;4.1&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>6</item>
  <item>6</item>
  <item>-21</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>Base Unit</item>
  <item>#0A3651B</item>
  <item>VZW BU              </item>
  <item>0</item>
  <item>1</item>
  <item>2</item>
  <item>=&#34;4.1&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>7</item>
  <item>7</item>
  <item>-27</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>Base Unit</item>
  <item>#50772EC</item>
  <item>                    </item>
  <item>0</item>
  <item>4</item>
  <item>1</item>
  <item>=&#34;5.3&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>2</item>
  <item>2</item>
  <item>-22</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>
<row>
  <item>Base Unit</item>
  <item>#50772EC</item>
  <item>                    </item>
  <item>0</item>
  <item>4</item>
  <item>2</item>
  <item>=&#34;5.3&#34;</item>
  <item>N/A </item>
  <item>Normal</item>
  <item>RIU</item>
  <item>OFF</item>
  <item>3</item>
  <item>3</item>
  <item>-18</item>
  <item>0</item>
  <item></item>
  <item></item>
</row>

So what are the rules here...

  1. I only need to keep rows where the first item starts with a #. As an xpath this is expressed as //row/item[1][matches(.,"(#)")]/..
  2. Whenever I have a row where the first item starts with # I need to copy the first item from the row immediately preceding the first preceding sibling where the first item starts with ***.

Here is amore graphical version.

<row>
  <item>Controller</item>    <- I need to include this value into each of these
</row>                                                             |
<row>                                                              |
  <item>****************</item>                                    |
</row>                                                             |
<row>                                                              |
  <item>Serial Number</item>                                       |
  <item>Name</item>                                                |
  <item>Controller index</item>                                    |
  <item>Firmware Version</item>                                    |
  <item> Product Rev.</item>                                       |
  <item>Mode</item>                                                |
  <item>Type</item>                                                |
  <item>ExtName</item>                                             |
  <item>Comment</item>                                             |
</row>                                                            \ /
<row>             <- I want to include this row as its first item starts with `#`
  <item>#0A384D3</item>                                            |
  <item>=&#34;AdventistBolingbrook&#34;</item>                     |
  <item>0</item>                                                   |
  <item>=&#34;7.0/2.1&#34;</item>                                  |
  <item>A00</item>                                                 |
  <item>MA 1000 &amp; 2000</item>                                  |
  <item>Master</item>                                              |
  <item></item>                                                    |
  <item></item>                                                    |
</row>                                                            \ /
<row>             <- I want to include this row as its first item starts with `#`
  <item>#0A384D3</item>
  <item>=&#34;AdventistBolingbrook&#34;</item>
  <item>0</item>
  <item>=&#34;7.0/2.1&#34;</item>
  <item>A00</item>
  <item>MA 1000 &amp; 2000</item>
  <item>Master</item>
  <item></item>
  <item></item>
</row>

Upvotes: 0

Views: 63

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 116992

Given a well-formed input such as:

XML

<rows>
    <row>
        <item>Controller</item>
    </row>
    <row>
        <item>****************</item>
    </row>
    <row>
        <item>Serial Number</item>
        <item>Name</item>
        <item>Controller index</item>
        <item>Firmware Version</item>
        <item> Product Rev.</item>
        <item>Mode</item>
        <item>Type</item>
        <item>ExtName</item>
        <item>Comment</item>
    </row>
    <row>
        <item>#0A384D3</item>
        <item>=&#34;AdventistBolingbrook&#34;</item>
        <item>0</item>
        <item>=&#34;7.0/2.1&#34;</item>
        <item>A00</item>
        <item>MA 1000 &amp; 2000</item>
        <item>Master</item>
        <item></item>
        <item></item>
    </row>
    <row>
        <item>Base Unit</item>
    </row>
    <row>
        <item>****************</item>
    </row>
    <row>
        <item>Serial Number</item>
        <item>Name</item>
        <item>Controller Index</item>
        <item>Port Index</item>
        <item>Slot Index</item>
        <item>Firmware Version</item>
        <item>Product Rev.</item>
        <item>DL Input Power Status</item>
        <item>DL Power Interface Type</item>
        <item>DL AGC Status</item>
        <item>DL AGC Atten. Value</item>
        <item>DL DCA Manual Override</item>
        <item>DL Power</item>
        <item>UL Atten. Value</item>
        <item>ExtName</item>
        <item>Comment</item>
    </row>
    <row>
        <item>#0A3651B</item>
        <item>VZW BU              </item>
        <item>0</item>
        <item>1</item>
        <item>1</item>
        <item>=&#34;4.1&#34;</item>
        <item>N/A </item>
        <item>Normal</item>
        <item>RIU</item>
        <item>OFF</item>
        <item>6</item>
        <item>6</item>
        <item>-21</item>
        <item>0</item>
        <item></item>
        <item></item>
    </row>
    <row>
        <item>#0A3651B</item>
        <item>VZW BU              </item>
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>=&#34;4.1&#34;</item>
        <item>N/A </item>
        <item>Normal</item>
        <item>RIU</item>
        <item>OFF</item>
        <item>7</item>
        <item>7</item>
        <item>-27</item>
        <item>0</item>
        <item></item>
        <item></item>
    </row>
    <row>
        <item>#50772EC</item>
        <item>                    </item>
        <item>0</item>
        <item>4</item>
        <item>1</item>
        <item>=&#34;5.3&#34;</item>
        <item>N/A </item>
        <item>Normal</item>
        <item>RIU</item>
        <item>OFF</item>
        <item>2</item>
        <item>2</item>
        <item>-22</item>
        <item>0</item>
        <item></item>
        <item></item>
    </row>
    <row>
        <item>#50772EC</item>
        <item>                    </item>
        <item>0</item>
        <item>4</item>
        <item>2</item>
        <item>=&#34;5.3&#34;</item>
        <item>N/A </item>
        <item>Normal</item>
        <item>RIU</item>
        <item>OFF</item>
        <item>3</item>
        <item>3</item>
        <item>-18</item>
        <item>0</item>
        <item></item>
        <item></item>
    </row>
</rows>

the following stylesheet:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/rows">
    <xsl:copy>
        <xsl:for-each-group select="row" group-starting-with="row[item='****************']">
            <xsl:variable name="title-item" select="preceding-sibling::row[1]/item" />
            <xsl:for-each select="current-group()[starts-with(item[1], '#')]">
                <row>
                    <xsl:copy-of select="$title-item, *"/>
                </row>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

will return:

Result

<?xml version="1.0" encoding="UTF-8"?>
<rows>
   <row>
      <item>Controller</item>
      <item>#0A384D3</item>
      <item>="AdventistBolingbrook"</item>
      <item>0</item>
      <item>="7.0/2.1"</item>
      <item>A00</item>
      <item>MA 1000 &amp; 2000</item>
      <item>Master</item>
      <item/>
      <item/>
   </row>
   <row>
      <item>Base Unit</item>
      <item>#0A3651B</item>
      <item>VZW BU              </item>
      <item>0</item>
      <item>1</item>
      <item>1</item>
      <item>="4.1"</item>
      <item>N/A </item>
      <item>Normal</item>
      <item>RIU</item>
      <item>OFF</item>
      <item>6</item>
      <item>6</item>
      <item>-21</item>
      <item>0</item>
      <item/>
      <item/>
   </row>
   <row>
      <item>Base Unit</item>
      <item>#0A3651B</item>
      <item>222VZW BU              </item>
      <item>0</item>
      <item>1</item>
      <item>2</item>
      <item>="4.1"</item>
      <item>N/A </item>
      <item>Normal</item>
      <item>RIU</item>
      <item>OFF</item>
      <item>7</item>
      <item>7</item>
      <item>-27</item>
      <item>0</item>
      <item/>
      <item/>
   </row>
   <row>
      <item>Base Unit</item>
      <item>#50772EC</item>
      <item>                    </item>
      <item>3330</item>
      <item>4</item>
      <item>1</item>
      <item>="5.3"</item>
      <item>N/A </item>
      <item>Normal</item>
      <item>RIU</item>
      <item>OFF</item>
      <item>2</item>
      <item>2</item>
      <item>-22</item>
      <item>0</item>
      <item/>
      <item/>
   </row>
   <row>
      <item>Base Unit</item>
      <item>#50772EC</item>
      <item>                    </item>
      <item>0</item>
      <item>4</item>
      <item>2</item>
      <item>="5.3"</item>
      <item>N/A </item>
      <item>Normal</item>
      <item>RIU</item>
      <item>OFF</item>
      <item>3</item>
      <item>3</item>
      <item>-18</item>
      <item>0</item>
      <item/>
      <item/>
   </row>
</rows>

which AFAICT is identical to your expected output except for having a root element, self-closing of empty elements, and encoding of some characters.

Upvotes: 2

Related Questions