XSLT to text - 具有相同名称的子节点 - 检查每个父节点的最后一个子节点

时间:2018-05-29 20:27:36

标签: xml xslt

我需要使用XSLT将XML转换为Text。我得到的输出包含一个没有分隔符或新换行符的块中的所有数据,我觉得XSLT中的位置部分甚至没有被执行。

问题:我想测试每个父项的最后一个子项的位置,如果它是父项(currentRow)的最后一个子项(columnvalue),则包含一个新行,如果是&#,则包含一个分隔符39;不是。

我有一个XML,如下所示:

XML文件:

<?xml version='1.0'?>
<webRowSet xmlns='http://java.sun.com/xml/ns/jdbc'>
<data>
<currentRow>
<columnValue><![CDATA[]]></columnValue>
<columnValue><![CDATA[26068384]]></columnValue>
<columnValue><![CDATA[070-0010055-4842MAR18]]></columnValue>
<columnValue>2018-04-25</columnValue>
<columnValue>170.310</columnValue>
<columnValue><![CDATA[UI-004058]]></columnValue>
</currentRow>
<currentRow><columnValue><![CDATA[]]></columnValue>
<columnValue><![CDATA[26068385]]></columnValue>
<columnValue><![CDATA[070-0010058-5739MAR18]]></columnValue>
<columnValue>2018-04-25</columnValue>
<columnValue>209.900</columnValue>
<columnValue><![CDATA[UI-004057]]></columnValue>
</currentRow>
</data></webRowSet>

XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="Delimiter"><xsl:text>|</xsl:text></xsl:variable>
<xsl:variable name="NewLine"><xsl:text>&#10;</xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
<xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="webRowSet/data">
<xsl:for-each select="currentRow">
<xsl:for-each select="columnValue">
<xsl:value-of select="."/>
<xsl:variable name="Rec_position" select="count(../preceding-sibling::columnValue)+1"/>
<xsl:if test="$Rec_position=6"><xsl:value-of select="$NewLine"/></xsl:if>
<xsl:if test="$Rec_position!=6"><xsl:value-of select="$Delimiter"/></xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

TEXT中的输出应该是:

EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo
   |26068384|070-0010055-4842MAR18|2018-04-25|170.310|UI-004058
   |26068385|070-0010058-5739MAR18|2018-04-25|209.900|UI-004057

2 个答案:

答案 0 :(得分:0)

XSLT中存在两个问题。

首先,您没有考虑到XML中的元素位于默认命名空间中这一事实,如根元素上的xmlns='http://java.sun.com/xml/ns/jdbc所定义。

如果您确实只使用XSLT 1.0,则必须将该命名空间与XSLT中的前缀相关联,如此...

xmlns:j="http://java.sun.com/xml/ns/jdbc"

然后在select表达式中的所有元素之前使用该前缀。例如......

 <xsl:template match="j:webRowSet/j:data">

其次,在你的count考试中,..表示父节点,当你真的想要计算当前节点的前一个兄弟节点时,你应该写这个......

 <xsl:variable name="Rec_position" select="count(preceding-sibling::j:columnValue)+1"/>

虽然position()函数在这里会做同样的事情。

<xsl:variable name="Rec_position" select="position()"/>

但是你真的想把列数硬编码为6吗?试试这个XSLT:

<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:j="http://java.sun.com/xml/ns/jdbc">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>

<xsl:strip-space elements="*"/>

<xsl:variable name="Delimiter"><xsl:text>|</xsl:text></xsl:variable>
<xsl:variable name="NewLine"><xsl:text>&#10;</xsl:text></xsl:variable>

<xsl:template match="/">
  <xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
  <xsl:value-of select="$NewLine"/>
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="j:webRowSet/j:data">
  <xsl:for-each select="j:currentRow">
    <xsl:for-each select="j:columnValue">
      <xsl:if test="position() != 1"><xsl:value-of select="$Delimiter" /></xsl:if>
      <xsl:value-of select="."/>
    </xsl:for-each>
    <xsl:value-of select="$NewLine"/>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

注意,如果你可以使用XSLT 2.0,你可以这样写:

<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xpath-default-namespace="http://java.sun.com/xml/ns/jdbc">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="NewLine"><xsl:text>&#10;</xsl:text></xsl:variable>

<xsl:template match="/">
  <xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
  <xsl:value-of select="$NewLine"/>
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="webRowSet/data">
  <xsl:for-each select="currentRow">
    <xsl:value-of select="columnValue" separator="|"/>
    <xsl:value-of select="$NewLine"/>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

请注意使用xpath-default-namespace可以更轻松地处理默认命名空间。此外,在选择多个值时适用的separator上使用xsl:value-of。 (在XSLT 1.0中,xsl:value-of只显示第一个值。)

答案 1 :(得分:0)

您忘了考虑名称空间。因此,将xmlns:j="http://java.sun.com/xml/ns/jdbc"添加到XSLT文件的xsl:stylesheet元素中。这样,您就可以使用正确的命名空间访问所有元素。

关于命名空间,将您的上一个模板更改为:

<xsl:template match="j:webRowSet/j:data">
    <xsl:for-each select="j:currentRow">
      <xsl:for-each select="j:columnValue">
        <xsl:value-of select="."/>
        <xsl:variable name="Rec_position" select="position()"/>
        <xsl:if test="$Rec_position=6"><xsl:value-of select="$NewLine"/></xsl:if>
        <xsl:if test="$Rec_position &lt; 6"><xsl:value-of select="$Delimiter"/></xsl:if>
      </xsl:for-each>
    </xsl:for-each>
</xsl:template>

输出为:

EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo
|26068384|070-0010055-4842MAR18|2018-04-25|170.310|UI-004058
|26068385|070-0010058-5739MAR18|2018-04-25|209.900|UI-004057

这是一个非常简单的解决方案,只需要进行最少的修改。