Xslt 将源xml中的元素收集到内存中,在找到所有元素后输出
我有一个类似以下内容的源xml:Xslt 将源xml中的元素收集到内存中,在找到所有元素后输出,xslt,Xslt,我有一个类似以下内容的源xml: <item> <id>1</id> <property name="representative_email"><value>Jallu.Kola@foo.bar.com</value></property> <property name="representative_name"><value>Jallu Kola</val
<item>
<id>1</id>
<property name="representative_email"><value>Jallu.Kola@foo.bar.com</value></property>
<property name="representative_name"><value>Jallu Kola</value></property>
<property name="representative_phone"><value>555 123 456</value></property>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
</item>
<item>
<id>2</id>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
</item>
<item>
<id>3</id>
<property name="representative_email"><value>Jallu.Kola@foo.bar.com</value></property>
<property name="representative_name"><value>Jallu Kola</value></property>
<property name="representative_phone"><value>555 123 456</value></property>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
<property name="representative_email"><value>ville.kalle@foo.bar.com</value></property>
<property name="representative_name"><value>Ville Kalle</value></property>
<property name="representative_phone"><value>555 124 124124</value></property>
</item>
<item>
<id>
<representatives>
<representative>
<email></email>
<name></name>
</phone></phone>
</representative
</representatives
</item>
1.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
2.
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
3.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
维尔。kalle@foo.bar.com
维尔卡尔
555 124 124124
不幸的是,除了使用xslt将其转换为更合理的内容之外,我对此无能为力。
我想把它转换成这样:
<item>
<id>1</id>
<property name="representative_email"><value>Jallu.Kola@foo.bar.com</value></property>
<property name="representative_name"><value>Jallu Kola</value></property>
<property name="representative_phone"><value>555 123 456</value></property>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
</item>
<item>
<id>2</id>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
</item>
<item>
<id>3</id>
<property name="representative_email"><value>Jallu.Kola@foo.bar.com</value></property>
<property name="representative_name"><value>Jallu Kola</value></property>
<property name="representative_phone"><value>555 123 456</value></property>
<property name="representative_email"><value>Sala.Rakas@foo.bar.com</value></property>
<property name="representative_name"><value>Sala Rakas</value></property>
<property name="representative_phone"><value>555 2314 124</value></property>
<property name="representative_email"><value>ville.kalle@foo.bar.com</value></property>
<property name="representative_name"><value>Ville Kalle</value></property>
<property name="representative_phone"><value>555 124 124124</value></property>
</item>
<item>
<id>
<representatives>
<representative>
<email></email>
<name></name>
</phone></phone>
</representative
</representatives
</item>
因此,如果每个组始终包含所有3个元素,则可以迭代其中一个元素,然后按相同位置选择其他元素:
<xsl:template match="item">
<item>
<xsl:copy-of select="id"/>
<representatives>
<xsl:apply-templates select="property[@name='representative_email']"/>
</representatives>
</item>
</xsl:template>
<xsl:template match="property">
<representative>
<email>
<xsl:value-of select="../property[@name='representative_email'][position()]"/>
</email>
<name>
<xsl:value-of select="../property[@name='representative_name'][position()]"/>
</name>
<phone>
<xsl:value-of select="../property[@name='representative_phone'][position()]"/>
</phone>
</representative>
</xsl:template>
XSLT 2.0解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"></xsl:output>
<xsl:template match="*|@*">
<xsl:copy>
<xsl:apply-templates select="*|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<xsl:copy-of select="id"/>
<representatives>
<xsl:for-each-group select="property" group-adjacent="count(preceding::*[@name=current()/@name])">
<representative>
<xsl:for-each select="current-group()">
<xsl:element name="{substring-after(@name,'_')}">
<xsl:value-of select="."></xsl:value-of>
</xsl:element>
</xsl:for-each>
</representative>
</xsl:for-each-group>
</representatives>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这里有一个更通用的解决方案,它也很短(37行格式良好)且简单:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNumProps" select="3"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<item>
<id><xsl:value-of select="id"/></id>
<representatives>
<xsl:apply-templates select=
"property[position() mod $pNumProps = 1]"/>
</representatives>
</item>
</xsl:template>
<xsl:template match="property">
<representative>
<xsl:apply-templates mode="gen" select=
".|following-sibling::property
[not(position() >= $pNumProps)]"/>
</representative>
</xsl:template>
<xsl:template match="property" mode="gen">
<xsl:element name="{substring-after(@name,'_')}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<items>
<item>
<id>1</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>2</id>
<representatives>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>3</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
<representative>
<email>ville.kalle@foo.bar.com</email>
<name>Ville Kalle</name>
<phone>555 124 124124</phone>
</representative>
</representatives>
</item>
</items>
应用于提供的XML片段时(包装到单个顶部元素中,使其成为格式良好的XML文档):
1.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
2.
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
3.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
维尔。kalle@foo.bar.com
维尔卡尔
555 124 124124
生成所需的正确结果:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNumProps" select="3"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<item>
<id><xsl:value-of select="id"/></id>
<representatives>
<xsl:apply-templates select=
"property[position() mod $pNumProps = 1]"/>
</representatives>
</item>
</xsl:template>
<xsl:template match="property">
<representative>
<xsl:apply-templates mode="gen" select=
".|following-sibling::property
[not(position() >= $pNumProps)]"/>
</representative>
</xsl:template>
<xsl:template match="property" mode="gen">
<xsl:element name="{substring-after(@name,'_')}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<items>
<item>
<id>1</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>2</id>
<representatives>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>3</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
<representative>
<email>ville.kalle@foo.bar.com</email>
<name>Ville Kalle</name>
<phone>555 124 124124</phone>
</representative>
</representatives>
</item>
</items>
1.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
2.
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
3.
贾鲁。Kola@foo.bar.com
贾卢科拉
555 123 456
萨拉。Rakas@foo.bar.com
萨拉拉卡斯
555 2314 124
维尔。kalle@foo.bar.com
维尔卡尔
555 124 124124
注意事项:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNumProps" select="3"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<item>
<id><xsl:value-of select="id"/></id>
<representatives>
<xsl:apply-templates select=
"property[position() mod $pNumProps = 1]"/>
</representatives>
</item>
</xsl:template>
<xsl:template match="property">
<representative>
<xsl:apply-templates mode="gen" select=
".|following-sibling::property
[not(position() >= $pNumProps)]"/>
</representative>
</xsl:template>
<xsl:template match="property" mode="gen">
<xsl:element name="{substring-after(@name,'_')}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<items>
<item>
<id>1</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>2</id>
<representatives>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
</representatives>
</item>
<item>
<id>3</id>
<representatives>
<representative>
<email>Jallu.Kola@foo.bar.com</email>
<name>Jallu Kola</name>
<phone>555 123 456</phone>
</representative>
<representative>
<email>Sala.Rakas@foo.bar.com</email>
<name>Sala Rakas</name>
<phone>555 2314 124</phone>
</representative>
<representative>
<email>ville.kalle@foo.bar.com</email>
<name>Ville Kalle</name>
<phone>555 124 124124</phone>
</representative>
</representatives>
</item>
</items>
每个“代表”的属性数在外部提供的全局参数$pNumProps
中指定
要生成的元素的名称将自动生成(不是在接受的答案中硬编码),作为属性的名称属性中“\u1”后面的字符串
代表性道具是否总是以3为单位分组出现?或者有可能他们中的一些人失踪了?不幸的是,没有人保证他们是3人一组出现的。所以有可能他们中的一些人失踪了。他们中的一些人还是其中的任何一个?有一个总是出现吗?如果你有“email”然后是“name”。你怎么知道是一个代表同时拥有电子邮件和姓名,还是其中两个代表只有电子邮件,而第二个代表只有姓名?这看起来很不错,但不幸的是,我正在使用Xalan处理xml,它不支持这一点。也许你可以改为saxon(参见),更改Xalan的成本并没有那么高,XSLT 2.0是一种比XSLT 1.0强大得多的语言。谢谢。@kosoant:+1回答您的问题。您可能有兴趣看到一个更通用的解决方案,其中每个“代表”的元素名称和属性不是像此解决方案中那样硬编码的,而是可以从外部提供/动态计算的。:)