【问题标题】:XSL Transformation for table data表数据的 XSL 转换
【发布时间】:2010-11-10 14:38:12
【问题描述】:

我有一些 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 的精简版。我有更多的行,并且在每列上存储了更多的信息。

是否可以应用 XSL 转换来遍历 xml 中的每一行并输出每一列的值。如果列是 DateTime 类型(在列信息中指定)我想输出 localDate 文本值,否则我将只输出 value 文本值。

我可以做一点 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

非常感谢,

安德斯

【问题讨论】:

    标签: xml xslt transform


    【解决方案1】:

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

    <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 元素(如果存在)。够了吗? 还请说明您是否可以使用 XSLT 2.0(由 AltovaXML Tools 或 Saxon 9 实现),这使得这些事情变得更容易。

    [edit] 我想在匹配模式中使用一个键,虽然这在 XSLT 1.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>
    

    【讨论】:

    • 嗨,马丁。感谢那。我目前正在 M$ Visual Studio 2008 中编写我的 XSL,尽管我们正在编写代码以在 Netbeans 6.9.1 下用 Java 生成转换。我讨厌 Netbeans 中的 XML 编辑器。
    • 理想情况下,我想从行链接到列,因为还有其他信息要检查,例如格式等。
    • 使用 Java,您可以切换到 Saxon 9 和 XSLT 2.0 作为 XSLT 处理器。但是请参阅我的编辑,它显示了如何使用键来查找引用的列,并且它适用于 XSLT 1.0。
    • 谢谢马丁。它有效,我几乎可以遵循它。我唯一看不到的是,当您拥有 时,它适用于哪个模板?还是尝试将它们全部应用,但只有匹配返回节点的地方才会匹配?
    • apply-templates 选择 "table" 元素的 "rows" 子元素的 "row" 元素子元素,以使用匹配的模板进行处理。有一个匹配模板,它使用 match="rows/row" 作为匹配任何作为“row”元素的子元素的“row”元素。
    【解决方案2】:

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

    <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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-24
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      相关资源
      最近更新 更多