You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

适配多表头Base64 CSV的XSLT多XML文档生成方案问询

问题描述

CSV文件的行经过Base64编码后存入XML对象模型,再映射到目标XML Schema。现有代码在单表头场景下运行正常,需要适配多表头场景:Base64解码后,第9位字段值为2的行是表头行,需要为每个表头生成独立的XML文档。

当前XSLT代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:extensions="http://www.infor.com/ION/XSL/extensions" exclude-result-prefixes="extensions" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="SyncMySupplierInvoice">
<SyncPurchaseOrder>
<xsl:apply-templates select="ApplicationArea"/>
<xsl:apply-templates select="DataArea"/>
</SyncPurchaseOrder>
</xsl:template>
<xsl:template match="ApplicationArea">
<xsl:element name="ApplicationArea">
<xsl:copy-of select="*"/>
</xsl:element>
</xsl:template>
<xsl:template match="DataArea">
<xsl:element name="DataArea">
<xsl:apply-templates select="Sync"/>
<xsl:apply-templates select="MySupplierInvoice/RawData"/>
</xsl:element>
</xsl:template>
<xsl:template match="Sync">
<xsl:element name="Load">
<TenantID>XXXXXXX</TenantID>
<AccountingEntityID>510</AccountingEntityID>
<LocationID/>
<ActionCriteria>
<ActionExpression actionCode="Add"/>
</ActionCriteria>
</xsl:element>
</xsl:template>
<xsl:template match="MySupplierInvoice/RawData">
<xsl:variable name="b64" select="extensions:decodeString(string(.))"/>
<xsl:variable name="Header" select="$b64"/>
<xsl:variable name="locCurrency" select="tokenize($Header,',')[position() = 8]"/>
<SupplierInvoice>
<SupplierInvoiceHeader>
<DocumentID>
<ID>
<xsl:value-of select="tokenize($Header,',')[position()=1]"/>
</ID>
</DocumentID>
<AlternateDocumentID>
<ID>
<xsl:value-of select="tokenize($Header,',')[position()=4]"/>
</ID>
</AlternateDocumentID>
<DocumentDateTime>
<xsl:value-of select=" tokenize($Header,',')[position()=6]"/>
</DocumentDateTime>
<LastModificationDateTime/>
<Description>
<xsl:value-of select="tokenize($Header,',')[position()=5]"/>
</Description>
<xsl:element name="TotalAmount">
<xsl:attribute name="currencyID">
<xsl:value-of select="$locCurrency"/>
</attribute>
<xsl:value-of select="tokenize($Header,',')[position() = 7]"/>
</element>
<RemitToParty/>
<PurchaseOrderReference>
<DocumentID>
<ID/>
</DocumentID>
</PurchaseOrderReference>
<BillFromParty>
<PartyIDs>
<ID>
<xsl:value-of select="tokenize($Header,',')[position() = 3]"/>
</ID>
<TaxID/>
<ID/>
</PartyIDs>
<Name/>
</BillFromParty>
</SupplierInvoiceHeader>
<xsl:for-each select="tokenize($Header,' ')">
<xsl:variable name="Line" select="."/>
<xsl:if test="position() != 1">
<!--    <xsl:if test="not(tokenize($Line,',')[position() = 9] = tokenize($Header,',')[position() = 9])">  -->
<SupplierInvoiceLine>
<LineNumber>
<xsl:value-of select="tokenize($Line,',')[position() = 9]"/>
</LineNumber>
<Description>
<xsl:value-of select="tokenize($Line,',')[position() =11]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="tokenize($Line,',')[position() =12]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="tokenize($Line,',')[position() =13]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="tokenize($Line,',')[position() =14]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="tokenize($Line,',')[position() =15]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="tokenize($Line,',')[position() =16]"/>
</Description>
<Quantity unitCode="PCE">1.00</Quantity>
<ItemID> </ItemID>
<UnitPrice>
<xsl:element name="Amount">
<xsl:attribute name="currencyID">
<xsl:value-of select="$locCurrency"/>
</attribute>
<xsl:value-of select="tokenize($Line,',')[position() = 22]"/>
</element>
<PerQuantity unitCode="PCE">1</PerQuantity>
</UnitPrice>
<xsl:element name="ExtendedAmount">
<xsl:attribute name="currencyID">
<xsl:value-of select="$locCurrency"/>
</attribute>
<xsl:value-of select="tokenize($Line,',')[position() = 22]"/>
</element>
<PurchaseOrderReference>
<DocumentID>
<ID/>
</DocumentID>
</PurchaseOrderReference>
<Tax>
<xsl:element name="BasisAmount">
<xsl:attribute name="currencyID">
<xsl:value-of select="$locCurrency"/>
</attribute>
<xsl:value-of select="tokenize($Line,',')[position() = 22]"/>
</element>
<Calculation>
<xsl:variable name="BaseAmount" select="tokenize($Line,',')[position() = 22]"/>
<xsl:variable name="VatAmount" select="tokenize($Line,',')[position() = 23]"/>
<!-- <xsl:variable name="VatAmount" select="substring-before($VatAmount, '&#xD;&#xA;')"/>  -->
<xsl:variable name="VatAmount" as="xs:double" select="if($VatAmount castable as xs:double) then xs:double($VatAmount) else 0"/>
<!--  <xsl:value-of select="$VatAmount"/>  -->
<RateNumeric>
<xsl:value-of select="round($VatAmount div number($BaseAmount),3)"/>
</RateNumeric>
</Calculation>
<xsl:element name="Amount">
<xsl:attribute name="currencyID">
<xsl:value-of select="$locCurrency"/>
</attribute>
<xsl:variable name="Amount" select="tokenize($Line,',')[position() = 23]"/>
<xsl:value-of select="$Amount"/>
</element>
</Tax>
</SupplierInvoiceLine>
<!--     <xsl:if test="not(tokenize($Line,',')[position() = 9] = tokenize($Header,',')[position() = 9])">  -->
<!--     Is this the right position to create a second XML Document Load.SupplierInvoice ?                 -->
<!--     How do I have to configure the code ???                                                           -->
<!--     </xsl:if>                                                                                         -->
</xsl:if>
</xsl:for-each>
</SupplierInvoice>
</xsl:template>
</xsl:stylesheet>

