XSLT 2.0,模板和匹配

时间:2015-09-30 16:43:05

标签: xml xslt

XSLT新手(提前谢谢)

我有一个包含付款数据的XML文件。我试图将其转换为银行使用的xml格式。 XML需要根据付款类型(紧急付款/电汇,标准付款/ ETF或人工付款)而有所不同。在给定文件中可以进行多次付款。以下是源XML的示例(简化,两个事务,都是相同的支付类型)

<Payments>
 <Payment xmlns:ns="urn:com.bank/paymentconnector">
  <Payment_Detail>
   <Payment_Info>
    <ns:PAYMENT_Payment_Memo>Payment Info1</ns:PAYMENT_Payment_Memo>
    <ns:PAYMENT_Payment_Amount>1111</ns:PAYMENT_Payment_Amount>
    <ns:PAYMENT_Type>Wire</ns:PAYMENT_Type>
    <ns:PAYMENT_Currency_Code>USD</ns:PAYMENT_Currency_Code>
    <ns:PAYMENT_Check_or_Advice_Number>0</ns:PAYMENT_Check_or_Advice_Number>
  </Payment_Info>
 <Payer_Data>
    <ns:PAYER_Company_Name>Company, LLP</ns:PAYER_Company_Name>
    <ns:PAYER_Address_Line_1>Main st</ns:PAYER_Address_Line_1>
    <ns:PAYER_Address_Line_2>Line 2</ns:PAYER_Address_Line_2>
    <ns:PAYER_City>Cleveland</ns:PAYER_City>
    <ns:PAYER_Zip_Code>11111</ns:PAYER_Zip_Code>
    <ns:PAYER_Country>US</ns:PAYER_Country>
    <ns:PAYER_Account_Number>1111-11111111</ns:PAYER_Account_Number>
    <ns:PAYER_Currency>USD</ns:PAYER_Currency>
 </Payer_Data>
 <Payee_Data>
    <ns:PAYEE_Name>Name</ns:PAYEE_Name>
    <ns:PAYEE_Bank_Name>Bank Name</ns:PAYEE_Bank_Name>
    <ns:PAYEE_Bank_Account_Name>Account Name</ns:PAYEE_Bank_Account_Name>
    <ns:PAYEE_Account_Number>1111111</ns:PAYEE_Account_Number>
    <ns:PAYEE_Masked_Account_Number>********** </ns:PAYEE_Masked_Account_Number>
    <ns:PAYEE_Account_Type>DD</ns:PAYEE_Account_Type>
    <ns:PAYEE_Routing_Transit_Number>22222</ns:PAYEE_Routing_Transit_Number>
    <ns:PAYEE_Bank_Country>US</ns:PAYEE_Bank_Country>
    </Payee_Data>
   </Payment_Detail>
  </Payment>
<Payment>
  <Payment_Detail>
   <Payment_Info>
    <ns:PAYMENT_Payment_Memo>Payment Info2</ns:PAYMENT_Payment_Memo>
    <ns:PAYMENT_Payment_Amount>22222</ns:PAYMENT_Payment_Amount>
    <ns:PAYMENT_Type>Wire</ns:PAYMENT_Type>
    <ns:PAYMENT_Currency_Code>USD</ns:PAYMENT_Currency_Code>
    <ns:PAYMENT_Check_or_Advice_Number>0</ns:PAYMENT_Check_or_Advice_Number>
 </Payment_Info>
 <Payer_Data>
    <ns:PAYER_Company_Name>Company, LLP</ns:PAYER_Company_Name>
    <ns:PAYER_Address_Line_1>Main st</ns:PAYER_Address_Line_1>
    <ns:PAYER_Address_Line_2>Line 2</ns:PAYER_Address_Line_2>
    <ns:PAYER_City>Cleveland</ns:PAYER_City>
    <ns:PAYER_Zip_Code>11111</ns:PAYER_Zip_Code>
    <ns:PAYER_Country>US</ns:PAYER_Country>
    <ns:PAYER_Account_Number>1111-11111111</ns:PAYER_Account_Number>
    <ns:PAYER_Currency>USD</ns:PAYER_Currency>
 </Payer_Data>
 <Payee_Data>
    <ns:PAYEE_Name>Name</ns:PAYEE_Name>
    <ns:PAYEE_Bank_Name>Bank Name</ns:PAYEE_Bank_Name>
    <ns:PAYEE_Bank_Account_Name>Account Name</ns:PAYEE_Bank_Account_Name>
    <ns:PAYEE_Account_Number>1111111</ns:PAYEE_Account_Number>
    <ns:PAYEE_Masked_Account_Number>**********</ns:PAYEE_Masked_Account_Number>
    <ns:PAYEE_Account_Type>DD</ns:PAYEE_Account_Type>
    <ns:PAYEE_Routing_Transit_Number>22222</ns:PAYEE_Routing_Transit_Number>
    <ns:PAYEE_Bank_Country>US</ns:PAYEE_Bank_Country>
 </Payee_Data>
