防止XSLT 1.0中文件末尾的空白输出行

时间:2014-09-05 14:42:25

标签: xml xslt-1.0 fixed-width

我们每天都有一个外部提供商发送的xml文件,如下所示:

<StreamStart>
    <Stream>
        ... data nodes
    </Stream>
</StreamStart>

<DDIVouchers>
    <Voucher>
        ... data nodes
    </Voucher>
</DDIVouchers>

<StreamEnd>
    <Stream>
        ... data nodes
    </Stream>
</StreamEnd>

我的xslt工作正常,这是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:msg="http://www.voca.com/schemas/messaging" 
     xmlns:cmn="http://www.voca.com/schemas/common" 
     xmlns:str="http://exslt.org/strings" extension-element-prefixes="str" >
<xsl:output method="text" encoding="UTF-8" />
<xsl:strip-space elements="AccountName TransactionCode" />

    <!--
    defined template to convert YYYY-MM-DD into CYYMMDD 
        so 2014-08-14 becomes 1140814 which is good for Equation
    -->
 <xsl:template name="date">
    <xsl:param name="yyyy-mm-dd"/>
    <xsl:variable name="yyyy" select="substring-before($yyyy-mm-dd, '-')"/> <!-- extract the year-->
    <xsl:variable name="mm-dd" select="substring-after($yyyy-mm-dd, '-')"/> <!-- extract the month and day-->
    <xsl:variable name="mm" select="substring-before($mm-dd, '-')"/>            <!-- extract the month-->
    <xsl:variable name="dd" select="substring-after($mm-dd, '-')"/>             <!-- extract the day-->

    <!-- now determine if it will be 0 for before 2000, or 1 for after-->
    <xsl:choose>
      <xsl:when test="substring($yyyy,1,2)='19'">0</xsl:when>
      <xsl:otherwise>1</xsl:otherwise>
    </xsl:choose>
    <xsl:value-of select="substring($yyyy,3,4)"/>
    <xsl:value-of select="$mm"/>
    <xsl:value-of select="$dd"/>
  </xsl:template>

    <!--
    named template to first remove all the leading and trailing spaces, 
    then output the result with a total fixed length of 71 characters
    -->
   <xsl:template name="FormattedPhoneFaxNumber">
      <xsl:param name="text"/>
      <xsl:variable name="noSpaces" select="normalize-space($text)" />
      <xsl:value-of select="substring(concat('                                                                       ', $noSpaces), string-length($noSpaces) + 1)"/>
  </xsl:template>

