如何使用XSLT 1.0扁平化XML并优化转换方案?
XSLT 1.0 优化XML转换实现
问题概述
刚接触XSL,需要将层级XML转换为扁平化结构,仅保留指定元素并重命名,适配API输入格式,要求使用XSLT 1.0。
原始XML输入
<?xml version="1.0" encoding="UTF-8" ?> <EXCHANGE> <SCE> <SCE.SRS> <SCE_SCJC.SCE.SRS>1234567/1</SCE_SCJC.SCE.SRS> <SCE_SEQ2.SCE.SRS>01</SCE_SEQ2.SCE.SRS> <SCE_STUC.SCE.SRS>1234567</SCE_STUC.SCE.SRS> <SCE_AYRC.SCE.SRS>2022/23</SCE_AYRC.SCE.SRS> <SCE_CRSC.SCE.SRS>CRS123456</SCE_CRSC.SCE.SRS> <SCE_BLOK.SCE.SRS>01</SCE_BLOK.SCE.SRS> <SCE_DPTC.SCE.SRS>ABCD</SCE_DPTC.SCE.SRS> <STU> <STU.SRS> <STU_CODE.STU.SRS>22100814</STU_CODE.STU.SRS> <STU_NAME.STU.SRS>Test Student Name</STU_NAME.STU.SRS> <STU_DOB.STU.SRS>01011993</STU_DOB.STU.SRS> <STU_INEM.STU.SRS/> </STU.SRS> </STU> <DPT> <DPT.SRS> <DPT_CODE.DPT.SRS>ABCD</DPT_CODE.DPT.SRS> <DPT_NAME.DPT.SRS>Department Name</DPT_NAME.DPT.SRS> </DPT.SRS> </DPT> <CRS> <CRS.SRS> <CRS_CODE.CRS.SRS>CRS123456</CRS_CODE.CRS.SRS> <CRS_NAME.CRS.SRS>Course Name</CRS_NAME.CRS.SRS> <CRS_MOAC.CRS.SRS>FT</CRS_MOAC.CRS.SRS> </CRS.SRS> </CRS> </SCE.SRS> </SCE> </EXCHANGE>
转换需求
- 扁平化XML结构
- 仅保留指定元素
- 重命名选中元素,最终输出:
<StudentRecord> <STUDENT_NO>1234567</STUDENT_NO> <STUDENT_NAME>Test Student Name</STUDENT_NAME> <DATE_OF_BIRTH>01011993</DATE_OF_BIRTH> <EMAIL_ADDRESS/> <FACULTY>ABCD</FACULTY> <DEGREE_NAME>Course Name</DEGREE_NAME> </StudentRecord>
现有XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/EXCHANGE/SCE/SCE.SRS"> <xsl:element name="STUDENT_NO"> <xsl:value-of select="SCE_SCJC.SCE.SRS"/> </xsl:element> <xsl:text> </xsl:text> <xsl:element name="STUDENT_NAME"> <xsl:value-of select="STU/STU.SRS/STU_NAME.STU.SRS"/> </xsl:element> <xsl:text> </xsl:text> <xsl:element name="DATE_OF_BIRTH"> <xsl:value-of select="STU/STU.SRS/STU_DOB.STU.SRS"/> </xsl:element> <xsl:text> </xsl:text> <xsl:element name="EMAIL_ADDRESS"> <xsl:value-of select="STU/STU.SRS/STU_INEM.STU.SRS"/> </xsl:element> <xsl:text> </xsl:text> <xsl:element name="FACULTY"> <xsl:value-of select="DPT/DPT.SRS/DPT_NAME.DPT.SRS"/> </xsl:element> <xsl:text> </xsl:text> <xsl:element name="DEGREE_NAME"> <xsl:value-of select="CRS/CRS.SRS/CRS_NAME.CRS.SRS"/> </xsl:element> </xsl:template> </xsl:stylesheet>
当前转换输出
<?xml version="1.0"?> <STUDENT_NO>1234567/1</STUDENT_NO> <STUDENT_NAME>Test Student Name</STUDENT_NAME> <DATE_OF_BIRTH>01011993</DATE_OF_BIRTH> <EMAIL_ADDRESS></EMAIL_ADDRESS> <FACULTY>ABCD</FACULTY> <DEGREE_NAME>Course Name</DEGREE_NAME>
优化方案及代码
现有代码逻辑可行,但存在结构缺失、数据不符合需求、格式冗余等问题。以下是优化后的XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 去除多余空白,统一控制输出格式 --> <xsl:strip-space elements="*"/> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 匹配根节点,生成目标根元素 --> <xsl:template match="/"> <StudentRecord> <xsl:apply-templates select="EXCHANGE/SCE/SCE.SRS"/> </StudentRecord> </xsl:template> <!-- 处理SCE.SRS节点,生成目标子元素 --> <xsl:template match="SCE.SRS"> <!-- 截取/前的内容,匹配目标STUDENT_NO值 --> <STUDENT_NO> <xsl:value-of select="substring-before(SCE_SCJC.SCE.SRS, '/')"/> </STUDENT_NO> <STUDENT_NAME> <xsl:value-of select="STU/STU.SRS/STU_NAME.STU.SRS"/> </STUDENT_NAME> <DATE_OF_BIRTH> <xsl:value-of select="STU/STU.SRS/STU_DOB.STU.SRS"/> </DATE_OF_BIRTH> <!-- 直接生成空元素,符合XML规范 --> <EMAIL_ADDRESS/> <!-- 直接从SCE层级取值,无需嵌套遍历DPT节点 --> <FACULTY> <xsl:value-of select="SCE_DPTC.SCE.SRS"/> </FACULTY> <DEGREE_NAME> <xsl:value-of select="CRS/CRS.SRS/CRS_NAME.CRS.SRS"/> </DEGREE_NAME> </xsl:template> </xsl:stylesheet>
优化点说明
- 补全根元素:新增根节点匹配模板,将所有输出元素包裹在
<StudentRecord>中,完全符合需求结构。 - 简化元素写法:直接编写目标元素标签(如
<STUDENT_NO>)替代<xsl:element>,代码更简洁易读。 - 修正数据内容:使用
substring-before()函数截取/前的内容,让STUDENT_NO值符合要求。 - 格式自动控制:通过
<xsl:strip-space>和<xsl:output>配置自动处理缩进和空白,无需手动插入换行文本。 - 优化取值路径:
FACULTY直接从SCE_DPTC.SCE.SRS取值,减少节点遍历层级,提升效率。 - 规范空元素:
<EMAIL_ADDRESS>直接写空元素形式,避免生成<EMAIL_ADDRESS></EMAIL_ADDRESS>的冗余写法。
规范确认
你的原始写法符合XSLT 1.0语法规范,但存在冗余和结构缺失。优化后的代码更贴合XSLT最佳实践:
- 模板职责划分清晰,匹配逻辑明确
- 避免不必要的节点创建函数
- 利用内置函数简化数据处理
- 输出格式通过标准配置统一控制
内容的提问来源于stack exchange,提问作者Zeal0try
相关产品推荐
相关产品推荐

