基于XSL模板构建多值CSV转XML的映射逻辑技术问询
解决CSV到XML的分组映射问题(相同Field A+C聚合多行Field B)
不用在CSV里新增标识列!你要的多行聚合可以用XSLT的Muenchian分组实现,这是处理这种“相同键值聚合子元素”场景的标准方案,比单纯用xsl:if高效得多。
核心思路
- 以Field A + Field C的组合作为分组键,把所有同组的CSV行聚合到同一个
<Field_A>节点下 - 每个分组内的每一行,对应一个
<Field_B>子元素,把该行的Field D-J字段都塞进去
示例实现
假设你的CSV数据长这样(逗号分隔,第一行是表头):
Field A,Field B,Field C,Field D,Field E,Field F,Field G,Field H,Field I,Field J A1,B1,C1,D1,E1,F1,G1,H1,I1,J1 A1,B2,C1,D2,E2,F2,G2,H2,I2,J2 A2,B3,C2,D3,E3,F3,G3,H3,I3,J3 A2,B4,C2,D4,E4,F4,G4,H4,I4,J4
对应的XSLT模板可以这么写:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义分组键:用Field A和Field C的组合作为唯一标识,用|分隔避免字段值冲突 --> <xsl:key name="group-by-AC" match="row" use="concat(Field_A, '|', Field_C)"/> <xsl:template match="/"> <Root> <!-- 遍历所有唯一的Field A+C分组,只处理每个分组的第一行 --> <xsl:for-each select="csv/row[generate-id() = generate-id(key('group-by-AC', concat(Field_A, '|', Field_C))[1])]"> <!-- 生成Field_A父元素,保留Field A和C的值 --> <Field_A value="{Field_A}" field_c="{Field_C}"> <!-- 遍历当前分组内的所有行,生成对应的Field_B子元素 --> <xsl:for-each select="key('group-by-AC', concat(Field_A, '|', Field_C))"> <Field_B value="{Field_B}"> <Field_D><xsl:value-of select="Field_D"/></Field_D> <Field_E><xsl:value-of select="Field_E"/></Field_E> <Field_F><xsl:value-of select="Field_F"/></Field_F> <Field_G><xsl:value-of select="Field_G"/></Field_G> <Field_H><xsl:value-of select="Field_H"/></Field_H> <Field_I><xsl:value-of select="Field_I"/></Field_I> <Field_J><xsl:value-of select="Field_J"/></Field_J> </Field_B> </xsl:for-each> </Field_A> </xsl:for-each> </Root> </xsl:template> </xsl:stylesheet>
关键部分解释
xsl:key:定义分组规则,把Field A和Field C拼接成唯一键(用|分隔是防止字段值本身包含特殊字符导致分组错误)- 外层
xsl:for-each:通过generate-id()判断只遍历每个分组的第一行,确保每个分组只生成一个<Field_A>父元素 - 内层
xsl:for-each:通过key()函数取出当前分组的所有行,每行对应生成一个<Field_B>,并映射D-J字段为子元素
转换后的XML结果
<Root> <Field_A value="A1" field_c="C1"> <Field_B value="B1"> <Field_D>D1</Field_D> <Field_E>E1</Field_E> <Field_F>F1</Field_F> <Field_G>G1</Field_G> <Field_H>H1</Field_H> <Field_I>I1</Field_I> <Field_J>J1</Field_J> </Field_B> <Field_B value="B2"> <Field_D>D2</Field_D> <Field_E>E2</Field_E> <Field_F>F2</Field_F> <Field_G>G2</Field_G> <Field_H>H2</Field_H> <Field_I>I2</Field_I> <Field_J>J2</Field_J> </Field_B> </Field_A> <Field_A value="A2" field_c="C2"> <Field_B value="B3"> <Field_D>D3</Field_D> <Field_E>E3</Field_E> <Field_F>F3</Field_F> <Field_G>G3</Field_G> <Field_H>H3</Field_H> <Field_I>I3</Field_I> <Field_J>J3</Field_J> </Field_B> <Field_B value="B4"> <Field_D>D4</Field_D> <Field_E>E4</Field_E> <Field_F>F4</Field_F> <Field_G>G4</Field_G> <Field_H>H4</Field_H> <Field_I>I4</Field_I> <Field_J>J4</Field_J> </Field_B> </Field_A> </Root>
对你问题的补充说明
- 你之前用
xsl:if的思路是逐行判断归属,但Muenchian分组是更高效的标准方案,完全不需要额外标识列 - 如果你的CSV解析后字段名是带空格的
Field A(不是驼峰的Field_A),只需要把XSLT里的字段名改成对应格式即可,比如Field_A换成Field A(取决于你用的CSV转XML工具的输出)
内容的提问来源于stack exchange,提问作者Miya
相关产品推荐
相关产品推荐