<xsl:template match="/">
    <!--

    Explanation:
    The instruction:

        <xsl:for-each select="msg:VocaDocument/msg:Data/msg:Document/msg:DDIVouchers/msg:Voucher">

        puts us in the context of Voucher (within the default name-space that has been aliased to 'msg'. In this context, the path:

        "../../StreamStart/Stream/BankName"

        goes "up" to the parent element twice (i.e. to Document) and from there "down" to StreamStart/Stream/BankName where the required value is. 
string-length(../../msg:StreamEnd/msg:Stream/msg:StreamCode)
    -->

    <!-- START LOOP THROUGH ALL VOUCHERS-->
    <xsl:for-each select="msg:VocaDocument/msg:Data/msg:Document/msg:DDIVouchers/msg:Voucher">

        <!-- STREAM START-->
        <xsl:value-of select="substring(concat(../../msg:StreamStart/msg:Stream/msg:BankName, '                                                                      '), 1, 70)"/>
        <xsl:value-of select="substring(concat(../../msg:StreamStart/msg:Stream/msg:BankCode, '0000'), 1, 4)"/>
        <xsl:value-of select="substring(concat('0000', ../../msg:StreamStart/msg:Stream/msg:StreamCode), 3 ,4)"/>
        <xsl:value-of select="../../msg:StreamStart/msg:Stream/msg:VoucherSortCode"/>
        <xsl:value-of select="substring(concat(../../msg:StreamStart/msg:Stream/msg:VoucherAccountNumber, '00000000'), 1, 8)"/>        
        <xsl:value-of select="substring(concat(../../msg:StreamStart/msg:Stream/msg:TotalVouchers, '00000000'), 1, 8)"/>  

        <!-- VOUCHER START-->
        <xsl:value-of select="substring(concat(translate((msg:TransactionCode), ' ',''), '          '), 1, 10)"/> 
        <xsl:value-of select="substring(concat(msg:OriginatorIdentification/msg:ServiceUserName, '                                   '), 1, 35)"/>

        <xsl:value-of select="substring(concat(msg:OriginatorIdentification/msg:ServiceUserNumber, '      '), 1, 6)"/>
        <xsl:value-of select="substring(concat(msg:PayingBankAccount/msg:BankName, '                                                                      '), 1, 70)"/>
        <xsl:value-of select="substring(concat(normalize-space(msg:PayingBankAccount/msg:AccountName), '                  '), 1, 18)"/>
        <xsl:value-of select="substring(concat(normalize-space(msg:PayingBankAccount/msg:AccountNumber), '        '), 1, 8)"/>
        <xsl:value-of select="substring(concat(normalize-space(msg:PayingBankAccount/msg:UkSortCode), '        '), 1, 8)"/>
        <xsl:value-of select="substring(concat(normalize-space(msg:ReferenceNumber), '                  '), 1, 18)"/>

        <xsl:call-template name="FormattedPhoneFaxNumber">
            <xsl:with-param name="text" select="msg:ContactDetails/msg:PhoneNumber" />
        </xsl:call-template>

        <xsl:call-template name="FormattedPhoneFaxNumber">
            <xsl:with-param name="text" select="msg:ContactDetails/msg:FaxNumber" />
        </xsl:call-template>

        <!-- NOTE HOW TO EXTRACT AN ADDRESS ELEMENT THAT HAS ITS OWN NAMESPACE -->
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:AddresseeName, '                                 '), 1, 33)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:PostalName, '                                 '), 1, 33)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:AddressLine, '                                 '), 1, 33)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:TownName, '                              '), 1, 30)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:CountyIdentification, '                                        '), 1, 40)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:CountryName, '                                        '), 1, 40)"/>
        <xsl:value-of select="substring(concat(msg:ContactDetails/msg:Address/cmn:ZipCode, '          '), 1, 10)"/>

        <xsl:call-template name="date">
           <xsl:with-param name="yyyy-mm-dd" select="msg:ProcessingDate"/>
        </xsl:call-template>

        <xsl:value-of select="substring(concat(msg:BankAccount/msg:FirstLastVoucherCode, '               '), 1, 15)"/>
        <xsl:value-of select="substring(concat(msg:BankAccount/msg:AgencyBankCode, '0000'), 1, 4)"/>
        <xsl:value-of select="substring(concat(msg:BankAccount/msg:SortCode, '00000000'), 1, 8)"/>
        <xsl:value-of select="substring(concat(msg:BankAccount/msg:AccountNumber, '00000000'), 1, 8)"/>
        <xsl:value-of select="substring(concat('000000000000000', msg:BankAccount/msg:Counter), string-length(msg:BankAccount/msg:Counter) + 1, 15)"/>

        <!-- STREAM END-->
        <xsl:value-of select="substring(concat(../../msg:StreamEnd/msg:Stream/msg:BankName, '                                                                      '), 1, 70)"/>
        <xsl:value-of select="substring(concat(../../msg:StreamEnd/msg:Stream/msg:BankCode, '0000'), 1, 4)"/>
        <xsl:value-of select="substring(concat('0000', ../../msg:StreamEnd/msg:Stream/msg:StreamCode), 3 ,4)"/>
        <xsl:value-of select="substring(concat(../../msg:StreamEnd/msg:Stream/msg:VoucherSortCode, '00000000'), 1, 8)"/>
        <xsl:value-of select="substring(concat(../../msg:StreamEnd/msg:Stream/msg:VoucherAccountNumber, '00000000'), 1, 8)"/>
        <xsl:value-of select="substring(concat('00000000', ../../msg:StreamEnd/msg:Stream/msg:TotalVouchers), string-length(../../msg:StreamEnd/msg:Stream/msg:TotalVouchers) + 1, 8)"/>

        <!-- CR/LF NEW LINE &#xA;-->
        <xsl:text>&#xD;</xsl:text>

    </xsl:for-each>
</xsl:template> 

</xsl:stylesheet>

这是显示结尾处空行的输出:

enter image description here

在输出输出中,我们最后得到2个空行....对我来说似乎没有理由。

我可以在我的XSLT样式表中添加或更改某些内容,以防止在输出结尾处出现这些额外的空白行(这是一个固定宽度的文本文件,将被加载到另一个会计系统中。

修改

我还尝试在样式表的最后添加这两个模板:

<xsl:template match="text()[not(string-length(normalize-space()))]"/>

<xsl:template match="text()[string-length(normalize-space()) > 0]">
  <xsl:value-of select="translate(.,'&#xA;&#xD;', '  ')"/>
</xsl:template>

(来自SO:5737862 (answer by Dimitre),但我没有运气,或者其他可能是错误的。

编辑2: 额外的行是否可能是MS XMSL 6 DOM Document TransformNode 方法的结果,我在Excel VBA中使用它来生成测试文件输出?

1 个答案:

答案 0 :(得分:2)

您无条件地添加换行符

<!-- CR/LF NEW LINE &#xA;-->
<xsl:text>&#xD;</xsl:text>

请尝试此操作(另请注意,换行符实际为&#xA;):

<xsl:if test="position () &lt; last()">
  <xsl:text>&#xA;</xsl:text>
</xsl:if>