开发者

XSL Transformation for table data

I have some XML that stores column information and row data from a table in the following form:

<?xml version="1.0" encoding="utf-8"?>
<table>
  <columns>
    <column id="1">
      <name>Date</name>
      <type>Date</type>
    </column>
    <col开发者_如何学Cumn id="2">
      <name>Name</name>
      <type>String</type>
    </column>
  </columns>
  <rows>
    <row id="1">
      <columns>
        <column id="1">
          <name>Date</name>
          <value>1-Dec-2010</value>
          <localDate>1-Dec-2010 00:00:00 GMT</localDate>
        </column>
        <column id="2">
          <name>Name</name>
          <value>Jim</value>
        </column>
      </columns>
    </row>
    <row id="2">
      <columns>
        <column id="1">
          <name>Date</name>
          <value>2-Dec-2010</value>
          <localDate>2-Dec-2010 00:00:00 GMT</localDate>
        </column>
        <column id="2">
          <name>Name</name>
          <value>Jane</value>
        </column>
      </columns>
    </row>
  </rows>
</table>

NOTE: This is a cut down version of my xml. I have a lot more rows and store a lot more information on each column.

Is it possible to apply an XSL transform that will iterate through each row in the xml and output each column value. If the column is of type DateTime (as specified in the column information) I want to output the localDate text value otherwise I will just output the value text value.

I can do a little XSL but I am unsure as to how you would check the different part of the document which would essentially map from the tableModel/rows/row/columns/column to the tableModel/columns/column.

I am essentially outputting this as CSV. I have code in place to append the column information for each /tableModel/rows/row/columns/column xml but I think this is unnecessary and it makes the xml too large for Netbeans/Visual Studio to handle (around 7MB).

The output I am trying to get is:

Date,Name
1-Dec-2010 00:00:00 GMT,Jim
2-Dec-2010 00:00:00 GMT,Jane

Many thanks,

Andez


Well the following produces the described output for your input sample

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

  <xsl:param name="sep" select="','"/>
  <xsl:param name="lf" select="'&#10;'"/>

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:apply-templates select="table/columns/column/name"/>
    <xsl:value-of select="$lf"/>
    <xsl:apply-templates select="table/rows/row"/>
  </xsl:template>

  <xsl:template match="column/name">
    <xsl:value-of select="."/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="rows/row">
    <xsl:apply-templates select="columns/column"/>
    <xsl:value-of select="$lf"/>
  </xsl:template>

  <xsl:template match="row/columns/column[not(localDate)]">
    <xsl:value-of select="value"/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="row/columns/column[localDate]">
    <xsl:value-of select="localDate"/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

but it does not look at the corresponding column type, it simply outputs the localDate element if that is present. Does that suffice? Please also state whether you can use XSLT 2.0 (as implemented by AltovaXML Tools or Saxon 9), that makes such stuff easier.

[edit] I wanted to use a key in match pattern and though that is not allowed in XSLT 1.0 but it seems it works so the following is a better implementation of your requirement:

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

  <xsl:param name="sep" select="','"/>
  <xsl:param name="lf" select="'&#10;'"/>

  <xsl:key name="k1" match="table/columns/column" use="@id"/>

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:apply-templates select="table/columns/column/name"/>
    <xsl:value-of select="$lf"/>
    <xsl:apply-templates select="table/rows/row"/>
  </xsl:template>

  <xsl:template match="column/name">
    <xsl:value-of select="."/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="rows/row">
    <xsl:apply-templates select="columns/column"/>
    <xsl:value-of select="$lf"/>
  </xsl:template>

  <xsl:template match="row/columns/column[not(key('k1', @id)/type = 'Date')]">
    <xsl:value-of select="value"/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="row/columns/column[key('k1', @id)/type = 'Date']">
    <xsl:value-of select="localDate"/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$sep"/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>


This less verbose but maybe... esoteric stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:key name="kDataType" match="type" use="../@id"/>
    <xsl:template match="value|table/*/*/name">
        <xsl:variable name="vIsDateType"
                      select="key('kDataType',../@id)='Date'"/>
        <xsl:value-of
             select="concat(substring(',',
                                      1 div boolean(../preceding-sibling::*)),
                            self::name,
                            self::value[not($vIsDateType)],
                            ../localDate[$vIsDateType],
                            substring('&#xA;',
                                      1 div not(../following-sibling::*)))"/>
    </xsl:template>
    <xsl:template match="text()"/>
</xsl:stylesheet>

Output:

Date,Name
1-Dec-2010 00:00:00 GMT,Jim
2-Dec-2010 00:00:00 GMT,Jane
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