CSV示例

11,Kostenrechnung,200000001,5511,701 -XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,2,XXXXX,,,,,,,,,,,Haben,1191.95,0
11,Kostenrechnung,200000001,5511,701 - XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,3,XXXXX,49450,210001,,,,,Einkauf,DE,120,Netto,Soll,328.23,22.98
11,Kostenrechnung,200000001,5511,701 - XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,4,XXXXX,49450,210001,,,,,Einkauf,,0,Netto,Soll,254.54,0
11,Kostenrechnung,200000001,5511,701 - XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,5,XXXXX,49480,410002,,,,,Einkauf,,0,Netto,Soll,78,0
11,Kostenrechnung,200000001,5511,701 - XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,6,XXXXX,49800,999998,3000,,,,Einkauf,,0,Netto,Soll,139.8,0
11,Kostenrechnung,200000001,5511,701 - XXXXX,2022-08-15T09:00:00Z,1191.95,EUR,7,XXXXX,49690,210001,,,,,Einkauf,,0,Netto,Soll,368.4,0
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,2,XXXXX,,,,,,,,,,,Haben,773.55,0
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,3,XXXXX,49450,210001,,,,,Einkauf,DEU,000,Netto,Soll,36.40,0.00
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,4,XXXXX,49450,210001,,,,,Einkauf,DEU,000,Netto,Soll,54.00,0.00
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,5,XXXXX,49450,210001,,,,,Einkauf,DEU,000,Netto,Soll,97.20,0.00
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,6,XXXXX,49800,999998,3000,,,,Einkauf,DEU,000,Netto,Soll,488.40,0.00
13,Kostenrechnung,200000003,5512,701 - XXXXX,2022-08-30T09:00:00Z,773.55,EUR,7,XXXXX,49800,999998,3000,,,,Einkauf,DEU,132,Netto,Soll,81.97,15.58

