代码之家  ›  专栏  ›  技术社区  ›  Andez

表数据的XSL转换

  •  0
  • Andez  · 技术社区  · 14 年前

    我有一些XML以以下形式存储表中的列信息和行数据:

    <?xml version="1.0" encoding="utf-8"?>
    <table>
      <columns>
        <column id="1">
          <name>Date</name>
          <type>Date</type>
        </column>
        <column 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>
    

    注意:这是我的XML的精简版。我有更多的行,并且在每一列中存储了更多的信息。

    是否可以应用将遍历XML中每一行并输出每一列值的XSL转换。如果列的类型为datetime(如列信息中指定的),则我希望输出 本地日期 否则我只输出 价值 文本值。

    我可以做一点XSL,但是我不确定您将如何检查文档的不同部分,这些部分基本上是从tablemodel/rows/row/columns/column映射到tablemodel/columns/column的。

    我基本上把这个输出为csv。我有适当的代码来为每个/tablemodel/rows/row/columns/column xml附加列信息,但我认为这是不必要的,它使XML太大,NetBeans/Visual Studio无法处理(大约7MB)。

    我想得到的结果是:

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

    非常感谢,

    安德仕

    2 回复  |  直到 14 年前
        1
  •  2
  •   Martin Honnen    14 年前

    下面将为您的输入样本生成所描述的输出

    <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>
    

    但它不查看相应的列类型,它只输出localdate元素(如果存在)。够了吗? 还请说明您是否可以使用XSLT2.0(由AltovaXML工具或Saxon9实现),这使得这类工作变得更简单。

    [编辑]我想在匹配模式中使用一个键,虽然这在XSLT1.0中是不允许的,但它似乎可以工作的,所以下面是您的需求的更好实现:

    <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>
    
        2
  •  0
  •   user357812    14 年前

    这不那么冗长,但也许…深奥的样式表:

    <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>
    

    输出:

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