重新编号发票 LineNumber 标签并使用 xslt 将 NaN 替换为 0

Renumber invoice LineNumber tags and replace NaN with 0 using xslt

很抱歉再次打扰您,但我正在努力重新开始使用 XSLT。在我所做的所有搜索中,我看不到这些问题的答案。不知道你学过 XSLT 的人能帮帮我吗..

我在 XML 收到发票,其中有 3 个问题需要处理:

  1. 问题 1 是我们得到贷方票据并且一些 LineNumber 标签为 0(如果两个有 0 那么我们的导入失败,因为 table 行在发票/贷方上有唯一索引ref 和行号(很好))。

  2. 问题 2 是新供应商在我们初始订单后添加的行号增加 10000 和 x 10 因此如果我们订购了 3 行并且他们添加了两行,发票上的行号是1,2,3 10040 和 10050。我们的(疯狂的)接收 table 的行号最大值为 255。

  3. 问题 3 是 InvoicedQuantity 行级别标记中的某些值偶尔会出现 NaN,而我们的 table 具有小数类型。

我对保留行号没有兴趣,因此为了处理这些问题我希望:

  1. 如果 NaN
  2. ,则将标签 InvoicedQuantity 和其他受影响标签的值更改为 0
  3. 按物理顺序将 LineNumber 标签从 1 重置为最大值

这是一个示例 XML 文件(被截断以仅包含强制问题)

<?xml version="1.0" encoding="UTF-8"?>
<Invoice>
    <InvoiceHeader>
        <InvoiceReferences>
            <InvoiceReference>ABC123</InvoiceReference>
            <InvoiceDate>2020-03-11</InvoiceDate>
        </InvoiceReferences>
        <CostCentreCode>H020</CostCentreCode>
    </InvoiceHeader>
    <InvoiceDetail>
        <InvoiceLine>
            <LineNumber>0</LineNumber>
            <SuppliersProductCode>A0</SuppliersProductCode>
            <BuyersProductCode>ABC120</BuyersProductCode>
            <ProductDescription>Product Z</ProductDescription>
            <InvoicedQuantity UnitOfMeasure="EA">2</InvoicedQuantity>
            <PackSize>1</PackSize>
            <UnitValueExclVAT>5</UnitValueExclVAT>
            <LineValueExclVAT>10</LineValueExclVAT>
            <VATCode>Z</VATCode>
            <VATRate>0.00</VATRate>
        </InvoiceLine>
        <InvoiceLine>
            <LineNumber>1</LineNumber>
            <SuppliersProductCode>A1</SuppliersProductCode>
            <BuyersProductCode>ABC123</BuyersProductCode>
            <ProductDescription>Product A</ProductDescription>
            <InvoicedQuantity UnitOfMeasure="EA">2</InvoicedQuantity>
            <PackSize>1</PackSize>
            <UnitValueExclVAT>7.45</UnitValueExclVAT>
            <LineValueExclVAT>18.70</LineValueExclVAT>
            <VATCode>Z</VATCode>
            <VATRate>0.00</VATRate>
        </InvoiceLine>
        <InvoiceLine>
            <LineNumber>10020</LineNumber>
            <SuppliersProductCode>B1</SuppliersProductCode>
            <BuyersProductCode>ABC1456</BuyersProductCode>
            <ProductDescription>Product B</ProductDescription>
            <InvoicedQuantity UnitOfMeasure="EA">NaN</InvoicedQuantity>
            <PackSize>1</PackSize>
            <UnitValueExclVAT>7.45</UnitValueExclVAT>
            <LineValueExclVAT>NaN</LineValueExclVAT>
            <VATCode>Z</VATCode>
            <VATRate>0.00</VATRate>
        </InvoiceLine>
    </InvoiceDetail>
    <InvoiceTrailer>
    </InvoiceTrailer>
</Invoice>

这是一个经过修改的身份转换,对 LineNumber 和 InvoicedQuantity 进行了特殊处理,希望对您有所帮助。

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match='InvoiceDetail'>
        <xsl:element name='InvoiceDetail'>
            <xsl:for-each select='InvoiceLine'>
                <xsl:copy>
                    <!-- Create a sequential line # -->
                    <xsl:element name='LineNumber'>
                        <xsl:value-of select='position()'/>
                    </xsl:element>

                    <xsl:apply-templates select="@*|node()"/>

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

    <!-- Templates to handle our special cases -->
    <xsl:template match='LineNumber'>
        <!-- Nothing, get rid of the existing line #s -->
    </xsl:template>

    <xsl:template match='InvoicedQuantity'>
        <xsl:element name='InvoicedQuantity'>
            <xsl:apply-templates select="@*"/>
            <!-- Convert NaN to 1 -->
            <xsl:if test='(.="NaN")'>1</xsl:if>
            <xsl:if test='not(.="NaN")'><xsl:value-of select='.'/></xsl:if>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

将这些模板与 XSLT-1.0 结合使用 身份模板:

  1. NaN 值替换为 0

    <xsl:template match="InvoiceLine/InvoicedQuantity[text()='NaN']">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:value-of select="'0'" />
        </xsl:copy>
    </xsl:template>
    
  2. 并按照文档顺序对所有以 1 开头的 LineNumber 重新编号:

    <xsl:template match="InvoiceLine/LineNumber">
        <xsl:copy>
            <xsl:value-of select="count(../preceding-sibling::InvoiceLine)+1" />
        </xsl:copy>
    </xsl:template>