表数据的 XSL 转换

发布于 2024-10-01 09:58:30 字数 1884 浏览 5 评论 0原文

我有一些 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

非常感谢,

Andez

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拥抱我好吗 2024-10-08 09:58:30

下面为您的输入示例生成所描述的输出

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

  <xsl:param name="sep" select="','"/>
  <xsl:param name="lf" select="'
'"/>

  <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 实现),这使得此类事情变得更容易。

[编辑] 我想在匹配模式中使用键,虽然 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="'
'"/>

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

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="'
'"/>

  <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="'
'"/>

  <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>
晨敛清荷 2024-10-08 09:58:30

这不太冗长,但也许......深奥的样式表:

<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('
',
                                      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

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('
',
                                      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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文