使用Xslt将数据从Xml中的类似节点导出到Excel

时间:2011-03-15 19:49:00

标签: xml xslt

我有一个xml文档,其中动态生成值,我需要使用xslt将这些数据导出到excel。出于测试目的,我创建了一个示例xml: -

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ucdetector>
  <!--COPY_RIGHT-->
  <statistics/>
  <markers>
    <!--Sample XML_INFO-->
    <marker>
      <description>Desc</description>
      <classRef>Test1</classRef>
      <classRef>Test2</classRef>
      <classRef>Test3</classRef>
      <markerType>Class PreferenceInitializer has 8 references</markerType>
    </marker>
  </markers>
  <problems/>
</ucdetector>

xslt如下: -

= tab = new line - &gt;

<!-- First line: about -->
<xsl:value-of
    select="concat('Report', '&#x9;', /ucdetector/statistics/abouts/about[@name='reportCreated']/value, '&#xA;', '&#xA;')" />
<!-- Second line: header -->

<xsl:value-of
    select="concat('Class Name', '&#x9;', 'Referring class
    name', '&#x9;', 'Class Details', '&#xA;')" />


<xsl:for-each select="/ucdetector/markers/marker">
    <xsl:variable name="vars">
        <xsl:apply-templates select="classRef" />
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '&#x9;', $vars, '&#x9;', markerType, '&#xA;')" />
</xsl:for-each>

我能够将所有数据正确导出到excel中,除了标签“classRef”中的数据,它们一起显示为“Test1Test2Test3”,但我需要在excel的不同列中单独使用它们。 任何人都能提供一些线索吗?

2 个答案:

答案 0 :(得分:0)

我猜你想要三个值分隔?在这种情况下,我倾向于这样做(在XSLT 2.0中)

<xsl:for-each select="/ucdetector/markers/marker">
    <xsl:variable name="vars">
        <xsl:value-of select="classRef" separator="'&#x9;'"/>
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '&#x9;', $vars, '&#x9;', markerType, '&#xA;')" />
</xsl:for-each>

或1.0

<xsl:for-each select="/ucdetector/markers/marker">
    <xsl:variable name="vars">
        <xsl:for-each select="classRef">
          <xsl:if test="position()!=1"><xsl:text>&#x9;</xsl:text></xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '&#x9;', $vars, '&#x9;', markerType, '&#xA;')" />
</xsl:for-each>

答案 1 :(得分:0)

你的问题有点不清楚。我认为你要做的是发出marker元素的所有子元素的文本,由制表符分隔,作为以换行符终止的文本行。是对的吗?

如果是这样,我认为创建一个包含所有连接在一起的classRef元素的变量没有任何好处 - 你不会对它们的处理方式与其他元素不同。您可以使用简单的模板将每个marker元素转换为输出行:

 <!-- It's really only worth doing this if your transform uses lots of tabs
      and newlines, which this one no longer does.  But it aids readability
      and reduces the number of typos you'll make, so it's a good habit to
      get into. -->
 <xsl:variable name="tab">&#x9</xsl:variable>
 <xsl:variable name="newline">&#xA;</xsl:variable>

 <xsl:template match="marker">
    <xsl:for-each select="*">
      <xsl:if test="position() != 1">
        <xsl:value-of select="$tab"/>
      </xsl:if>
      <xsl:value-of select="."/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
 </xsl:template>

修改

好的,你发布的例子说明了你在寻找什么。您想要的是每个classRef元素的输出中的一行,而不是每个marker元素。每行应具有相同数量的选项卡,并以换行符终止。但是,任何给定marker元素的第一个行应包含非classRef元素的数据,而其余行应仅包含classRef元素的数据

这应该可以解决问题:

<xsl:template match="marker">
   <xsl:apply-templates select="classRef"/>
</xsl:template>

<xsl:template match="classRef[position() = 1]">
   <xsl:variable name="current" select="."/>
   <xsl:for-each select="../*[name() != 'classRef' or . = $current]">
      <xsl:if test="position() != 1">
         <xsl:value-of select="$tab"/>
      </xsl:if>
      <xsl:value-of select="."/>
   </xsl:for-each>
   <xsl:value-of select="$newline"/>
</xsl:template>

<xsl:template match="classRef">
   <xsl:variable name="current" select="."/>
   <xsl:for-each select="../*[name() != 'classRef' or . = $current]">
      <xsl:if test="position() != 1">
         <xsl:value-of select="$tab"/>
      </xsl:if>
      <xsl:if test=". = $current">
         <xsl:value-of select="."/>
      </xsl:if>
   </xsl:for-each>
   <xsl:value-of select="$newline"/>
</xsl:template>