我有以下xml结构
<transport titel="vervoer">
<type titel="car">
<brand titel="volvo">
<color titel="kleur">red</color>
</brand>
</type>
<type titel="car">
<brand titel="volvo">
<color titel="kleur">green</color>
</brand>
</type>
<type titel="car">
<brand titel="ford">
<color titel="kleur">red</color>
</brand>
</type>
<type titel="bike">
<brand titel="trek">
<color titel="kleur">blue</color>
</brand>
</type>
</transport>
我可以使用以下xsl创建一个csv:
<xsl:template match="/">
<xsl:for-each select="/transport/type/brand/color">
<xsl:variable name="color" select="@titel" />
<xsl:variable name="brand" select="../@titel" />
<xsl:variable name="type" select="../../@titel"/>
<xsl:value-of select="concat($type,$brand,$color)" />
</xsl:for-each>
</xsl:template>
这给出了单行上每个节点的输出:
car,volvo,red
car,volo.green
car,ford,red
bike,trek,blue
但这种方法存在两个问题 1.有没有办法从顶部走树并显示所有可用的标题?如果有一个没有颜色子节点的节点,它将不会显示。
<type titel="bike">
<brand titel="trek">
</brand>
</type>
2.我希望我的csv输出如下:
car,volvo,red
, ,green
,ford,red
bike,trek,blue
答案 0 :(得分:1)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kElementByName" match="*/*" use="name()"/>
<xsl:variable name="vFields"
select="//*/*[count(.|key('kElementByName',name())[1])=1]"/>
<xsl:template match="/*/*">
<xsl:variable name="vCurrent" select="."/>
<xsl:for-each select="$vFields">
<xsl:variable name="vField"
select="$vCurrent/descendant-or-self::*[
name() = name(current())
]"/>
<xsl:variable name="vValue"
select="($vField/@titel|$vField/text())[last()]"/>
<xsl:if test="position()!=1">,</xsl:if>
<xsl:value-of
select="concat(substring('	',1 div not($vValue)),$vValue)"/>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
输出:
car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue
编辑:按评论请求分组,此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kTypeByTitel" match="type" use="@titel"/>
<xsl:key name="kBrandByType-Titel" match="brand"
use="concat(../@titel,'++',@titel)"/>
<xsl:template match="/*">
<xsl:apply-templates
select="type[count(.|key('kTypeByTitel',@titel)[1])=1]"/>
</xsl:template>
<xsl:template match="type">
<xsl:value-of select="@titel"/>
<xsl:apply-templates
select="key('kTypeByTitel',@titel)/brand[
count(.|key('kBrandByType-Titel',
concat(../@titel,'++',@titel)
)[1]
) = 1
]"/>
</xsl:template>
<xsl:template match="brand">
<xsl:if test="position()!=1">
<xsl:text>	</xsl:text>
</xsl:if>
<xsl:value-of select="concat(',',@titel)"/>
<xsl:apply-templates select="key('kBrandByType-Titel',
concat(../@titel,'++',@titel)
)"
mode="color"/>
</xsl:template>
<xsl:template match="brand" mode="color">
<xsl:if test="position()!=1">
<xsl:text>	,	</xsl:text>
</xsl:if>
<xsl:value-of select="concat(
',',
(color/@titel|color/text())[last()],
'
'
)"/>
</xsl:template>
</xsl:stylesheet>
输出:
car,volvo,red
, ,green
,ford,red
bike,trek,blue
注意:不需要有序的输入源。修复字段,因为一般解决方案(动态键嵌套分组)将是XSLT 1.0中最复杂的任务
答案 1 :(得分:0)
您的问题是,您在<color>
中选择了for-each
,因此您将错过没有<type>
后代的每个<color>
。
使用for-each
进行处理的替代方法可能是:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" />
<xsl:strip-space elements="transport" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="transport">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="type">
<xsl:choose>
<xsl:when test="@titel">
<xsl:value-of select="@titel" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
<xsl:text>,</xsl:text>
<xsl:choose>
<xsl:when test="brand[@titel]">
<xsl:apply-templates select="brand" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
<xsl:text>,</xsl:text>
<xsl:choose>
<xsl:when test="brand/color">
<xsl:apply-templates select="brand/color" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="brand">
<xsl:value-of select="@titel"/>
</xsl:template>
<xsl:template match="brand/color">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
示例输入
<?xml version="1.0" encoding="utf-8" ?>
<transport titel="vervoer">
<type titel="car">
<brand titel="volvo">
<color titel="kleur">red</color>
</brand>
</type>
<type titel="car">
<brand titel="volvo">
<color titel="kleur">green</color>
</brand>
</type>
<type titel="car">
<brand titel="ford">
<color titel="kleur">red</color>
</brand>
</type>
<type titel="bike">
<brand titel="trek">
<color titel="kleur">blue</color>
</brand>
</type>
<type titel="trike">
<brand titel="foo" />
</type>
<type>
<brand titel="porsche">
<color titel="kleur">black</color>
</brand>
</type>
<type>
<brand>
<color titel="kleur">black</color>
</brand>
</type>
示例输出
car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue
trike,trek,
,porsche,black
, ,black
要从输出中省略不需要的元素,只需添加一个空模板:
...
<xsl:template match="sometext" />
</xsl:stylesheet>