XSLT 1.0复杂分组性能优化:非结构化XML转结构化求助
优化XSLT 1.0性能:从非结构化XML构建层级结构
需求说明
需要将平铺的非结构化XML转换为层级清晰的结构化XML,原有实现通过for-each结合全局节点匹配完成转换,但处理15000行数据时性能严重不足,需优化实现逻辑,避免低效的全局遍历。
输入非结构化XML
<Document> <HEADER> <h1>1</h1> </HEADER> <SUMMARY> <s1>1</s1> </SUMMARY> <SUBMISSION> <su1>1</su1> </SUBMISSION> <TRANSACTION> <tr1>1</tr1> </TRANSACTION> <TXPRICE> <tx1>1</tx1> </TXPRICE> <TXPRICE> <tx1>2</tx1> </TXPRICE> <CHARGEBACK> <c1>1</c1> </CHARGEBACK> <FOOTER> <f1>1</f1> </FOOTER> </Document>
期望输出结构化XML
<HEADER> <h1>1</h1> </HEADER> <SUMMARY> <s1>1</s1> <SUBMISSION> <su1>1</su1> <TRANSACTION> <tr1>1</tr1> <TXPRICE> <tx1>1</tx1> </TXPRICE> <TXPRICE> <tx1>2</tx1> </TXPRICE> </TRANSACTION> <CHARGEBACK> <c1>1</c1> </CHARGEBACK> </SUBMISSION> </SUMMARY> <FOOTER> <f1>1</f1> </FOOTER>
原有实现的性能问题
原有XSLT代码在每个模板中使用/Document/XXX[匹配条件]进行全局节点查询,每次匹配都要遍历整个文档的对应节点类型,数据量增大时时间复杂度呈**O(n²)**增长,导致处理大文档时速度无法接受。
原有XSLT代码
<xsl:stylesheet version="1.0"> <xsl:template match="/"> <Structured_Document> <xsl:apply-templates select="/Document/HEADER"/> <xsl:apply-templates select="/Document/SUMMARY"/> <xsl:apply-templates select="/Document/TRAILER"/> </Structured_Document> </xsl:template> <xsl:template match="/Document/HEADER"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="/Document/SUMMARY"> <xsl:copy> <xsl:apply-templates/> <xsl:for-each select="/Document/SUBMISSION[su1/text() = current()/s1/text()]"> <xsl:apply-templates select="."/> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template match="/Document/SUBMISSION"> <xsl:copy> <xsl:apply-templates/> <xsl:for-each select="/Document/TRANSACTN[tr1/text() = current()/su1/text()]"> <xsl:apply-templates select="."/> </xsl:for-each> <xsl:for-each select="/Document/CHARGEBACK[ch1/text() = current()/tr1/text()]"> <xsl:apply-templates select="."/> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template match="/Document/TRANSACTN"> <xsl:copy> <xsl:apply-templates/> <xsl:for-each select="/Document/TXNPRICING[tx1/text() = current()/tr1/text()]"> <xsl:apply-templates select="."/> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template match="/Document/TXNPRICING"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="/Document/CHARGEBACK"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="/Document/FOOTER"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="node() | @*"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
优化后的XSLT实现
使用XSLT 1.0的<xsl:key>创建节点索引,将全局遍历改为索引查询,大幅降低时间复杂度。以下代码基于实际场景的关联字段调整(示例中匹配字段已修正对应关系):
<xsl:stylesheet version="1.0"> <!-- 预创建关联索引 --> <xsl:key name="submission-by-summary" match="SUBMISSION" use="su1"/> <xsl:key name="transaction-by-submission" match="TRANSACTION" use="tr1"/> <xsl:key name="txprice-by-transaction" match="TXPRICE" use="tx1"/> <xsl:key name="chargeback-by-submission" match="CHARGEBACK" use="c1"/> <xsl:template match="/"> <Structured_Document> <xsl:apply-templates select="Document/HEADER"/> <xsl:apply-templates select="Document/SUMMARY"/> <xsl:apply-templates select="Document/FOOTER"/> </Structured_Document> </xsl:template> <!-- HEADER模板 --> <xsl:template match="HEADER"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- SUMMARY模板:通过key获取关联的SUBMISSION --> <xsl:template match="SUMMARY"> <xsl:copy> <xsl:apply-templates/> <xsl:apply-templates select="key('submission-by-summary', s1)"/> </xsl:copy> </xsl:template> <!-- SUBMISSION模板:通过key获取关联的TRANSACTION和CHARGEBACK --> <xsl:template match="SUBMISSION"> <xsl:copy> <xsl:apply-templates/> <xsl:apply-templates select="key('transaction-by-submission', su1)"/> <xsl:apply-templates select="key('chargeback-by-submission', su1)"/> </xsl:copy> </xsl:template> <!-- TRANSACTION模板:通过key获取关联的TXPRICE --> <xsl:template match="TRANSACTION"> <xsl:copy> <xsl:apply-templates/> <xsl:apply-templates select="key('txprice-by-transaction', tr1)"/> </xsl:copy> </xsl:template> <!-- 基础复制模板 --> <xsl:template match="TXPRICE | CHARGEBACK | FOOTER"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- 身份模板:复制所有未匹配的节点和属性 --> <xsl:template match="node() | @*"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
优化说明
- 索引优化:通过
<xsl:key>为每个关联层级创建索引,查询关联节点时直接调用key()函数,时间复杂度降至O(n),避免了重复遍历整个文档。 - 简化逻辑:去掉冗余的
for-each循环,直接通过xsl:apply-templates调用关联节点的模板,代码更简洁易维护。 - 模板复用:合并了重复的节点复制逻辑,减少代码冗余。
内容的提问来源于stack exchange,提问作者AgaKar
相关产品推荐
相关产品推荐

