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

Posted

技术标签:

【中文标题】使用 Xslt 将 Xml 中类似节点的数据导出到 excel【英文标题】:Export data from similar nodes in Xml to excel using Xslt 【发布时间】:2011-03-15 19:49:00 【问题描述】:

我有一个动态生成值的 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 = 换行 -->

<!-- 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 的不同列中。 有人可以提供一些线索吗?

【问题讨论】:

【参考方案1】:

我猜您希望三个值以制表符分隔?在这种情况下,我倾向于这样做(在 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>

【讨论】:

感谢您的反馈。我尝试了您建议的选项。实际上,我需要“classRef”节点中的值而不是制表符分隔,而是一个在另一个之下。请你帮忙解决这个问题!【参考方案2】:

你的问题有点不清楚。我认为您要做的是将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>

【讨论】:

感谢您的评论。你几乎是正确的。我需要标记元素的所有子元素的文本,它们位于由制表符分隔的相应列中。除了没有出现在其他元素下方的“classRef”元素之外,我能够部分生成此输出。 classRef 值应该用什么字符分隔? 上面提供的 xml 中的 classRef 值是“Test1”、“Test2”、“Test3”。我需要它们在 excel 列中低于其他列,我认为可以用新行来分隔! ! 为了更好地理解,我上传了一个示例 excel 格式,我希望使用上述 xml 和 xslt 来实现。 '请从 url 下载示例 excel' :- [link]4shared.com/document/GdMlndFR/Demo.html @Robert - 我希望你明白我的意思.. 如果你反刍帮助,我会是 gr8

以上是关于使用 Xslt 将 Xml 中类似节点的数据导出到 excel的主要内容,如果未能解决你的问题,请参考以下文章

XSLT - 如何将节点内的内联/转义 XML 视为嵌套节点

使用 XSLT 将 XML 元素移动到不同的节点

XSLT 导出过滤器产生不必要的空 XML 标记

如何在 XSLT 中拆分数据并存储在多个节点中

如何使用带条件的 XSLT 映射在 XML 中移动节点

使用 XSLT 将具有相同 ID 的元素 (XML) 合并到 txt 文件