【问题标题】:Use XSL to Iterate over Elements in For Each Loop使用 XSL 迭代 For Each 循环中的元素
【发布时间】:2015-01-28 18:36:57
【问题描述】:

所以我在让它工作时遇到了严重的问题(我确信这很简单,我对 XSL 的经验很少)。

我试图在一个结构如下的 xml 文档中迭代一堆非常不同的子元素:

<transaction>
 <data_xml>
  <document data_type="0">
   <element1>value1</element1>
   <element2>value2</element2>
   <element3>value3</element3>
  </document>
 </data_xml>
</transaction>

我使用的是 XSL 1.0 版,考虑到我正在工作的系统的限制,我很确定我不能为此使用 2.0。

我想要的输出是:

<foo>
 <bar:element1><!CDATA[[value]]></bar:element1>
 <bar:element2><!CDATA[[value]]></bar:element2>
 <bar:element3><!CDATA[[value]]></bar:element3>
</foo>

我目前使用的可怕的代码是:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
 <foo>
  <xsl:for-each select="/transaction/data_xml/document[@data_type='0']/*">
   &lt;bar:<xsl:value-of select="name(name(/transaction/data_xml/document[@data_type='0']/*)"/>>
   &#60;![CDATA[<xsl:value-of select="/transaction/data_xml/document[@data_type='0']/*"/>]]&gt;
   &#60;/bar:<xsl:value-of select="name(/transaction/data_xml/document[@data_type='0']/*)"/>>
  </xsl:for-each>
 </foo>
</xsl:template>
</xsl:stylesheet>

但是,当我使用它时,它只是多次迭代同一个元素,而不是依次迭代每个元素。

有什么想法吗?除了因为看起来很糟糕的代码而向我开枪吗?

【问题讨论】:

  • 您请求的输出不是格式良好的 XML 文档(bar: 前缀必须绑定到命名空间)。为什么三个 CDATA 值都相同?
  • 根据我的转换器,XSL 也是无效的。
  • 因为我是个笨蛋,我没有仔细检查。不过感谢您的 cmets!

标签: xml xslt xpath xslt-1.0


【解决方案1】:

你可能想做这样的事情:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bar="http://example.com/bar">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
    <foo>
        <xsl:for-each select="transaction/data_xml/document[@data_type='0']/*">
            <xsl:element name="bar:{local-name()}">
                <xsl:value-of select="."/>
            </xsl:element>
        </xsl:for-each>
    </foo>
</xsl:template>

</xsl:stylesheet>

应用于您的示例输入,将导致:

<?xml version="1.0" encoding="utf-8"?>
<foo xmlns:bar="http://example.com/bar">
   <bar:element1>value1</bar:element1>
   <bar:element2>value2</bar:element2>
   <bar:element3>value3</bar:element3>
</foo>

如果您希望各种 bar:elementX 值成为 CDATA 部分,则应在 &lt;xsl:output&gt; 指令中指定:

<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" cdata-section-elements="bar:element1 bar:element2 bar:element3"/>

但是,这需要您提前知道所有可能的元素名称。否则你必须破解它,例如:

<xsl:template match="/">
    <foo>
        <xsl:for-each select="transaction/data_xml/document[@data_type='0']/*">
            <xsl:element name="bar:{local-name()}">
                <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
                <xsl:value-of select="."/>
                <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
            </xsl:element>
        </xsl:for-each>
    </foo>
</xsl:template>

【讨论】:

  • 这是一个更好的实现,看起来不错而且很有意义!谢谢!
【解决方案2】:

两件事:

  • 您可以使用不带参数的name()local-name() 来获取当前元素的名称。
  • 您应该使用xsl:element 来创建具有动态名称的元素。您不应该手动构建他们的标签:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:bar="namespaceForBarGoesHere"
                version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <foo>
      <xsl:for-each select="/transaction/data_xml/document[@data_type='0']/*">
        <xsl:element name="bar:{local-name()}">
          <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
          <xsl:value-of select="." />
          <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
        </xsl:element>
     </xsl:for-each>
   </foo>
 </xsl:template>

产生这个结果:

<foo xmlns:bar="namespaceForBarGoesHere">
  <bar:element1><![CDATA[value1]]></bar:element1>
  <bar:element2><![CDATA[value2]]></bar:element2>
  <bar:element3><![CDATA[value3]]></bar:element3>
</foo>

【讨论】:

  • 我相信您的 CDATA 模拟结果不正确。
  • @michael.hor257k 我错过了感叹号。现在应该可以工作了。
猜你喜欢
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-19
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多