修改后的XSLT方案

核心思路:

  1. 将解码后的CSV按行拆分,过滤空行
  2. 使用xsl:for-each-group按表头行(第9字段=2)分组,每组包含一个表头和后续的明细行
  3. 为每个分组生成独立的SyncPurchaseOrder文档
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:extensions="http://www.infor.com/ION/XSL/extensions" exclude-result-prefixes="extensions" version="2.0">
    <xsl:output method="xml" indent="yes"/>

    <!-- 主模板:为每个发票分组生成独立的SyncPurchaseOrder -->
    <xsl:template match="SyncMySupplierInvoice">
        <xsl:variable name="appArea" select="ApplicationArea"/>
        <xsl:variable name="syncNode" select="DataArea/Sync"/>
        <xsl:variable name="decodedCsv" select="extensions:decodeString(string(DataArea/MySupplierInvoice/RawData))"/>
        <!-- 拆分CSV为行,过滤空行 -->
        <xsl:variable name="csvLines" select="tokenize($decodedCsv, '&#10;')[normalize-space(.) ne '']"/>
        
        <!-- 按表头行分组 -->
        <xsl:for-each-group select="$csvLines" group-starting-with=".[tokenize(., ',')[9] = '2']">
            <SyncPurchaseOrder>
                <xsl:copy-of select="$appArea"/>
                <DataArea>
                    <xsl:copy-of select="$syncNode"/>
                    <!-- 处理当前分组的发票 -->
                    <xsl:call-template name="processInvoiceGroup">
                        <xsl:with-param name="headerLine" select="current-group()[1]"/>
                        <xsl:with-param name="detailLines" select="current-group()[position() > 1]"/>
                    </xsl:call-template>
                </DataArea>
            </SyncPurchaseOrder>
        </xsl:for-each-group>
    </xsl:template>

    <!-- 处理单个发票分组:表头+明细 -->
    <xsl:template name="processInvoiceGroup">
        <xsl:param name="headerLine"/>
        <xsl:param name="detailLines"/>
        <xsl:variable name="headerFields" select="tokenize($headerLine, ',')"/>
        <xsl:variable name="locCurrency" select="$headerFields[8]"/>

        <SupplierInvoice>
            <SupplierInvoiceHeader>
                <DocumentID>
                    <ID><xsl:value-of select="$headerFields[1]"/></ID>
                </DocumentID>
                <AlternateDocumentID>
                    <ID><xsl:value-of select="$headerFields[4]"/></ID>
                </AlternateDocumentID>
                <DocumentDateTime><xsl:value-of select="$headerFields[6]"/></DocumentDateTime>
                <LastModificationDateTime/>
                <Description><xsl:value-of select="$headerFields[5]"/></Description>
                <TotalAmount currencyID="{$locCurrency}">
                    <xsl:value-of select="$headerFields[7]"/>
                </TotalAmount>
                <RemitToParty/>
                <PurchaseOrderReference>
                    <DocumentID><ID/></DocumentID>
                </PurchaseOrderReference>
                <BillFromParty>
                    <PartyIDs>
                        <ID><xsl:value-of select="$headerFields[3]"/></ID>
                        <TaxID/>
                        <ID/>
                    </PartyIDs>
                    <Name/>
                </BillFromParty>
            </SupplierInvoiceHeader>

            <!-- 处理明细行 -->
            <xsl:for-each select="$detailLines">
                <xsl:variable name="lineFields" select="tokenize(., ',')"/>
                <SupplierInvoiceLine>
                    <LineNumber><xsl:value-of select="$lineFields[9]"/></LineNumber>
                    <Description>
                        <xsl:value-of select="$lineFields[11]"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$lineFields[12]"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$lineFields[13]"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$lineFields[14]"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$lineFields[15]"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$lineFields[16]"/>
                    </Description>
                    <Quantity unitCode="PCE">1.00</Quantity>
                    <ItemID/>
                    <UnitPrice>
                        <Amount currencyID="{$locCurrency}"><xsl:value-of select="$lineFields[2
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 23:45:36