【问题标题】:Produce an xslt output in a specific order按特定顺序生成 xslt 输出
【发布时间】:2013-10-23 13:02:38
【问题描述】:

我有一个大的 xml 文档,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<Data>
  <aTable>
    <aTableRow Col1="1" Col2="someText"/>
    <aTableRow Col1="2" Col2="newText"/>
    ...
  </aTable>
  <anotherTable>
    <anotherTableRow Col3="someText" Col4="42"/>
    <anotherTableRow Col3="myText" Col4="34"/>
    ...
  </anotherTable>
  ...
</Data>

我需要在相应的 SQL INSERT 语句序列中转换文档。比如:

INSERT INTO aTable (Col1, Col2) VALUES (1, "someText")

我已经有了从“表”到对应SQL语句的转换,但是xslt输出是按照文档的相同顺序生成的。

有没有办法在 aTable 之前拥有例如 anotherTable?

编辑

感谢 cmets 和回答。阅读它们,我意识到我最初的问题并不是那么清楚。我会尝试添加更多细节。

我已经制作了一个模板,它可以在一系列插入语句中正确转换 xml 数据,假设该模板名为“insertGeneration”。

然后我写了类似的东西:

<xsl:template match="Data/anotherTable">
  <xsl:call-template name="insertGeneration"/>
</xsl:template>

<xsl:template match="Data/aTable">
  <xsl:call-template name="insertGeneration"/>
</xsl:template>

我希望按此顺序生成输出,即所有INSERT INTO anotherTable 在所有INSERT INTO aTable 之前。但生成的顺序与源文档相同。

我需要一个特定的顺序,否则在执行 SQL 脚本时我可能会违反外键约束。

我的 xslt 处理器是 Visual Studio 2005。好吧,不是一个紧凑的 xslt 处理器;-)

【问题讨论】:

  • 这将有助于查看您当前的转换。

标签: xml xslt xslt-1.0


【解决方案1】:
<xsl:output method="text" encoding="UTF-8" />

<xsl:template match="Data">
  <xsl:apply-templates select="*/*">
    <xsl:sort select="name(..)" case-order="lower-first" />
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="Data/*/*">
  <xsl:text>INSERT INTO [</xsl:text>
  <xsl:value-of select="name(..)" />
  <xsl:text>] (</xsl:text>
  <xsl:apply-templates select="@*" mode="names" />
  <xsl:text>) VALUES (</xsl:text>
  <xsl:apply-templates select="@*" mode="values" />
  <xsl:text>)&#xA;</xsl:text>
</xsl:template>

<xsl:template match="Data/*/*/@*" mode="names">
  <xsl:text>[</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>]</xsl:text>
  <xsl:if test="position() &lt; last()">, </xsl:if>
</xsl:template>

<xsl:template match="Data/*/*/@*" mode="values">
  <xsl:text>'</xsl:text>
  <xsl:call-template name="string-replace">
    <xsl:with-param name="search">'</xsl:with-param>
    <xsl:with-param name="replace">''</xsl:with-param>
  </xsl:call-template>
  <xsl:text>'</xsl:text>
  <xsl:if test="position() &lt; last()">, </xsl:if>
</xsl:template>

产生与 T-SQL 兼容的输出,如下所示:

INSERT INTO [anotherTable] ([Col3], [Col4]) VALUES ('someText', '42')
INSERT INTO [anotherTable] ([Col3], [Col4]) VALUES ('myText', '34')
INSERT INTO [aTable] ([Col1], [Col2]) VALUES ('1', 'some''Text')
INSERT INTO [aTable] ([Col1], [Col2]) VALUES ('2', 'newText')

如有必要,将代码调整为数据库的语法。

这使用表名的字典顺序。如果您想要不同的顺序,请相应地更改&lt;xsl:sort&gt; 或使用多个单独的&lt;xsl:apply-templates&gt; 来生成所需的序列。 (请注意,一些 XSLT 处理器似乎忽略了 case-order 参数。)

请注意,string-replace 是一个命名模板,它实现了字符串替换功能(XSLT 1.0 所必需的)。如果您有 XSLT 2.0,您可以简单地使用内置的 string-replace() 函数。

<xsl:template name="string-replace">
  <xsl:param name="subject" select="string()" />
  <xsl:param name="search" />
  <xsl:param name="replace" />

  <xsl:variable name="head" select="substring-before($subject, $search)" />
  <xsl:variable name="tail" select="substring-after($subject, $search)" />
  <xsl:variable name="found" select="$head or $tail" />

  <xsl:if test="not($found)">
    <xsl:value-of select="$subject" />
  </xsl:if>

  <xsl:if test="$found">
    <xsl:value-of select="$head" />
    <xsl:value-of select="$replace" />
    <xsl:call-template name="string-replace">
      <xsl:with-param name="subject" select="$tail" />
      <xsl:with-param name="search" select="$search" />
      <xsl:with-param name="replace" select="$replace" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

【讨论】:

  • 感谢您提供详细而有用的答案,但这不是我想要的。问题不是很清楚是我的错。我会努力改进的...
  • 即使您不使用我的其余答案,您也可以使用指向&lt;xsl:sort&gt; 的明显指针,不是吗? &lt;xsl:apply-templates&gt;&lt;xsl:for-each&gt;都可以排序。
  • 是的,但排序不是按字母顺序排列的,我需要对输出进行排序,以便在启动生成的 SQL 脚本时不违反任何外键约束
  • XSLT 究竟应该如何知道该命令是什么?
  • 我知道 XSLT 不能,但我知道那个顺序。我坚持我可以以某种方式强制改变模板处理的顺序
猜你喜欢
  • 2017-05-27
  • 2022-08-19
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2015-05-11
  • 2018-04-25
  • 1970-01-01
相关资源
最近更新 更多