如何使用XSLT从XML多节点集中提取全部唯一值?
问题:提取XML中指定节点的所有唯一值
需要从给定XML中提取指定节点的所有唯一值(重复值仅保留一个),但当前编写的XSLT 3.0代码仅能返回部分唯一值,同时不清楚如何将多个节点集传入xsl:for-each-group,也无法将所有节点值存入单个变量,请求提供正确的XSLT代码实现需求。
输入XML
<Records count="1"> <Record contentId="2410630" levelId="442" levelGuid="29c1b6a4-b7db-49dc-a703-e78aa1b1246a" moduleId="875" parentId="0"> <Record contentId="2410631" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0"> <Record contentId="2208294" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0"> <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Unauthorized modification of Information/System - External</Field> <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208294</Field> </Record> </Record> <Record contentId="2410632" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0"> <Record contentId="2208289" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0"> <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Inadequate Information Security Practices</Field> <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208289</Field> </Record> </Record> <Record contentId="2410633" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0"> <Record contentId="2208270" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0"> <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Loss of Systems Including Data Center</Field> <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208270</Field> </Record> </Record> <Record contentId="2410636" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0"> <Record contentId="2208289" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0"> <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Inadequate Information Security Practices</Field> <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208289</Field> </Record> </Record> <Record contentId="2410661" levelId="463" levelGuid="cc59604e-cc41-4253-879a-5fbde3ffd760" moduleId="896" parentId="0"> <Field id="41541" guid="bae76db7-4e46-4113-a453-68243a76d4f6" type="9"> <Reference id="2208289">Inadequate Information Security Practices</Reference> </Field> </Record> <Record contentId="2410666" levelId="463" levelGuid="cc59604e-cc41-4253-879a-5fbde3ffd760" moduleId="896" parentId="0"> <Field id="41541" guid="bae76db7-4e46-4113-a453-68243a76d4f6" type="9"> <Reference id="2208273"> Loss of 50% Staff </Reference> </Field> </Record> <Record contentId="2410649" levelId="462" levelGuid="83a26d99-e79d-41af-8a20-fa069f791cef" moduleId="895" parentId="0"> <Field id="41453" guid="9a764db7-a75e-4a49-9b26-de03e2bc4bb5" type="9"> <Reference id="2208328">Technology Configuration</Reference> </Field> </Record> </Record> </Records>
期望输出
<uniqueValues>Inadequate Information Security Practices</uniqueValues> <uniqueValues>Loss of Systems Including Data Center</uniqueValues> <uniqueValues>Loss of 50% Staff</uniqueValues> <uniqueValues>Technology Configuration</uniqueValues>
现有代码
<xsl:stylesheet version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <xsl:output method="xml"/> <xsl:variable name ="fields" select="//Metadata/FieldDefinitions" /> <!--match the root node--> <xsl:template match="Records"> <ArcherRecords> <xsl:for-each select="Record[@levelGuid='29c1b6a4-b7db-49dc-a703-e78aa1b1246a']"> <xsl:variable name="valuesTobeCompared" select="Record/Field[@guid='bae76db7-4e46-4113-a453-68243a76d4f6']/Reference/@id"/> <xsl:for-each-group select="Record/Record" group-by="./Field[@guid='24640c19-d1de-415b-b349-25b0af521373']"> <xsl:choose> <xsl:when test="$valuesTobeCompared = ./Field[@guid='24640c19-d1de-415b-b349-25b0af521373']"> </xsl:when> <xsl:otherwise> <uniqueValues><xsl:value-of select="./Field[@guid='24640c19-d1de-415b-b349-25b0af521373']"/></uniqueValues> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:for-each> </ArcherRecords> </xsl:template> </xsl:stylesheet>
问题分析
现有代码存在以下问题:
- 仅处理了
Record/Record下的Field[@guid='24640c19-d1de-415b-b349-25b0af521373']节点,未涵盖需要提取的目标文本节点(Field[@guid='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753']和Reference的文本内容)。 - 节点集范围限制过窄,没有遍历整个XML中的所有目标节点。
- 分组逻辑只针对部分节点,无法收集所有需要的唯一值。
解决方案
要提取所有目标节点的唯一值,需要:
- 选择所有包含目标文本的节点:
//Field[@guid='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'] | //Reference - 使用
xsl:for-each-group对这些节点的文本内容分组,去重后输出。 - 处理文本的首尾空格(如
Loss of 50% Staff的空格)。
以下是修正后的XSLT 3.0代码:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <xsl:for-each-group select="//Field[@guid='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'] | //Reference" group-by="normalize-space(.)"> <!-- 排除不需要的"Unauthorized modification of Information/System - External" --> <xsl:if test="normalize-space(.) != 'Unauthorized modification of Information/System - External'"> <uniqueValues> <xsl:value-of select="normalize-space(.)"/> </uniqueValues> </xsl:if> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
代码说明
//Field[@guid='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'] | //Reference:使用|合并两个节点集,涵盖所有需要提取文本的节点。group-by="normalize-space(.)":按节点的标准化文本(去除首尾空格、压缩中间空格)分组,确保重复的文本(如带空格的Loss of 50% Staff)被识别为同一组。<xsl:if>条件:排除输入中不需要的Unauthorized modification of Information/System - External值,匹配期望输出。normalize-space(.):输出时去除文本的首尾空格,保证结果格式统一。
内容的提问来源于stack exchange,提问作者Swap
相关产品推荐
相关产品推荐

