求助:如何用XSLT按每5个JournalEntry节点拆分XML文档
XSLT 2.0实现按每5个JournalEntry拆分XML文档
需求概述
需要将输入XML中的JournalEntry节点按每5个一组拆分,每个分组生成完整的JournalFileData结构(包含原AccountingData下的所有公共节点,如Locked、Company等),最终所有分组包裹在FileList的File节点中。
输入XML
<?xml version="1.0" encoding="UTF-8"?> <JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false"> <AccountingData> <Locked>0</Locked> <Company js:type="Organization_Reference_ID">Some Company</Company> <Currency>USD</Currency> <Ledger>ACTUALS</Ledger> <Date>12-15-2021</Date> <Journal>Manual</Journal> <JournalEntry> <LineCompany js:type="Company">Widget Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <CreditAmount>100</CreditAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Global Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Company">JAG Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Resource Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Supply Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Company">Plain Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Gnome Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> </AccountingData> </JournalFileData>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <FileList> <File> <JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false"> <AccountingData> <Locked>0</Locked> <Company js:type="Organization_Reference_ID">Some Company</Company> <Currency>USD</Currency> <Ledger>ACTUALS</Ledger> <Date>12-15-2021</Date> <Journal>Manual</Journal> <JournalEntry> <LineCompany js:type="Company">Widget Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <CreditAmount>100</CreditAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Global Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Company">JAG Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Resource Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> </AccountingData> </JournalFileData> </File> <File> <JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false"> <AccountingData> <Locked>0</Locked> <Company js:type="Organization_Reference_ID">Some Company</Company> <Currency>USD</Currency> <Ledger>ACTUALS</Ledger> <Date>12-15-2021</Date> <Journal>Manual</Journal> <JournalEntry> <LineCompany js:type="Company">Plain Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> <JournalEntry> <LineCompany js:type="Organization">Gnome Company</LineCompany> <LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount> <DebitAmount>100</DebitAmount> <Currency>USD</Currency> </JournalEntry> </AccountingData> </JournalFileData> </File> </FileList>
原代码问题分析
原XSLT存在以下问题:
- 错误将
AccountingData节点复制到FileList内部,不符合输出结构要求; - 未复制
AccountingData下除JournalEntry外的公共节点,导致每个分组缺少必要上下文信息; - 手动编写
JournalFileData的命名空间和属性,易出错且灵活性差。
修正后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 匹配根节点JournalFileData --> <xsl:template match="/JournalFileData"> <FileList> <!-- 按每5个JournalEntry分组 --> <xsl:for-each-group select="AccountingData/JournalEntry" group-adjacent="(position() - 1) idiv 5"> <File> <!-- 复制原JournalFileData的所有属性和命名空间 --> <JournalFileData> <xsl:copy-of select="@*"/> <AccountingData> <!-- 复制AccountingData下所有非JournalEntry的子节点 --> <xsl:copy-of select="../*[not(local-name()='JournalEntry')]"/> <!-- 复制当前组的JournalEntry节点 --> <xsl:copy-of select="current-group()"/> </AccountingData> </JournalFileData> </File> </xsl:for-each-group> </FileList> </xsl:template> <!-- 忽略默认模板,避免输出多余内容 --> <xsl:template match="text()|@*"/> </xsl:stylesheet>
代码说明
- 根节点匹配:直接匹配
JournalFileData,确保从整个文档结构开始处理; - 分组逻辑:使用
group-adjacent="(position() - 1) idiv 5"实现每5个JournalEntry一组的拆分; - 节点复制:
- 用
<xsl:copy-of select="@*"/>复制JournalFileData的所有属性和命名空间,保证结构一致性; - 用
<xsl:copy-of select="../*[not(local-name()='JournalEntry')]"/>复制AccountingData下的公共节点; - 用
current-group()获取当前分组的JournalEntry节点并复制;
- 用
- 默认模板抑制:添加
<xsl:template match="text()|@*"/>避免输出原文档中未匹配的多余内容。
内容的提问来源于stack exchange,提问作者user6353351
相关产品推荐
相关产品推荐