</Payment_Detail>
</Payments>   

这是我的(简化)输出

 <?xml version="1.0" encoding="UTF-8"?>
   <!-- urgent payment-->
   <urgent_payment_header>
    <header_fields/>
    </urgent_payment_header>
    <paymentrec>
     <recordType>5</recordType>
     <payerAccNum>1111-11111111</payerAccNum>
     <!-- (other fields)-->
    </paymentrec>
    <paymentrec>
     <recordType>5</recordType>
    <payerAccNum></payerAccNum>
    <!-- continue with any other urgent payments in the file-->
   </paymentrec>
   <urgent_control_fields>
   </urgent_control_fields>

   <!-- standard payment-->
  <standard_payment_header>
  <header_fields/>
  </standard_payment_header>
  <paymentrec>
   <recordType>4</recordType>
   <payerAccNum>1111-11111111</payerAccNum>
    <!-- (other fields)-->
   </paymentrec>
   <paymentrec>
   <recordType>4</recordType>
   <payerAccNum></payerAccNum>
    <!-- continue with any other standard payments in the file-->
   </paymentrec>
   <standard_control_fields>
   </standard_control_fields>

  <!-- catch all payments-->
  <catchall_payment_header>
  <header_fields/>
  </catchall_payment_header>
  <paymentrec>
  <recordType>3</recordType>
  <payerAccNum>1111-11111111</payerAccNum>
<!-- (other fields)-->
   </paymentrec>
   <paymentrec>
   <recordType>3</recordType>
   <payerAccNum></payerAccNum>
    <!-- continue with any other catchall payments in the file-->
   </paymentrec>
   <catchall_control_fields>
   </catchall_control_fields>

我的XSLT在源文件中的所有付款都是相同类型(所有紧急,所有标准,所有其他类型)和一个标题,列出的付款记录然后一个控制记录

时有效

但是,当支付类型混合时(例如,一个紧急和一个标准),则只有标题,第一个节点和控制记录被写入输出。如果文件包含紧急付款/电汇和标准付款,我希望输出为

这是我的(简化的XSLT)

 <!-- Begin writing the output-->
  <xsl:template match="Payments">
  <xsl:choose>
       <xsl:when test="Payment/Payment_Detail/Payment_Info[ns:PAYMENT_Type != 'Wire']">
                <xsl:call-template select="Payment-Header"/>
                <xsl:apply-templates select="Payment"/>
                <xsl:call-templates select="Payment-Control-Standard"/>
      </xsl:when>
       <xsl:when test="Payment/Payment_Detail/Payment_Info[ns:PAYMENT_Type = 'Wire']">
                 <xsl:call-template select="Payment-Header"/>
                 <xsl:apply-templates select="Payment"/> 
                 <xsl:call-template name="Payment-Control-Urgent"/>
       </xsl:when>
       <xsl:otherwise>
                 <xsl:call-template name="Payment-Header"/>
                 <xsl:apply-templates select="Payment"/> 
                 <xsl:call-template name="Payment-Control-CatchAll"/>
       </xsl:otherwise>
   </xsl:choose> 
  </xsl:template>


<xsl:template match="Payment">
    <xsl:choose>
        <xsl:when test="Payment_Detail/Payment_Info[ns:PAYMENT_Type != 'Wire']">
                <xsl:call-template name="Payment-Standard"/>  
        </xsl:when>
        <xsl:when test="Payment_Detail/Payment_Info[ns:PAYMENT_Type = 'Wire']">
                <xsl:call-template name="Payment-Urgent"/>
        </xsl:when>
        <xsl:otherwise>
                <xsl:call-template name="Payment-CatchAll"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!-- End writing the output-->

<!-- Begin template details-->

    <xsl:template name="Payment-Header">
        <header>
            (header fields, details not important)
        </header>
    </xsl:template>


<xsl:template name="Payment-Control-Standard">
    <control>
        <numberOfPayments>count of standard payments in the file</numberOfPayments>
        <sumOfPayments>sum of standard payments in the file</sumOfPayments>
    </control>  
</xsl:template>

<xsl:template name="Payment-Control-Urgent">
    <control>
        <numberOfPayments>count of urgent payments in the file</numberOfPayments>
        <sumOfPayments>sum of urgent payments in the file</sumOfPayments>
    </control>  
</xsl:template>

<xsl:template name="Payment-Control-CatchAll">
    <control>
        <numberOfPayments>count of catch all payments in the file</numberOfPayments>
        <sumOfPayments>sum of catch all payments in the file</sumOfPayments>
    </control>  
</xsl:template>

<xsl:template name="Payment-Standard">
 <paymentrec>
        (payment fields, details not important)
 </paymentrec>
</xsl:template>

