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

发布于 2024-10-21 20:45:08 字数 1553 浏览 2 评论 0原文

我有一个 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 -->

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

I have an xml document where values are generated dynamically and i need to export these data to an excel using xslt. For testing purpose I have created a sample 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>

The xslt is as follows:-

= tab = new line -->

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

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


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

I was able to export all the data properly into excel except for data in tag "classRef" which appears together as "Test1Test2Test3" , but i need them separately in different columns of excel.
Can anybody provide some clue on this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

謌踐踏愛綪 2024-10-28 20:45:08

我猜您希望这三个值以制表符分隔?在这种情况下,我倾向于这样做(在 XSLT 2.0 中)

<xsl:for-each select="/ucdetector/markers/marker">
    <xsl:variable name="vars">
        <xsl:value-of select="classRef" separator="'	'"/>
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '	', $vars, '	', markerType, '
')" />
</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>	</xsl:text></xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '	', $vars, '	', markerType, '
')" />
</xsl:for-each>

I guess you want the three values to be tab-separated? In which case I would be inclined to do this (in XSLT 2.0)

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

or in 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>	</xsl:text></xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:value-of
        select="concat(description, '	', $vars, '	', markerType, '
')" />
</xsl:for-each>
浮云落日 2024-10-28 20:45:08

你的问题有点不清楚。我认为您想要做的是发出 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">	</xsl:variable>
 <xsl:variable name="newline">
</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>

Your question's a little unclear. I think what you're trying to do is emit the text of all of the child elements of the marker element, separated by tabs, as a line of text terminated with a newline. Is that right?

If so, I don't see any benefit of creating a variable that contains the classRef elements all concatenated together - you're not treating them any differently than you are the other elements. You can just use a simple template to transform each marker element into an output line:

 <!-- 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">	</xsl:variable>
 <xsl:variable name="newline">
</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>

Edit:

Okay, the example you posted clarifies what you're looking for. What you want is one line in the output for each classRef element, not each marker element. Every line should have the same number of tabs, and be terminated with a newline. But the first line for any given marker element should contain data for the non-classRef elements, while the remaining lines should only contain data for the classRef elements.

This should do the trick:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文