XSLT 2.0 转换——这是正确的方法吗?

XSLT 2.0 Transformations - is this the right approach?

我有以下 XML 负载:

    <?xml version="1.0" encoding="utf8" ?>
    <Output>
    <Error>
        <Status>0</Status>
        <Details>No errors</Details>
    </Error>
    <Synopsis>
        <Count>451</Count>
    </Synopsis>
    <BankAccounts>
        <BankAccount AcctNo="103" CustName="Frank" BalanceAmount="" Inactive="N" NoOfAccounts="1" >
            <Addresses>
                <Address>ABC</Address>
                <Address>XYZ</Address>
            </Addresses>
        </BankAccount>
        <BankAccount AcctNo="101" CustName="Jane" BalanceAmount="10005" Inactive="N" NoOfAccounts="1" >
            <Addresses>
                <Address>LMN</Address>
                <Address>QWE</Address>
            </Addresses>
        </BankAccount>
        
    </BankAccounts>
</Output>

我需要将其转换为以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Output>
    <Count>451</Count>
    <?xml-multiple bankAccounts?>
    <bankAccounts>
        <acctNo>103</acctNo>
        <custName>Frank</custName>
        <balanceAmount/>
        <inactive>N</inactive>
        <noOfAccounts>1</noOfAccounts>
        <?xml-multiple Address?>
        <Address>ABC</Address>
        <Address>XYZ</Address>      
    </bankAccounts>
    <bankAccounts>
        <acctNo>101</acctNo>
        <custName>Jane</custName>
        <balanceAmount>10005</balanceAmount>
        <inactive>N</inactive>
        <noOfAccounts>1</noOfAccounts>
        <?xml-multiple Address?>
        <Address>LMN</Address>
        <Address>QWE</Address>
    </bankAccounts> 
</Output>

我是一个业余爱好者 w.r.t XSLT,通过查找 SO 并在这里提问,不知何故能够提出如下 XSLT。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <!-- Identity template, copies everything as is -->
    <xsl:template match="@*|node()"> 
        <xsl:copy> 
            <xsl:apply-templates select="@*|node()"/> 
        </xsl:copy> 
    </xsl:template> 
    
    <!-- breakdown attributes of BankAccount into child elements -->
    <xsl:template match="BankAccount/@*">
        <xsl:element name="{lower-case(substring(name(), 1, 1))}{substring(name(), 2)}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
    
    
    
    <!--  Drop 'Synopsis' element NOT children AND insert a PI at the end of this operation -->
    <xsl:template match="Synopsis" >
        <xsl:apply-templates/>
        <xsl:processing-instruction name="xml-multiple">
            bankAccounts
        </xsl:processing-instruction>
        
    </xsl:template>
    
    <!--  This will drop 'Result/Header' element and its children  -->
    <xsl:template match="Output/Error" />   
    
    <!--  This will drop 'BankAccounts' element BUT preserve its children -->
    <xsl:template match="BankAccounts">
        <xsl:apply-templates/>
    </xsl:template>
    
    <!-- rename element 'BankAccount' to 'bankAccounts' -->
    <xsl:template match="BankAccount">
        <bankAccounts>
            <xsl:apply-templates select="@* | node()" />
        </bankAccounts>
    </xsl:template>
    
    <!--  Drop 'Addresses' element and insert PI first inside 'Addresses' -->
    <xsl:template match="Addresses" >
        <xsl:processing-instruction name="xml-multiple">
            Address
        </xsl:processing-instruction>
        <xsl:apply-templates/>
        
        
    </xsl:template>
</xsl:stylesheet>

这似乎有效,但这是我的疑问:

#1 上述 XSL 中是否有任何错误/性能不佳的地方?应该避免的事情?

#2 为什么需要身份模板?我尝试删除它,但它似乎弄乱了 o/p ?

#3 每条指令是否扫描整个 XML 文档?我想知道是否有一种方法 'chain' 可以将一个 XSLT 操作的 o/p 馈送到下一个 xslt 操作?

#4 在将 'BankAccount' 元素的属性分解为子元素时使用了从另一个问题粘贴的函数副本,但我真的不明白为什么需要子字符串?我猜它只是试图处理第一个字母

谢谢

#1 上述 XSL 中是否有任何错误/性能不佳的地方?应该避免的事情?

我注意到的主要事情是您不能依赖属性的顺序:输出中的元素可能以不同的顺序结束,它是 implementation-dependent。

#2 为什么需要身份模板?我尝试删除它,但它似乎弄乱了 o/p ?

您正在调用 apply-templates 来处理您没有明确模板规则的某些节点(例如地址元素和空白文本节点)。您的后备模板规则与默认 (built-in) 后备规则不同。

#3a 每条指令是否扫描整个 XML 文档?

每个 apply-templates 指令选择一组要处理的节点(默认情况下,当前节点的子节点),从概念上讲,检查样式​​表中的所有模板规则以查看它们中的哪些最适合处理这些节点中的每一个。 (在实践中,XSLT 处理器可能有更好的策略)。

#3b 我想知道是否有一种方法可以 'chain' 其中一个 XSLT 操作的 o/p 可以馈送到下一个 xslt 操作?

是的,但这是一个全新的主题。搜索 XSLT 管道。

#4 在将 'BankAccount' 元素的属性分解为子元素时使用了从另一个问题粘贴的函数副本,但我真的不明白为什么需要子字符串?我猜它只是试图处理第一个字母表

您正在将名称的第一个字符转换为 lower-case 并原样复制字符串的其余部分。