在
CSDN
上无意中看到了这样一篇老帖
,关于
XSLT
转换的。
XSLT
原文:
<?xml version="1.0" encoding="GB2312"?>
<?xml-stylesheet type="text/xsl" href="sort.xsl"?>
<root>
<item f1="
浙江
" f2="
绍兴
" f3="aaa"/>
<item f1="
江苏
" f2="
苏州
" f3="bbb"/>
<item f1="
浙江
" f2="
杭州
" f3="ccc"/>
<item f1="
山东
" f2="
济南
" f3="ddd"/>
<item f1="
山东
" f2="
青岛
" f3="eee"/>
<item f1="
江苏
" f2="
南京
" f3="fff"/>
<item f1="
山东
" f2="
青岛
" f3="ggg"/>
<item f1="
江苏
" f2="
南京
" f3="hhh"/>
<item f1="
山东
" f2="
济南
" f3="iii"/>
</root>
要转换的结果文件:
江苏
-
南京:
fff
,
hhh
苏州:
bbb
山东
-
济南:
ddd
,
iii
青岛:
eee
,
ggg
浙江
-
杭州:
ccc
绍兴:
aaa
意思是要把在同一个省同一个市的归纳在一起,并且省市都要按字典排序。
楼主想到了一点:轴是用在原文档中的。
其实,这个问题可以解决:
首先第一步:提取
f1
代码
:
<
?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"
>
<
xsl:sort
select=
"@f1"
/
>
<
/xsl:apply-templates
>
<
/xsl:template
>
<
xsl:template
match=
"item"
>
<
xsl:if
test=
"not(preceding-sibling::*[@f1=current()/@f1])"
>
<
xsl:value-of
select=
"concat(@f1,'-')"
/
>
<
br/
>
<
/xsl:if
>
<
/xsl:template
>
<
/xsl:stylesheet
>
OK,
可以得到下面的结果:
江苏
-
山东
-
浙江
-
现在需要输出第二项内容:即
f2,
可是该如何实现呢?我们知道
apply-templates,
通常只应用于子孙节点的模板。第一步我们已经到了
item
了,下面就是属性了,应用属性的模板,该如何实现属性的唯一性输出呢?
其实打破常理来想,我们可以再次应用
item
的模板,但是如何应用呢?我们应该先利用
for-each
将当前节点移到
item
的顶层,那么就可以再次应用
item
的模板了,但是,另一个问题又出来了,再次应用这个模板,是不是会混乱了,我们这次的目的是输出
f2
啊,
OK,
还记得吗?
<xsl:templates>
有一个
mode
属性。代码也就顺理成章的出来了(当然还得保证所选定的
item
节点没变):
<
?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::*[@f2=current()/@f2])"
>
<
xsl:value-of
select=
"concat(' ',@f2,':')"
/
>
<
/xsl:if
>
<
/xsl:template
>
<
/xsl:stylesheet
>