xslt根据服务响应更改输出

时间:2017-07-10 09:43:41

标签: xml xslt soap

我正在转换像这样的XML文件......

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <swiftResponseResponse xmlns="http://webservice.sbi.com">
         <swiftResponseReturn>15617TS006140|DC768736|13321.49|04-05-2017 15:13:03|SWIFTINR|NA|FAIL-ACCOUNT UNAVAILABLE</swiftResponseReturn>
      </swiftResponseResponse>
   </soapenv:Body>
</soapenv:Envelope>

...通过这个XSL样式表:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://webservice.sbi.com" exclude-result-prefixes="soapenv xsl  xsd xsi xs ">
       <xsl:output omit-xml-declaration="yes" indent="yes"/>
       <xsl:template name="tokenize">
              <xsl:param name="text"/>
              <xsl:param name="separator" />
              <xsl:param name="index" select="1"/>
              <xsl:choose>
                     <xsl:when test="not(contains($text, $separator))">
                           <xsl:element name="swiftResponseReturnValue_{$index}">
                                  <xsl:value-of select="$text"/>
                           </xsl:element>
                     </xsl:when>
                     <xsl:otherwise>
        <xsl:element name="swiftResponseReturnValue_{$index}">
                                  <xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
                           </xsl:element>
                           <xsl:call-template name="tokenize">
                                  <xsl:with-param name="text" select="substring-after($text, $separator)"/>
                                  <xsl:with-param name="separator" select="$separator"/>
                                  <xsl:with-param name="index" select="$index + 1"/>
                           </xsl:call-template>
                     </xsl:otherwise>
              </xsl:choose>
       </xsl:template>
       <xsl:template match="xs:swiftResponseReturn">
              <swiftResponseReturn>
                     <xsl:call-template name="tokenize">
                           <xsl:with-param name="text" select="."/>
                           <xsl:with-param name="separator" select="'|'"/>
                     </xsl:call-template>
              </swiftResponseReturn>
       </xsl:template>
</xsl:stylesheet>

对于给定的示例输入XML,此转换产生所需的结果:

<swiftResponseReturn>
    <swiftResponseReturnValue_1>15617TS006140</swiftResponseReturnValue_1>
    <swiftResponseReturnValue_2>DC768736</swiftResponseReturnValue_2>
    <swiftResponseReturnValue_3>13321.49</swiftResponseReturnValue_3>
    <swiftResponseReturnValue_4>04-05-2017 15:13:03</swiftResponseReturnValue_4>
    <swiftResponseReturnValue_5>SWIFTINR</swiftResponseReturnValue_5>
    <swiftResponseReturnValue_6>NA</swiftResponseReturnValue_6>
    <swiftResponseReturnValue_7>FAIL-ACCOUNT UNAVAILABLE</swiftResponseReturnValue_7>
</swiftResponseReturn>

但是,如果应用程序输入不正确,则转换为转换的XML将改为:

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <swiftResponseResponse xmlns="http://webservice.sbi.com">
         <swiftResponseReturn>15617TS006140||NO RECORDS FOUND</swiftResponseReturn>
      </swiftResponseResponse>
   </soapenv:Body>
</soapenv:Envelope>

生成的XML输出是......

    <swiftResponseReturn>
    <swiftResponseReturnValue_1>15617TS006140</swiftResponseReturnValue_1>
    <swiftResponseReturnValue_2/>
    <swiftResponseReturnValue_3>NO RECORDS FOUND</swiftResponseReturnValue_3>
</swiftResponseReturn>

...但在这种情况下,我希望产生这样的结果:

  <swiftResponseReturn>
                <swiftResponseReturnValue_1>15617TS006140</swiftResponseReturnValue_1>
                <swiftResponseReturnValue_2></swiftResponseReturnValue_2>
                <swiftResponseReturnValue_3></swiftResponseReturnValue_3>
                <swiftResponseReturnValue_4></swiftResponseReturnValue_4>
                <swiftResponseReturnValue_5></swiftResponseReturnValue_5>
                <swiftResponseReturnValue_6></swiftResponseReturnValue_6>
                <swiftResponseReturnValue_7>NO RECORDS FOUND</swiftResponseReturnValue_7>
</swiftResponseReturn>

。如何在无效输入的情况下修改样式表以产生上述输出,但仍然在有效输入的情况下产生与现在相同的输出?

1 个答案:

答案 0 :(得分:1)

我从你想要的输出中推断出你希望输出树中总是有<swiftResponseReturnValue_*>个元素,在最后一个之前插入空元素,如果有必要,填充计数那个数字。您可以修改样式表来执行此操作。

目前,您的&#34;标记化&#34;模板通过分隔符字符串是否出现在提供的文本中来测试它是否已到达最后一个元素。那不是你想要的;相反,您必须根据到目前为止发出的元素数量更改为一个标准,它可以从$index参数中确定。

您希望前六个元素中的每一个都具有相同的行为:

  • 发出一个返回值元素,如果有任何
  • ,则包含分隔符前面当前文本的子字符串
  • 递归

另一方面,对于第七个元素,您只需发出包含文本尾部的返回值。唯一的问题是,当tokenize递归时,它必须绑定到$text参数的值取决于分隔符字符串是否出现在当前文本中。如果是这样,它必须在分隔符之后发送子字符串;否则,它必须发送全文。没有内置函数可以做到这一点,但您可以通过xsl:with-param正文中的XSL元素来完成。

这是沿着这些行的变化,为每个输入产生所需的输出:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xs="http://webservice.sbi.com"
    exclude-result-prefixes="soapenv xsl xsd xsi xs">

  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="separator" />
    <xsl:param name="index" select="1"/>
    <xsl:choose>
      <xsl:when test="$index &lt; 7">
        <xsl:element name="swiftResponseReturnValue_{$index}">
          <!-- substring-before() returns an empty string when the separator
               string is not found -->
          <xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
        </xsl:element>
        <xsl:call-template name="tokenize">
          <xsl:with-param name="text">
            <xsl:choose>
              <xsl:when test="contains($text, $separator)">
                <xsl:value-of select="substring-after($text, $separator)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="$text"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:with-param>
          <xsl:with-param name="separator" select="$separator"/>
          <xsl:with-param name="index" select="$index + 1"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <swiftResponseReturnValue_7>
          <!-- the tail goes into the seventh return value -->
          <xsl:value-of select="$text"/>
        </swiftResponseReturnValue_7>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="xs:swiftResponseReturn">
    <swiftResponseReturn>
      <xsl:call-template name="tokenize">
        <xsl:with-param name="text" select="."/>
        <xsl:with-param name="separator" select="'|'"/>
      </xsl:call-template>
    </swiftResponseReturn>
  </xsl:template>

</xsl:stylesheet>