如何用XSLT 2.0拆分含detail元素的大型XML文件?
可以用XSLT 2.0实现该拆分需求
完全可以通过XSLT 2.0配合Saxon工具实现这个XML拆分需求。以下是具体实现方案:
核心XSLT代码
这段XSLT会遍历每个<item>,将其下的<detail>按指定数量分组,每个分组生成一个独立的XML文件,保留原<item>的所有非<detail>结构,仅替换对应分组的<detail>元素:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 可配置参数:每个文件包含的detail数量,默认2 --> <xsl:param name="detail-per-file" select="2"/> <!-- 匹配根节点,启动处理流程 --> <xsl:template match="/"> <xsl:apply-templates select="payment/item"/> </xsl:template> <!-- 处理每个item元素 --> <xsl:template match="item"> <!-- 获取当前item的所有detail元素(无论嵌套层级) --> <xsl:variable name="all-details" select=".//detail"/> <xsl:variable name="item-id" select="id"/> <xsl:variable name="item-name" select="name"/> <!-- 如果当前item没有detail,直接生成一个文件 --> <xsl:if test="not($all-details)"> <xsl:result-document href="item-{$item-id}-0.xml" method="xml" indent="yes"> <xsl:copy-of select="."/> </xsl:result-document> <xsl:continue/> </xsl:if> <!-- 对detail进行分组,每组$detail-per-file个 --> <xsl:for-each-group select="$all-details" group-adjacent="floor((position()-1) div $detail-per-file)"> <xsl:variable name="group-index" select="current-grouping-key() + 1"/> <!-- 生成输出文件,命名规则:item-<id>-<分组序号>.xml --> <xsl:result-document href="item-{$item-id}-{$group-index}.xml" method="xml" indent="yes"> <item> <!-- 复制item下所有非detail的节点,递归处理时替换detail为当前分组的内容 --> <xsl:apply-templates select="parent::*/.." mode="copy-with-grouped-details"> <xsl:with-param name="current-group" select="current-group()"/> </xsl:apply-templates> </item> </xsl:result-document> </xsl:for-each-group> </xsl:template> <!-- 递归复制节点,遇到detail时替换为当前分组的对应元素 --> <xsl:template match="node() | @*" mode="copy-with-grouped-details"> <xsl:param name="current-group"/> <xsl:copy> <xsl:apply-templates select="@*" mode="copy-with-grouped-details"> <xsl:with-param name="current-group" select="$current-group"/> </xsl:apply-templates> <!-- 匹配detail节点,只保留当前分组中的对应元素 --> <xsl:if test="not(local-name()='detail')"> <xsl:apply-templates select="node()" mode="copy-with-grouped-details"> <xsl:with-param name="current-group" select="$current-group"/> </xsl:apply-templates> </xsl:if> <!-- 插入当前分组的detail到原位置 --> <xsl:if test="local-name()='header'"> <xsl:copy-of select="$current-group[parent::header is current()]"/> </xsl:if> </xsl:copy> </xsl:template> </xsl:stylesheet>
Java调用Saxon执行XSLT的示例代码
使用Saxon HE/PE/EE版本(需确保版本支持XSLT 2.0,推荐9.9及以上),通过Java API执行上述XSLT:
import net.sf.saxon.s9api.*; import java.io.File; public class XmlSplitter { public static void main(String[] args) throws Exception { // 初始化Saxon处理器 Processor processor = new Processor(false); XsltCompiler compiler = processor.newXsltCompiler(); // 加载XSLT文件 XsltExecutable executable = compiler.compile(new File("splitter.xsl")); XsltTransformer transformer = executable.load(); // 设置输入XML文件 DocumentBuilder builder = processor.newDocumentBuilder(); XdmNode input = builder.build(new File("input.xml")); transformer.setInitialContextNode(input); // 设置参数:每个文件包含2个detail transformer.setParameter(new QName("detail-per-file"), new XdmAtomicValue(2)); // 执行转换(输出文件由XSLT中的xsl:result-document自动生成) transformer.transform(); } }
关键说明
- 参数配置:通过
$detail-per-file参数可以灵活调整每个文件中的<detail>数量,无需修改XSLT核心逻辑 - 文件命名:采用
item-<id>-<分组序号>.xml的命名规则,避免文件覆盖,同时方便溯源原数据 - 嵌套处理:递归模板会自动处理
<detail>在不同嵌套层级的情况(比如<type_a>/<header>或<type_b>/<header>下的<detail>) - 空情况处理:如果
<item>下没有<detail>,会直接生成一个包含完整<item>的文件
内容的提问来源于stack exchange,提问作者samragu
相关产品推荐
相关产品推荐

