XSL to show parent as columns, with matching child

2019-03-03 17:04发布

问题:

I am new to XML and XSL. I am trying to take a XML strings generated by our vendor software and translate it into Excel format. The XML can have repeating Rows that each have a number of associated child Fields. The child Fields will always be the same from Row to Row, and in the same order, but may be different in different XMLs. The number of rows will change from file to file.

I have a feeling there is a for-each here, maybe nested, or using relational positions, but I'm having trouble wrapping my head around the querying functions. I've reviewed many samples, but every solution was tailored to the question, and I didn't find one where the desired output was like mine.

Any assistance, or a nudge in the right direction at least, would be appreciated.

Thanks!

Sample XML:

<?xml version="1.0" standalone="yes" ?>
<RpcData SrcNm="SnapshotBuckets" SrcTyp="DIR" ClientID="000" LoanNo="0000000000" Borrower="" RsltCd="0">
  <RepeatingFieldSet Nm="Hazard" Type="All Data" Count="3">
    <Row Index="1">
      <Fld Nm="Type">A</Fld>
      <Fld Nm="AgentCode">TESTAP</Fld>
      <Fld Nm="Agent City">ANYTOWN</Fld>
      <Fld Nm="Agent Desc Line 1">APPLE</Fld>
      <Fld Nm="Agent Desc Line 2">PICKERS</Fld>
      <Fld Nm="Agent Desc Line 3">123 MAIN ST</Fld>
      <Fld Nm="Agent Phone">(718) 555-1212</Fld>
      <Fld Nm="Agent State">AL</Fld>
      <Fld Nm="Agent ZIP Code">00001</Fld>
    </Row>
    <Row Index="2">
      <Fld Nm="Type">B</Fld>
      <Fld Nm="AgentCode">TESTBA</Fld>
      <Fld Nm="Agent City">ANYTOWN</Fld>
      <Fld Nm="Agent Desc Line 1">BANANA</Fld>
      <Fld Nm="Agent Desc Line 2">BUNCHERS</Fld>
      <Fld Nm="Agent Desc Line 3">456 MAIN ST</Fld>
      <Fld Nm="Agent Phone">(718) 555-1213</Fld>
      <Fld Nm="Agent State">AK</Fld>
      <Fld Nm="Agent ZIP Code">00002</Fld>
    </Row>
    <Row Index="3">
      <Fld Nm="Type">C</Fld>
      <Fld Nm="AgentCode">TESTCH</Fld>
      <Fld Nm="Agent City">ANYTOWN</Fld>
      <Fld Nm="Agent Desc Line 1">CHERRY</Fld>
      <Fld Nm="Agent Desc Line 2">PITTERS</Fld>
      <Fld Nm="Agent Desc Line 3">789 MAIN ST</Fld>
      <Fld Nm="Agent Phone">(718) 555-1214</Fld>
      <Fld Nm="Agent State">CA</Fld>
      <Fld Nm="Agent ZIP Code">00003</Fld>
    </Row>
  </RepeatingFieldSet>
</RpcData>

Desired Output:

Field                   1               2               3
Type                    A               B               C
AgentCode               TESTAP          TESTBA          TESTCH
Agent City              ANYTOWN         ANYTOWN         ANYTOWN
Agent Desc Line 1       APPLE           BANANA          CHERRY
Agent Desc Line 2       PICKERS         BUNCHERS        PITTERS
Agent Desc Line 3       123 MAIN ST     456 MAIN ST     789 MAIN ST
Agent Phone             (718) 555-1212  (718) 555-1213  (718) 555-1214
Agent State             AL              AK              CA
Agent ZIP Code          00001           00002           00003

XSL so far:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:x="urn:schemas-microsoft-com:office:excel">
    <xsl:template match="/">
        <xsl:processing-instruction name="mso-application"><xsl:text>progid="Excel.Sheet"</xsl:text></xsl:processing-instruction>
        <Workbook>
            <Worksheet ss:Name="Sheet1">
                <Table>
                    <Row>
                        <Cell>Business Name</Cell>
                        <xsl:for-each select="RpcData/RepeatingFieldSet/Row">
                            <Cell>
                                <xsl:value-of select="@Index"/>
                            </Cell>
                        </xsl:for-each>
                    </Row>
                    <xsl:for-each select="RpcData/RepeatingFieldSet/*/Fld">
                        <Row>
                            <Cell>
                                <xsl:value-of select="@Nm"/>
                            </Cell>
                            <xsl:for-each select="*">
                                <Cell>
                                    <xsl:value-of select="."/>
                                </Cell>
                            </xsl:for-each>
                        </Row>
                    </xsl:for-each>
                </Table>
            </Worksheet>
        </Workbook>
   </xsl:template>      
</xsl:stylesheet>

回答1:

IIUC, you want to transpose the given table - rows to columns, fields to rows. The foilowing stylesheet shows how this can be done. For simplicity, this generates an HTML table - the adjustment for an Excel worksheet should be trivial.

XSLT 1.0

<xsl:stylesheet version="1.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="/RpcData">
    <xsl:variable name="col" select="RepeatingFieldSet/Row"/>
    <xsl:variable name="row" select="RepeatingFieldSet/Row[1]/Fld"/>
    <table border="1">
        <!-- header row -->
        <tr>
            <th>Field</th>
            <xsl:for-each select="$col">
                <th>
                    <xsl:value-of select="@Index"/>
                </th>
             </xsl:for-each>
        </tr>
        <!-- data rows -->
        <xsl:for-each select="$row">
            <xsl:variable name="i" select="position()"/>
            <tr>
                <th><xsl:value-of select="@Nm"/></th>
                <xsl:for-each select="$col">
                    <td>
                        <xsl:value-of select="Fld[$i]"/>
                    </td>
                </xsl:for-each>
            </tr>    
        </xsl:for-each>
    </table>
</xsl:template>

</xsl:stylesheet>

Applied to your example input, the (rendered) result will be:



标签: xml excel xslt