【问题标题】:Trying to print out node values in XSLT using variable elements names尝试使用变量元素名称在 XSLT 中打印出节点值
【发布时间】:2011-11-09 17:52:50
【问题描述】:

所以这是过去几天一直困扰我的问题。它应该相当容易,但是 XSLT 调试起来实在是太痛苦了。我们在 java 1.6 上使用 Xalan 1.0

输入 XML

<?xml version="1.0" encoding="UTF-8"?>
<rfb2>
    <rfb2_item>
        <VALDATE>2011-10-23</VALDATE>
        <FUND_ID>300</FUND_ID>
        <SEC_ID>34567</SEC_ID>
    </rfb2_item>
    <rfb2_item>
        <VALDATE>2011-1-09</VALDATE>
        <FUND_ID>700</FUND_ID>
        <SEC_ID>13587</SEC_ID>
    </rfb2_item>
    <rfb2_item>
        <VALDATE>2011-3-09</VALDATE>
        <FUND_ID>200</FUND_ID>
        <SEC_ID>999334</SEC_ID>
    </rfb2_item>
<rfb2>

我们需要将 XML 转换为每个 rfb2_item 的逗号分隔值列表,因此样式表总是迭代 rfb2_item 节点。我们在样式表中使用一个参数来控制 rfb2_item (valdate,fund_id,sec_id) 的哪些元素将被输出,以及以什么顺序输出,例如

<xsl:param name="$outputElements" select="'VALDATE,FUND_ID'"/>
..outputs...

2011-10-23,300
2011-1-09,700
2011-3-09,200



<xsl:param name="$outputElements" select="'SEC_ID'"/>    
..outputs...

34567
13587
999334

如果 $outputElements 是 '*' 的特殊情况,只需按照元素在输入 xml 中出现的顺序输出元素

<xsl:param name="$outputElements" select="'*'"/>

..outputs...

2011-10-23,300,34567
2011-1-09,700,13587
2011-3-09,200,999334

那么,我的问题是我们如何编写一个模板来根据 $outputElements 参数创建所需的输出?一个可行的例子会很棒......

【问题讨论】:

  • 你忘了问这个问题。除非您希望有人为您编写完整的 xslt - 他们会这样做。

标签: java xslt csv transformation xalan


【解决方案1】:

是的,FailedDev 是对的。有人会为你写的:

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

    <xsl:output method="text" />

    <xsl:param name="outputElements" select=" 'FUND_ID,SEC_ID,VALDATE' " />

    <xsl:template match="rfb2_item">

        <xsl:for-each select="*[contains($outputElements, local-name()) or $outputElements = '*']">
            <xsl:sort select="string-length(substring-before($outputElements, local-name(.)))" />
            <xsl:value-of select="text()" />
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#13;&#10;</xsl:text>

    </xsl:template>

</xsl:stylesheet>

一点解释。 xsl:for-each 将选择当前 rfb2_item 中的每个元素,其本地名称包含在 outputElements 参数中,或者 outputElements 参数为 * (如果这是案子)。然后它会根据outputElements 中本地名称之前的子字符串的长度对它们进行排序。由于名称在该参数后面出现时该值会变高,因此会根据您的参数进行排序。

示例:元素VALDATE 将为substring-before 函数生成FUND_ID,SEC_ID,而该函数又将生成14 作为字符串长度。这高于您为SEC_ID 获得的8,这意味着VALDATE 的值排在SEC_ID 之后。

xsl:sort 之后,我们只是使用xsl:value-of 来输出元素值。您可能想在那里修剪多余的空白。最后,我们正在测试该位置是否不等于当前上下文中最后一个节点的位置(即xsl:for-each 排序后的位置),如果是,则输出一个逗号。这样可以避免在最后一个值之后输出逗号。

我使用xsl:text 插入的换行符采用Windows/DOS 约定。如果文件只应使用换行符而不是回车符 + 换行符,请删除 &amp;#13;

请注意,这不会在您的 CSV 输出中转义逗号!我会把它留给你。如果在 XSLT/XPath 中证明太难,那么研究使用 extension functions 将这项任务委托给 Java 可能会很有趣。

【讨论】:

  • 嘿,G_H,这很棒,而且有效。你刚刚减轻了很多压力,谢谢。我在样式表的顶部添加了 以删除所有空白。我确实有几个问题。排序有必要吗?而且您对字符串长度所做的 cmets 让我很担心,我是否需要考虑如果 2 个或多个元素的长度相同,例如 rfb2_item/E1 和 rfb2_item/E2?
  • @RaffiM 排序是为了确保输出字段的顺序由您的参数确定,因为我认为这是要求之一。如果是参数,则检查的字符串长度是子字符串的长度,而不是输出元素的内容。确保元素按参数中指定的顺序输出是一个技巧。基本上,必须输出的每个元素的名称(FUND_IDVALDATE...)将产生不同的数字。这些数字根据给定参数建立排序。
  • @G_H...这很有意义...最后一个问题,我们正在尝试将您的代码集成到更大的样式表中,它会产生奇怪的结果。我们知道它可以独立工作,但问题在于我们称之为它的方式。如果我们从另一个已在“/*”上匹配的模板调用您的模板(使用 xsl:call-template),您的模板代码会发生什么变化以产生相同的输出?
  • @RaffiM xsl:call-template 用于命名模板。我的使用输入匹配。您要么需要将我的模板更改为已命名的模板,然后使用 rfb2_item 节点作为上下文调用它,要么将 xsl:apply-templates 与针对这些节点的选择一起使用。
【解决方案2】:

有时在这种情况下,值得研究使用 XSLT 生成或修改 XSLT 代码的可能性。您可以通过这种方式进一步进行参数化 - 例如控制输出哪些字段、如何排序、是否分组、选择哪些行的选择标准等。

【讨论】:

    猜你喜欢
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多