基于XSLT从指定子节点去重迭代,实现用户数据XML转换导入
用XSLT实现Excel导出XML的用户组去重转换
我来帮你搞定这个Excel转XML的需求!首先咱们得先明确前提:通常Excel转成XML后,每个用户会对应一个<User>节点,里面的每一列都是它的子节点(比如<Firstname>、<Group1>这类)。咱们的目标是把这些用户信息转换成符合要求的XML,同时对从第6列开始的用户组进行去重,确保每个用户的组都是唯一的。
第一步:假设源XML结构
先假设你的Excel转成的源XML是这样的(每个用户的组列从<Group1>开始,可能有重复):
<Users> <User> <Firstname>John</Firstname> <Lastname>Doe</Lastname> <Username>jdoe</Username> <E-Mail>john.doe@example.com</E-Mail> <Phone>1234567890</Phone> <Group1>Admin</Group1> <Group2>Editor</Group2> <Group3>Admin</Group3> <!-- 重复的组,需要去重 --> </User> <User> <Firstname>Jane</Firstname> <Lastname>Smith</Lastname> <Username>jsmith</Username> <E-Mail>jane.smith@example.com</E-Mail> <Phone>0987654321</Phone> <Group1>Viewer</Group1> </User> </Users>
第二步:目标XML结构
咱们要生成的目标XML应该是这样的,每个用户的组去重后放在<Groups>节点下:
<ImportUsers> <User> <FirstName>John</FirstName> <LastName>Doe</LastName> <Username>jdoe</Username> <Email>john.doe@example.com</Email> <Phone>1234567890</Phone> <Groups> <Group>Admin</Group> <Group>Editor</Group> </Groups> </User> <User> <FirstName>Jane</FirstName> <LastName>Smith</LastName> <Username>jsmith</Username> <Email>jane.smith@example.com</Email> <Phone>0987654321</Phone> <Groups> <Group>Viewer</Group> </Groups> </User> </ImportUsers>
第三步:XSLT实现代码
下面分两种版本给你实现,优先推荐XSLT 2.0+的版本,更简洁;如果只能用XSLT 1.0,也给你对应的代码。
版本1:XSLT 2.0+(推荐,语法更简洁)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 匹配根节点,生成目标根节点 --> <xsl:template match="/Users"> <ImportUsers> <xsl:apply-templates select="User"/> </ImportUsers> </xsl:template> <!-- 处理每个用户节点 --> <xsl:template match="User"> <User> <!-- 复制基本信息,重命名部分节点(比如E-Mail转成Email) --> <FirstName><xsl:value-of select="Firstname"/></FirstName> <LastName><xsl:value-of select="Lastname"/></LastName> <Username><xsl:value-of select="Username"/></Username> <Email><xsl:value-of select="E-Mail"/></Email> <Phone><xsl:value-of select="Phone"/></Phone> <!-- 处理用户组:筛选所有以Group开头的子节点,去重后生成Group节点 --> <Groups> <xsl:for-each select="distinct-values(*[starts-with(local-name(), 'Group')]/text())"> <Group><xsl:value-of select="."/></Group> </xsl:for-each> </Groups> </User> </xsl:template> </xsl:stylesheet>
版本2:XSLT 1.0(兼容旧环境)
XSLT 1.0没有distinct-values()函数,咱们用key来实现去重:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义key:按用户组的文本值分组,作用域是当前User节点 --> <xsl:key name="groupKey" match="*[starts-with(local-name(), 'Group')]" use="text()"/> <!-- 匹配根节点 --> <xsl:template match="/Users"> <ImportUsers> <xsl:apply-templates select="User"/> </ImportUsers> </xsl:template> <!-- 处理每个用户节点 --> <xsl:template match="User"> <User> <!-- 复制基本信息 --> <FirstName><xsl:value-of select="Firstname"/></FirstName> <LastName><xsl:value-of select="Lastname"/></LastName> <Username><xsl:value-of select="Username"/></Username> <Email><xsl:value-of select="E-Mail"/></Email> <Phone><xsl:value-of select="Phone"/></Phone> <!-- 处理用户组:筛选唯一的组节点 --> <Groups> <xsl:for-each select="*[starts-with(local-name(), 'Group')][generate-id() = generate-id(key('groupKey', text())[1])]"> <Group><xsl:value-of select="text()"/></Group> </xsl:for-each> </Groups> </User> </xsl:template> </xsl:stylesheet>
关键逻辑说明
- 筛选用户组列:用
starts-with(local-name(), 'Group')匹配所有以Group开头的子节点,也就是从第6列开始的所有用户组列。 - 去重处理:
- XSLT 2.0+直接用
distinct-values()函数提取唯一的组文本值。 - XSLT 1.0通过
key分组,再用generate-id()判断是否是每组的第一个节点,从而实现去重。
- XSLT 2.0+直接用
- 节点重命名:如果你的目标XML需要把
Firstname改成FirstName、E-Mail改成Email这类,直接在模板里对应处理就行,很灵活。
内容的提问来源于stack exchange,提问作者Tobe
相关产品推荐
相关产品推荐

