XSLT转换需求:提取Rejected状态对应的考试中心及顶层节点数据
XML批量处理需求及解决方案
需求说明
现有一个20万+行的XML文件,需完成以下处理:
- 遍历所有
ExamStatus/E_Status节点 - 当
E_Status值为"Rejected"时,提取对应ExamInfo节点下Exam_Center的CenterName和CenterNo - 同时保留顶层节点的其他元素,生成新的XML文件
原始XML示例
<ExamDetails> <Ex_Descripiton> <ExamMethod>writing</ExamMethod> <OnPaper>Green</OnPaper> </Ex_Descripiton> <ExamInfo> <Grade>11TH</Grade> <Grade-Tsk>I</Grade-Tsk> <Desc>txt11,txt12,txt13</Desc> <University>Cacllc</University> <Exv1 Segment="1"> <HIGHESTMark>100</HIGHESTMark> <LowestMark>40</LowestMark> </Exv1> <Exv2 Segment="2"> <HIGHESTMark>100</HIGHESTMark> <LowestMark>40</LowestMark> </Exv2> <Exam_Center Segment="1"> <CenterName>calicut</CenterName> <CenterNo>289</CenterNo> <CeterGroup>1</CeterGroup> </Exam_Center> <ExamModel_Item segment="1"> <MODEL_ID>15 </MODEL_ID> <MODEL_Name>physic</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Item> <ExamModel_Partners segment="2"> <Colleges>40</Colleges> <MODEL_Name>Social</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Partners> <ExamModel_Partners segment="2"> <Colleges>45</Colleges> <MODEL_Name>maths</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Partners> <ExamStatus Segment="1"> <E_Name>Maths</E_Name> <E_Date>07-23-2024</E_Date> <E_Status>Completed</E_Status> </ExamStatus> <ExamStatus Segment="1"> <E_Name>physic</E_Name> <E_Date>07-23-2024</E_Date> <E_Status>Rejected</E_Status> </ExamStatus> <ExamStatus Segment="1"> <E_Name>Social</E_Name> <E_Date>07-23-2024</E_Date> <E_Status>Completed</E_Status> </ExamStatus> </ExamInfo> <ExamInfo> <Grade>12TH</Grade> <Grade-Tsk>I</Grade-Tsk> <Desc>txt11,txt12,txt13</Desc> <University>Delhi</University> <Exv1 Segment="1"> <HIGHESTMark>100</HIGHESTMark> <LowestMark>40</LowestMark> </Exv1> <Exv2 Segment="2"> <HIGHESTMark>100</HIGHESTMark> <LowestMark>40</LowestMark> </Exv2> <Exam_Center Segment="1"> <CenterName>Mumbai</CenterName> <CenterNo>300</CenterNo> <CeterGroup>1</CeterGroup> </Exam_Center> <ExamModel_Item segment="1"> <MODEL_ID>15 </MODEL_ID> <MODEL_Name>physic</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Item> <ExamModel_Partners segment="2"> <Colleges>40</Colleges> <MODEL_Name>Social</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Partners> <ExamModel_Partners segment="2"> <Colleges>45</Colleges> <MODEL_Name>maths</MODEL_Name> <MODEL_DATE>07-23-2024</MODEL_DATE> </ExamModel_Partners> <ExamStatus Segment="1"> <E_Name>Maths</E_Name> <E_Date>07-23-2024</E_Date> <E_Status>Completed</E_Status> </ExamStatus> <ExamStatus Segment="1"> <E_Name>physic</E_Name> <E_Date>07-23-2024</E_Date> <E_Status>Rejected</E_Status> </ExamStatus> </ExamInfo> </ExamDetails>
尝试的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <xsl:apply-templates select="/ExamInfo"/> </xsl:template> <xsl:template match="/ExamInfo/ExamStatus"> <xsl:for-each select="/ExamInfo/ExamStatus"> <!-- <CenterName><xsl:value-of select="'this is test'"/></CenterName> --> <xsl:choose> <xsl:when test="/E_Status='Rejected'"> <CenterName> <xsl:value-of select="/ExamDetails/Exam_Center/CenterName"/> </CenterName> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:template> </xsl:transform>
问题分析
现有代码存在以下关键错误:
- 路径定位错误:根节点是
ExamDetails,但代码中直接用/ExamInfo会找不到节点,正确路径应为/ExamDetails/ExamInfo - 绝对路径滥用:在
for-each和test条件中使用绝对路径(如/ExamInfo/ExamStatus、/E_Status),导致无法正确定位当前节点的相对元素 - 节点回溯错误:获取
CenterName时路径错误,应从当前ExamStatus回溯到父节点ExamInfo下的Exam_Center,而非直接从根节点查找
正确解决方案
以下XSLT代码可实现需求,且适合处理大文件(避免不必要的节点遍历):
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/> <!-- 匹配根节点,创建新的根元素 --> <xsl:template match="/ExamDetails"> <FilteredExamDetails> <!-- 保留顶层的Ex_Descripiton元素 --> <xsl:copy-of select="Ex_Descripiton"/> <!-- 筛选出包含Rejected状态的ExamInfo节点 --> <xsl:apply-templates select="ExamInfo[ExamStatus/E_Status='Rejected']"/> </FilteredExamDetails> </xsl:template> <!-- 处理符合条件的ExamInfo节点 --> <xsl:template match="ExamInfo"> <ExamInfo> <!-- 复制ExamInfo下的基础信息 --> <xsl:copy-of select="Grade | Grade-Tsk | Desc | University"/> <!-- 提取Exam_Center的指定字段 --> <Exam_Center> <xsl:copy-of select="Exam_Center/CenterName | Exam_Center/CenterNo"/> </Exam_Center> <!-- 可选:保留Rejected状态的ExamStatus节点 --> <xsl:copy-of select="ExamStatus[E_Status='Rejected']"/> </ExamInfo> </xsl:template> </xsl:transform>
代码说明
- 直接从根节点
ExamDetails开始处理,先复制顶层的Ex_Descripiton元素 - 通过
ExamInfo[ExamStatus/E_Status='Rejected']筛选出包含拒绝状态的考试信息节点,避免遍历所有节点 - 对符合条件的
ExamInfo,复制需要的基础字段,提取Exam_Center中的CenterName和CenterNo,也可选择性保留对应的Rejected状态节点 - 采用模板匹配而非
for-each循环,更符合XSLT的处理逻辑,且性能更优,适合大文件处理
内容的提问来源于stack exchange,提问作者SATHK
相关产品推荐
相关产品推荐

