writing xslt for the below scenario

2019-06-10 06:38发布

问题:

INPUT xml:

<?xml version="1.0"?>
<TABLE>
<THEAD>
    <ROW id="rh">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >A</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >B</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >C</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >D</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >F</Para>
        </CELL>
    </ROW>


</THEAD>
<TBODY editable="T">
    <ROW id="r1">
        <CELL rowmerged="T"  rowspan="2" >
            <Para >11</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para >12</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >13</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >14</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para >15</Para>
        </CELL>
    </ROW>

    <ROW id="r2">
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >23</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >24</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
    </ROW>

    <ROW id="r3">
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >33</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >34</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="2" >
            <Para ></Para>
        </CELL>
    </ROW>

    <ROW id="r4">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >41</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >42</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >43</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >44</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="1" >
            <Para >45</Para>
        </CELL>
    </ROW>
</TBODY>
</TABLE>

Rule: for merged rows: copy content of primary merged cell to other cells in merged rows. Expected result:

<?xml version="1.0"?>
<TABLE>
<THEAD>
    <ROW id="rh">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >A</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >B</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >C</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >D</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >F</Para>
        </CELL>
    </ROW>


</THEAD>
<TBODY editable="T">
    <ROW id="r1">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >11</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >12</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >13</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >14</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan=1" >
            <Para >15</Para>
        </CELL>
    </ROW>

    <ROW id="r2">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >11</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >12</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >23</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >24</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >15</Para>
        </CELL>
    </ROW>

    <ROW id="r3">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >11</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >12</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >33</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >34</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >15</Para>
        </CELL>
    </ROW>

    <ROW id="r4">
        <CELL rowmerged="F"  rowspan="1" >
            <Para >41</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >42</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >43</Para>
        </CELL>
        <CELL rowmerged="F"  rowspan="1" >
            <Para >44</Para>
        </CELL>
        <CELL rowmerged="T"  rowspan="1" >
            <Para >45</Para>
        </CELL>
    </ROW>
</TBODY>
</TABLE>

Rule: for merged rows: copy content of primary merged cell to other cells in merged rows. Could you please help me out in this scenario. I am new to xslt.

Thanks in advance.

回答1:

You haven't spelled out the rules in detail in your question but it appears to me that the output you've asked for can be achieved if for any cell with rowmerged="T" and and empty Para, you copy the Para from the corresponding cell in the nearest preceding row where it is not empty.

You can start as usual with the identity template, which copies everything unchanged by default but allows you to override this behaviour for specific nodes:

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>

Now for the changes we want to make: for CELL elements we need to fix up their attributes

  <xsl:template match="CELL">
    <CELL rowmerged="F" rowspan="1">
      <xsl:apply-templates select="node()"/><!-- process children -->
    </CELL>
  </xsl:template>

And for an empty Para in a rowmerged cell

  <xsl:template match="Para[not(normalize-space())][../@rowmerged='T']">

we want to find the nearest preceding row where the matching cell is not empty, and copy that

    <!-- find the number of this cell in the current row -->
    <xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1" />
    <!-- look for the corresponding Para in previous rows -->
    <xsl:variable name="matchingCells" select="
        ../../preceding-sibling::ROW/CELL[$cellnum]/Para" />
    <!-- filter for just the non-empty ones, and copy the nearest (last in doc order) -->
    <xsl:copy-of select="$matchingCells[normalize-space()][last()]" />

The complete stylesheet is as follows:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>

  <xsl:template match="CELL">
    <CELL rowmerged="F" rowspan="1">
      <xsl:apply-templates select="node()"/>
    </CELL>
  </xsl:template>

  <xsl:template match="Para[not(normalize-space())][../@rowmerged='T']">
    <xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1" />
    <xsl:variable name="matchingCells" select="
        ../../preceding-sibling::ROW/CELL[$cellnum]/Para" />
    <xsl:copy-of select="$matchingCells[normalize-space()][last()]" />
  </xsl:template>
</xsl:stylesheet>


标签: xslt