<xsl:template name="Payment-Urgent">
  <paymentrec>
        (payment fields, details not important)           
  </paymentrec>
 </xsl:template>

<xsl:template name="Payment-CatchAll">
  <paymentrec>
        (payment fields, details not important)           
  </paymentrec>
 </xsl:template>

2 个答案:

答案 0 :(得分:0)

的事情
<xsl:template match="Payments">
  <xsl:choose>
       <xsl:when test="Payment/Payment_Detail/Payment_Info/ns:PAYMENT_Type != 'Wire']">

如果至少一个 Payment元素且PAYMENT_Type不是'Wire',则评估为true。这可能不是你想要的。

如果要将输入中的一条记录转换为输出中的一条记录而没有其他任何记录要做,那么您不需要通用模板Payments。因此,我建议完全删除Payments的模板,并在Payment模板中执行重要的操作。

Payment的当前模板中,我可以看到两个问题:

  • 由于Martin Honnen已经出局,你在那里遇到语法错误:]是多余的。

  • 通过xsl:apply-templates调用模板,您的上下文节点已经Payment,因此XPath表达式中的Payment是错误的。

答案 1 :(得分:0)

虽然,我仍然不能100%确定我得到你想要的东西,但我会再试一次。

我在为“付款方式”添加另一个案例时,对您的输入XML进行了一些简化。现在看起来像这样:

<Payments xmlns:ns="urn:com.bank/paymentconnector">
    <Payment>
        <Payment_Detail>
            <Payment_Info>
                <ns:PAYMENT_Type>Wire</ns:PAYMENT_Type>
            </Payment_Info>
            <Payer_Data>
                <ns:PAYER_Company_Name>Company1</ns:PAYER_Company_Name>
            </Payer_Data>
        </Payment_Detail>
    </Payment>

    <Payment>
        <Payment_Detail>
            <Payment_Info>
                <ns:PAYMENT_Type>Wire</ns:PAYMENT_Type>
            </Payment_Info>
            <Payer_Data>
                <ns:PAYER_Company_Name>Company2</ns:PAYER_Company_Name>
            </Payer_Data>
        </Payment_Detail>
    </Payment>

    <Payment>
        <Payment_Detail>
            <Payment_Info>
                <ns:PAYMENT_Type>Something else than Wire</ns:PAYMENT_Type>
            </Payment_Info>
            <Payer_Data>
                <ns:PAYER_Company_Name>Company3</ns:PAYER_Company_Name>
            </Payer_Data>
        </Payment_Detail>
    </Payment>

    <Payment>
        <Payment_Detail>
            <Payment_Info>
                <ns:PAYMENT_Type>Something else than Wire</ns:PAYMENT_Type>
            </Payment_Info>
            <Payer_Data>
                <ns:PAYER_Company_Name>Company4</ns:PAYER_Company_Name>
            </Payer_Data>
        </Payment_Detail>
    </Payment>   
</Payments>

现在,如果我说得对,那么您需要为每种不同的付款方式添加标题,并为每条记录提供一些详细信息。我建议在for-each-groups中这样做:

    <?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 xmlns:ns="urn:com.bank/paymentconnector"
 version="2.0">
     <xsl:template match="/">
      <any_root_element>
          <xsl:for-each-group select="//Payment" group-by="Payment_Detail/Payment_Info/ns:PAYMENT_Type">
            <xsl:choose>
                <xsl:when test="current-grouping-key() = 'Wire'">
                    <header_for_wire/>
                    <xsl:for-each select="current-group()">
                        <paymentrec>
                        <details>
                        Paid by <xsl:value-of select="Payment_Detail/Payer_Data/ns:PAYER_Company_Name"/>
                        </details>
                        </paymentrec>
                    </xsl:for-each>
                </xsl:when>

                <xsl:when test="current-grouping-key() = 'Something else than Wire'">
                    <header_for_something_else_than_wire/>
                    <xsl:for-each select="current-group()">
                    <paymentrec>
                        <details>
                        Paid by <xsl:value-of select="Payment_Detail/Payer_Data/ns:PAYER_Company_Name"/>
                        </details>
                    </paymentrec>    
                    </xsl:for-each>
                </xsl:when>
            </xsl:choose>

        </xsl:for-each-group>

      </any_root_element>
    </xsl:template>
</xsl:transform>

这将导致此XML:

<any_root_element>
    <header_for_wire/>
    <paymentrec>
        <details> Paid by Company1</details>
    </paymentrec>
    <paymentrec>
        <details> Paid by Company2</details>
    </paymentrec>
    <header_for_something_else_than_wire/>
    <paymentrec>
        <details> Paid by Company3</details>
    </paymentrec>
    <paymentrec>
        <details> Paid by Company4</details>
    </paymentrec>
</any_root_element>

这或多或少是你想要的吗? (当然,如果细节很常见,您可能需要为它构建一个模板,以避免重复。)