正如原来问题的楼主所说:
preceding-sibling
是指在上下文节点在原
XML
文档中的前驱节点集合。所以在
mode b
中的代码:
<
xsl:if
test=
"not(preceding-sibling::*[@f2=current()/@f2])"
>
是判断在此之前没有出现过相同的
f2,
用
preceding-sibling
没错,但是这里有一个前提条件:同一个
f1
,在原文件中如果当前节点存在一个相同的
f2
,但不是同一个
f1
,那么当前节点的
f2
将无法输出了。
如果说
f2(
代表的是城市
)
很难有同名的,但是
mode c
呢,
<
xsl:if
test=
"not(preceding-sibling::*[@f3=current()/@f3])"
>
f3
同名的多了吧,更何况,有没有同名的城市还很难说呢。
总之为了程序的严密性,我们必须将其改成:
<
?xml version='1.0'?
>
<
xsl:stylesheet
version=
"1.0"
xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl:template
match=
"/"
>
<
xsl:apply-templates
select=
"root/item"
mode=
"a"
>
<
xsl:sort
select=
"@f1"
/
>
<
/xsl:apply-templates
>
<
/xsl:template
>
<
xsl:template
match=
"item"
mode=
"a"
>
<
xsl:if
test=
"not(preceding-sibling::*[@f1=current()/@f1])"
>
<
xsl:value-of
select=
"concat(@f1,'-')"
/
>
<
xsl:variable
name=
"f1"
select=
"@f1"
/
>
<
xsl:for-each
select=
".."
>
<
xsl:apply-templates
select=
"item[@f1 = $f1]"
mode=
"b"
>
<
xsl:sort
select=
"@f2"
/
>
<
/xsl:apply-templates
>
<
/xsl:for-each
>
<
br/
>
<
/xsl:if
>
<
/xsl:template
>
<
xsl:template
match=
"item"
mode=
"b"
>
<
xsl:if
test=
"not(preceding-sibling::*[@f1=current()/@f1][@f2=current()/@f2])"
>
<
xsl:value-of
select=
"concat(' ',@f2,':')"
/
>
<
xsl:variable
name=
"f2"
select=
"@f2"
/
>
<
xsl:for-each
select=
".."
>
<
xsl:apply-templates
select=
"item[@f2 = $f2]"
mode=
"c"
>
<
xsl:sort
select=
"@f3"
/
>
<
/xsl:apply-templates
>
<
/xsl:for-each
>
<
/xsl:if
>
<
/xsl:template
>
<
xsl:template
match=
"item"
mode=
"c"
>
<
xsl:if
test=
"not(preceding-sibling::*[@f1=current()/@f1][@f2=current()/@f2][@f3=current()/@f3])"
>
<
xsl:if
test=
"position()!=1"
>
<
xsl:value-of
select=
"','"
/
>
<
/xsl:if
>
<
xsl:value-of
select=
"@f3"
/
>
<
/xsl:if
>
<
/xsl:template
>
<
/xsl:stylesheet
>
其实,最重要的一点就是清楚程序每个步骤执行的状态,并有一个清晰的模型,到底是在原
XML
文档,还是节点集合。