XSLT用于将所有节点中的元素提取为1000个值的组

时间:2017-09-05 12:47:48

标签: xml xslt

我有一个XML,我需要将所有节点中的特定元素提取到1000个组中。实际XML的结构如下所示:

<host> 
<node> 
  <type>fruit1</type>
  <value>1</value>
</node>
<node>
  <type>fruit2</type>
  <value>2</value>
</node>
<node>
  <type>fruit3</type>
  <value>3</value>
</node>
<node>
  <type>fruit4</type>
  <value>4</value>
</node>  
....
....
....
<node>
  <type>fruit1500</type>
  <value>1500</value>
</node>
</host>

我必须从所有节点中选择元素并提取到格式'fruit1','fruit2','fruit3',...,'fruit1499','fruit1500'并将数据传递到SQL查询select * from tablename where ColumnName_type IN('fruit1','fruit2','fruit3',...,'fruit1499','fruit1500')。问题是我无法将超过1000个值传递到SQL IN条件。

现在我必须将前1000个值分组到一个组中,然后将1000个值分组到另一个组中并将其传递给查询。预期的sql查询如下 -

select * from tablename where ColumnName_type in 
('fruit1','fruit2','fruit3',...,'fruit1000') union all 
select * from tablename where ColumnName_type in 
('fruit1001','fruit1002',...'fruit1500')

为提取所有值而编写的XSLT如下 -

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" 
encoding="UTF-8" />
<xsl:template match="/">
<html>
<body>
<table border="1">
  <xsl:for-each select="//field/value/listValues/value">
  <tr>
    <td>
      <xsl:text>'</xsl:text><xsl:value-of select="ancestor::field/code"/>
      <xsl:text>'</xsl:text><xsl:if test="position()!=last()">,</xsl:if>
    </td>
  </tr> 
  </xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

任何将数据提取到群组中的建议都会有很大的帮助。

2 个答案:

答案 0 :(得分:0)

您可以使用模数和以下兄弟轴的巧妙组合创建组或批次。在样式表下面需要像您在问题中显示的XML并输出纯文本(SQL语句):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output encoding="utf-8" indent="no" method="text"/>

  <xsl:variable name="groupSize" select="1000"/>

  <xsl:template match="host">
    <xsl:for-each select="node[position() mod $groupSize = 1]">
      <xsl:if test="position() > 1">
        <xsl:text> union all&#xa;</xsl:text>
      </xsl:if>
      <xsl:variable name="values">
        <xsl:text>'</xsl:text>
        <xsl:value-of select="./type"/>
        <xsl:text>'</xsl:text>
        <xsl:for-each select="following-sibling::node[$groupSize > position()]/type">
          <xsl:text>,'</xsl:text>
          <xsl:value-of select="."/>
          <xsl:text>'</xsl:text>
        </xsl:for-each>
      </xsl:variable>
      <xsl:value-of select="concat('select * from tablename where ColumnName_type in &#xa;(', $values, ')')"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

使用groupSize = 3的结果:

select * from tablename where ColumnName_type in 
('fruit1','fruit2','fruit3') union all
select * from tablename where ColumnName_type in 
('fruit4','fruit1500')

答案 1 :(得分:0)

利用关系数据库的力量重新考虑您的方法和规模。使用XSLT将XML转换为表格式格式文件,例如CSV,用于所有列出的水果。然后,将CSV作为临时表导入数据库。

实际上,每个主要的RDBMS都可以使用方便的方法轻松导入CSV:

  • Oracle {MySQL LOAD DATA FILE...
  • Postgres COPY mytable FROM...
  • SQLite,命令行为.import csv...
  • 使用方法DoCmd.TransferText...
  • 进行MS Access
  • 带有BULK INSERT my table...
  • 的SQL Server
  • DB2 IMPORT FROM...

最后,将临时表(即INNER JOIN)加入到您需要的表中。这避免了重复的IN()条款和UNION ALL,所有这些都适用于干燥方案。

XSLT (将xml转换为csv)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/host">
      <xsl:text>fruit_name&#xa;</xsl:text>
      <xsl:for-each select="node">
        <xsl:value-of select="type"/>
        <xsl:if test="position() != last()">
          <xsl:text>&#xa;</xsl:text>
        </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

CSV 输出

fruit_name
fruit1
fruit2
fruit3
fruit4
...
fruit1500

SQL 查询(表格与水果临时表的显式连接)

SELECT t.* FROM tablename t
INNER JOIN fruit_temptable f
ON t.ColumnName_type = f.fruit_name