我需要解决一个奇怪的问题。我需要一个XSLT样式表,它将打印具有未知结构的xml文档的元素列表及其属性。经过多次尝试,我设法创造了这样的东西:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<HTML>
<title></title>
<body>
<xsl:call-template name="recurs">
<xsl:with-param name="nextnodes" select="child::*" />
</xsl:call-template>
</body>
</HTML>
</xsl:template>
<xsl:template name="recurs">
<xsl:param name="nextnodes" />
<xsl:for-each select="$nextnodes">
<xsl:if test="not(name(current())=name(following::*)) and not(name(current())=name(following::*/descendant::*)) ">
Element <b><xsl:value-of select="name(current())" /></b> has attributes <text> </text>
<xsl:for-each select="@*">
<xsl:if test="position()=last()">
<b><xsl:value-of select="name(current())" /><text>.</text></b>
</xsl:if>
<xsl:if test="position()!=last()">
<b><xsl:value-of select="name(current())" /><text>, </text></b>
</xsl:if>
</xsl:for-each>
<br /><br />
</xsl:if>
<xsl:call-template name="recurs">
<xsl:with-param name="nextnodes" select="child::*" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
对于这样的测试用例,当元素书再次出现在其他元素中时,它可以正常工作:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="task3_4a.xsl"?>
<catalog subnodes="2">
<cities country="England">
<city name="London" region="London" population="10000" />
<city name="New South Wales" region="Wales" population="800000" />
</cities>
<articles country="USA">
<article name="My lovely country" src="art1.txt" />
<article name="Places to visit" src="art2.txt" />
<article name="Article 3" src="art3.txt" />
</articles>
<books>
<book title="Warhammer">
</book>
<book title="We fought for truth">
</book>
</books>
<scientifics atr = " ">
<book title="Warhammer">
</book>
</scientifics>
</catalog>
但是当我尝试另一个测试时,如果书中有元素文章,则无法正确管理xml:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="task3_4a.xsl"?>
<catalog subnodes="2">
<cities country="England">
<city name="London" region="London" population="10000" />
<city name="New South Wales" region="Wales" population="800000" />
</cities>
<articles country="USA">
<article name="My lovely country" src="art1.txt" />
<article name="Places to visit" src="art2.txt" />
<article name="Article 3" src="art3.txt" />
</articles>
<books>
<book title="Warhammer">
<article name="My lovely country" src="art1.txt" />
</book>
<book title="We fought for truth">
<article name="My lovely country" src="art1.txt" />
</book>
</books>
<scientifics atr = " ">
<book title="Warhammer">
<article name="My lovely country" src="art1.txt" />
</book>
</scientifics>
</catalog>
输出现在包含字符串“元素文章具有属性名称,src”。 3次。我不知道如何解决它......
答案 0 :(得分:2)
<强>予。这是一个非常简短的XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:for-each-group select="//*"
group-by="string-join((name(), @*/name()), '|')">
<xsl:sort select="name()"/>
<p>
Element <b><xsl:sequence select="name()"/></b>
has attributes: <xsl:value-of select="@*/name()" separator=", "/>
</p>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<catalog subnodes="2">
<cities country="England">
<city name="London" region="London" population="10000" />
<city name="New South Wales" region="Wales" population="800000" />
</cities>
<articles country="USA">
<article name="My lovely country" src="art1.txt" />
<article name="Places to visit" src="art2.txt" />
<article name="Article 3" src="art3.txt" />
</articles>
<books>
<book title="Warhammer">
<article name="My lovely country" src="art1.txt" />
</book>
<book title="We fought for truth">
<article name="My lovely country" src="art1.txt" />
</book>
</books>
<scientifics atr = " ">
<book title="Warhammer">
<article name="My lovely country" src="art1.txt" />
</book>
</scientifics>
</catalog>
产生了想要的正确结果:
<p>
Element <b>article</b>
has attributes: name, src</p>
<p>
Element <b>articles</b>
has attributes: country</p>
<p>
Element <b>book</b>
has attributes: title</p>
<p>
Element <b>books</b>
has attributes: </p>
<p>
Element <b>catalog</b>
has attributes: subnodes</p>
<p>
Element <b>cities</b>
has attributes: country</p>
<p>
Element <b>city</b>
has attributes: name, region, population</p>
<p>
Element <b>scientifics</b>
has attributes: atr</p>
,并在浏览器中显示为:
元素文章 有属性:name,src
元素文章 有属性:国家
元素书 有属性:标题
元素书籍 有属性:
元素目录 有属性:子节点
元素城市 有属性:国家
元素城市 具有属性:名称,地区,人口
元素科学 有属性:atr
<强> II。 XSLT 1.0(两次通过)解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kElByNameandAttrs" match="*"
use="concat(name(), '|', @_____attribs)"/>
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:template match="*">
<xsl:copy>
<xsl:attribute name="_____attribs">
<xsl:for-each select="@*">
<xsl:sort select="name()"/>
<xsl:value-of select="concat(name(), ' ')"/>
</xsl:for-each>
</xsl:attribute>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates mode="pass2" select=
"ext:node-set($vrtfPass1)//*
[generate-id()
=
generate-id(key('kElByNameandAttrs',
concat(name(),
'|',
@_____attribs)
)
[1])
]"
>
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="pass2">
<p>
Element <b><xsl:value-of select="name()"/></b>
has attributes: <xsl:value-of select="@_____attribs"/></p>
</xsl:template>
</xsl:stylesheet>
当在同一个XML文档(上面)上应用此XSLT 1.0转换时,再次生成所需的正确结果:
<p>
Element <b>article</b>
has attributes: name src </p>
<p>
Element <b>articles</b>
has attributes: country </p>
<p>
Element <b>book</b>
has attributes: title </p>
<p>
Element <b>books</b>
has attributes: </p>
<p>
Element <b>catalog</b>
has attributes: subnodes </p>
<p>
Element <b>cities</b>
has attributes: country </p>
<p>
Element <b>city</b>
has attributes: name population region </p>
<p>
Element <b>scientifics</b>
has attributes: atr </p>
答案 1 :(得分:0)
您遇到的一个问题是使用此XPath
<xsl:if test="not(name(current())=name(following::*)) ...
使用轴以下:: 将返回多个节点,但应用 name()函数将只获取第一个节点的名称。
因此,而不是XSLT中的以下行&gt; ...
<xsl:if test="not(name(current())=name(following::*)) and not(name(current())=name(following::*/descendant::*)) ">
请尝试使用以下行替换它......
<xsl:if test="not(following::*[name() = name(current())])">
即没有跟随节点(在层次结构的任何级别中)与当前节点名称不同。
执行此操作时,将输出以下内容:
<HTML>
<title></title>
<body>
Element <b>catalog</b> has attributes <text></text><b>subnodes<text>.</text></b><br><br>
Element <b>cities</b> has attributes <text></text><b>country<text>.</text></b><br><br>
Element <b>city</b> has attributes <text></text><b>name<text>, </text></b><b>region<text>, </text></b><b>population<text>.</text></b><br><br>
Element <b>articles</b> has attributes <text></text><b>country<text>.</text></b><br><br>
Element <b>books</b> has attributes <text></text><br><br>
Element <b>scientifics</b> has attributes <text></text><b>atr<text>.</text></b><br><br>
Element <b>book</b> has attributes <text></text><b>title<text>.</text></b><br><br>
Element <b>article</b> has attributes <text></text><b>name<text>, </text></b><b>src<text>.</text></b><br><br></body>
</HTML>
当然,当两个具有相同名称的元素具有不同属性时,这并不能解决匹配问题,但它应该可以解决您文章出现多次的直接问题。