限制文档特定部分的键

时间:2015-09-25 08:42:54

标签: xslt

我需要将键的节点限制为文档的特定部分。我认为通过一个例子来解释会更容易。

这是我的XML

<xmlinterface>
<invoices>
    <invoice>
        <total>150</total>
        <positions>
            <position><status>valid</status><taxid>1</taxid></position>
            <position><status>invalid</status><taxid>2</taxid></position>
        </positions>
        <taxes>
            <taxe><taxid>1</taxid><amount>10</amount></taxe>
            <taxe><taxid>2</taxid><amount>20</amount></taxe>
        </taxes>
    </invoice>
    <invoice>
        <total>250</total>
        <positions>
           <position><status>valid</status><taxid>1</taxid></position>
        </positions>
        <taxes>
            <taxe><taxid>1</taxid><amount>5</amount></taxe>
        </taxes>
    </invoice>
</invoices>

这是我的XSLT

 <xsl:key name="kTaxes" match="taxe" use="taxid"/>

<xsl:template match="xmlinterface" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance">
    <ArrayList>
        <xsl:for-each select="./invoices/invoice">
               <invoice>
               <total><xsl:value-of select="./total"/></total>
               <total_without_taxe>
               <xsl:value-of select="./total - sum(key('kTaxes',positions/position[status!='invalid']/taxid)/amount[normalize-space() != ''])"/>
               </total_without_taxe>
               </invoice>
        </xsl:for-each>
    </ArrayList>
</xsl:template>

这是我生成的输出

    <invoice>
    <total>150</total>
    <total_without_taxe>135</total_without_taxe>
</invoice>
<invoice>
    <total>250</total>
    <total_without_taxe>235</total_without_taxe>
</invoice>

这就是理想的结果

    <invoice>
    <total>150</total>
    <total_without_taxe>140</total_without_taxe>
</invoice>
<invoice>
    <total>250</total>
    <total_without_taxe>245</total_without_taxe>
</invoice>

我希望只有至少一个&#34;有效&#34;应该从&#34;总计&#34;中减去...值。税收和职位与taxid属性联系在一起。根据我的实际xslt,我有一个问题,即从其他发票中征税。

是否有可能将密钥的节点限制为实际的发票元素?或者还有其他方法可以做到吗?

这是一个更复杂的&#34;例如:

<xmlinterface>
<invoices>
    <invoice>
        <total>150</total>
        <positions>
            <position><status>valid</status><taxid>1</taxid></position>
            <position><status>valid</status><taxid>1</taxid></position>
            <position><status>invalid</status><taxid>2</taxid></position>
            <position><status>valid</status><taxid>2</taxid></position>
        </positions>
        <taxes>
            <taxe><taxid>1</taxid><amount>10</amount></taxe>
            <taxe><taxid>2</taxid><amount>20</amount></taxe>
        </taxes>
    </invoice>
    <invoice>
        <total>250</total>
        <positions>
           <position><status>valid</status><taxid>1</taxid></position>
        </positions>
        <taxes>
            <taxe><taxid>1</taxid><amount>5</amount></taxe>
        </taxes>
    </invoice>
</invoices>

这是期望的结果

 <?xml version="1.0" encoding="UTF-8"?>
<ArrayList>
<invoice>
<total>150</total>
<total_without_taxe>120</total_without_taxe>
</invoice>
<invoice>
<total>250</total>
<total_without_taxe>245</total_without_taxe>
</invoice>
</ArrayList>

3 个答案:

答案 0 :(得分:1)

  

是否有可能将密钥的节点限制为实际的发票元素?

这可以通过generate-id()轻松完成。在这里,我们通过<taxe>

的ID对<invoice>元素进行索引
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"
>
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:key name="kValidTaxes" match="taxe[
        taxid = ancestor::invoice//position[status = 'valid']/taxid
        and amount &gt; 0
    ]" use="generate-id(ancestor::invoice)" />

    <xsl:template match="invoices">
        <ArrayList>
            <xsl:apply-templates select="invoice" />
        </ArrayList>
    </xsl:template>

    <xsl:template match="invoice">
        <xsl:variable name="taxes" select="key('kValidTaxes', generate-id())" />
        <xsl:copy>
            <xsl:copy-of select="total" />
            <total_without_taxe>
                <xsl:value-of select="total - sum($taxes/amount)" />
            </total_without_taxe>
        </xsl:copy>
    </xsl:template>
</xsl:transform>

请注意,<xsl:key>匹配表达式仅限于有效税。之后<taxid>不再重要,封闭式<invoice>的ID足以引用正确的税种。

答案 1 :(得分:0)

您的问题中未指定xslt版本,因此我建议您使用XSLT 1.0:

<asp:TemplateField HeaderText="Review">
    <ItemTemplate>
        <asp:Button ID="ButtonReview" CommandName="Review" 
           CssClass="ButtonCommon" runat="server" Text="Review" 
           OnClientClick="return confirm('Confirm to review this request?')" 
           CommandArgument='<%# Eval("id") %>'/>
    </ItemTemplate>
</asp:TemplateField>

这里我们使用一个取决于发票和taxid的复合键。在XSLT 2.0中,可以在'key'函数中指定第三个参数,该函数定义应用此函数的子树,即键('kTaxes',position / position [status!='invalid'] / taxid,。)。情况下

答案 2 :(得分:0)

  

我需要将密钥的节点限制为特定的部分   文档。

如果您使用 XSLT 2.0

,则可以使用此功能
int main()
{
    int i,j;
    for(i=1;i<=5;i++)
    {   
        for(j=1;j<=5;j++)
        {   
            if(i>=j)
            {
                printf(" %d ",j+i-1);
            }
        }
        printf("\n");
    }
    printf("\n");
}

在XSLT 1.0中,您需要将上下文节点的id连接到键值,如Rudolf Yurgenson的答案所示。

或者根本不使用密钥来执行此操作:

XSLT 1.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="kTaxes" match="taxe" use="taxid"/>

<xsl:template match="xmlinterface">
    <ArrayList>
        <xsl:for-each select="invoices/invoice">
            <invoice>
                <xsl:copy-of select="total"/>
                <total_without_taxe>
                    <xsl:value-of select="total - sum(key('kTaxes', positions/position[status!='invalid']/taxid, .)/amount)"/>
               </total_without_taxe>
            </invoice>
        </xsl:for-each>
    </ArrayList>
</xsl:template>

</xsl:stylesheet>