XSLT没有产生预期的结果

时间:2015-02-18 20:34:41

标签: xml csv xslt

我正在尝试将XML文档转换为CSV,这是我以前成功完成的事情,但是我的当前XML的结构不同,因为所有子节点元素都被命名为相同(值)。这是XML:

    <?xml version="1.0" encoding="utf-8"?>
<dataset  xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
    <metadata>
          <item name="Employee Number" type="xs:string" length="20"/>
          <item name="Last Name" type="xs:string" length="202"/>
          <item name="First Name" type="xs:string" length="202"/>
    </metadata>
    <data>
        <row>
            <value>000056</value>
            <value>Atkinson</value>
            <value>Joan</value>
        </row>
        <row>
            <value>000061</value>
            <value>Bolton</value>
            <value>Larry</value>
        </row>
        <row>
            <value>000092</value>
            <value>Hadley</value>
            <value>Charles</value>
        </row>
    </data>
</dataset>

每个节点代表的内容在上面的部分中定义。也就是说,这是我想要的输出:

000056,Atkinson,Joan
000061,Bolton,Larry
000092,Hadley,Charles

这是我开始使用的XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" omit-xml-declaration="yes" indent="no"/>
  <xsl:strip-space elements="*" />

  <xsl:template match="/data">
    <xsl:for-each select="row">
      <!-- Employee Number -->
      <xsl:text>,</xsl:text>
      <!-- Last Name -->
      <xsl:text>,</xsl:text>
      <!-- First Name -->
      <xsl:text>,</xsl:text>
      <!-- new line -->
      <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

我还没有弄清楚如何正确编码三个数据元素中每个元素的元素,所以我希望实际上在三行输出中只能看到两个逗号。但是,这就是我实际得到的:

000056AtkinsonJoan000061BoltonLarry000092HadleyCharles

它忽略了for-each循环中的所有内容,只输出整个元素中的所有数据。我还发现,即使我将select =“row”属性更改为select =“zzz”(或任何其他值),我仍然会得到相同的结果。那么,我从哪里走了?

2 个答案:

答案 0 :(得分:1)

这是因为你有一个默认命名空间。您看到的结果来自built-in templates。您应该使用前缀声明命名空间,并在XPath中使用该前缀。

示例...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://developer.cognos.com/schemas/xmldata/1/">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*" />

    <xsl:template match="x:row">
        <xsl:apply-templates/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>

    <xsl:template match="x:value">
        <xsl:if test="not(position()=1)">
            <xsl:text>,</xsl:text>
        </xsl:if>
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

这是由输入XML

中的附加命名空间引起的问题
xmlns="http://developer.cognos.com/schemas/xmldata/1/"

您可以将带有前缀的命名空间添加到XSLT,例如如

xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"

然后相应地匹配XML的元素:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*" />
   <xsl:template match="//c:data">
    <xsl:for-each select="c:row">
      <xsl:for-each select="c:value">
        <xsl:value-of select="."/>
        <xsl:if test="position() != last()">
          <xsl:text>,</xsl:text>
        </xsl:if>
      </xsl:for-each>
      <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

输出:

000056,Atkinson,Joan
000061,Bolton,Larry
000092,Hadley,Charles

我已为这些值添加了第二个for-each循环,否则您可以使用<xsl:value-of select="c:value[1]"/>为第一个值等检索该值。

已保存的示例:http://xsltransform.net/pPqsHTu