您好我正在尝试为国家/省/市建立类似树的结构但由于某种原因我的模板呈现错误
XML
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="hierarchy.xsl" ?>
<data>
<place id="CA" name="Canada"/>
<place parent="CA" id="ON" name="Ontario"/>
<place parent="CA" id="QC" name="Quebec"/>
<place parent="CA" id="NS" name="Nova Scotia"/>
<place parent="CA" id="NB" name="New Brunswick"/>
<place parent="CA" id="MB" name="Manitoba"/>
<place parent="CA" id="BC" name="British Columbia"/>
<place parent="CA" id="PE" name="Prince Edward Island"/>
<place parent="CA" id="SK" name="Saskatchewan"/>
<place parent="CA" id="AB" name="Alberta"/>
<place parent="CA" id="NL" name="Newfoundland and Labrador"/>
<place parent="ON" name="Barrie"/>
<place parent="ON" name="Belleville"/>
<place parent="ON" name="Brampton"/>
<place parent="ON" name="Brant"/>
<place parent="ON" name="Brantford"/>
<place parent="ON" name="Brockville"/>
<place parent="QC" name="Acton Vale"/>
<place parent="QC" name="Alma"/>
<place parent="QC" name="Amos"/>
<place parent="QC" name="Amqui"/>
<place parent="QC" name="Asbestos"/>
<place parent="MB" name="Brandon"/>
<place parent="MB" name="Dauphin"/>
<place parent="MB" name="Flin Flon"/>
<place parent="MB" name="Morden"/>
<place parent="MB" name="Portage la Prairie"/>
<place parent="PE" name="Charlottetown"/>
<place parent="PE" name="Summerside"/>
<place parent="PE" name="Alberton"/>
<place parent="PE" name="Borden-Carleton"/>
<place parent="PE" name="Cornwall"/>
<place parent="PE" name="Georgetown"/>
<place parent="PE" name="Kensington"/>
<place parent="PE" name="Montague"/>
<place parent="FR" id="LL" name="Newfoundland and Labrador"/>
<place id="FR" name="France"/>
<place id="JP" name="Japan"/>
</data>
我的XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<ul>
<xsl:apply-templates select="//place"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="place[not(@parent)]">
<li> <xsl:value-of select="@name" /></li>
<xsl:apply-templates select="place[@parent='CA']"/>
</xsl:template>
<xsl:template match="place[@parent='CA']">
<ul>
<li> <xsl:value-of select="@name" /></li>
<xsl:apply-templates select="place[@parent='ON']"/>
</ul>
</xsl:template>
<xsl:template match="place[@parent='ON']">
<li> <xsl:value-of select="@name" /></li>
</xsl:template>
</xsl:stylesheet>
我得到的输出是
加拿大 各省 城市
现在的问题是,在所有省份都被渲染后,安大略省的城市正在渲染。我需要帮助。
答案 0 :(得分:0)
有点难以准确地说出你想要的是什么,因为你没有表现出你想要的结果,但我还是会尝试。
建议xsl:key
使用place
属性引用parent
。
然后,您可以使用当前的id
属性来应用模板。
示例...
XML输入
<data>
<place id="CA" name="Canada"/>
<place parent="CA" id="ON" name="Ontario"/>
<place parent="CA" id="QC" name="Quebec"/>
<place parent="CA" id="NS" name="Nova Scotia"/>
<place parent="CA" id="NB" name="New Brunswick"/>
<place parent="CA" id="MB" name="Manitoba"/>
<place parent="CA" id="BC" name="British Columbia"/>
<place parent="CA" id="PE" name="Prince Edward Island"/>
<place parent="CA" id="SK" name="Saskatchewan"/>
<place parent="CA" id="AB" name="Alberta"/>
<place parent="CA" id="NL" name="Newfoundland and Labrador"/>
<place parent="ON" name="Barrie"/>
<place parent="ON" name="Belleville"/>
<place parent="ON" name="Brampton"/>
<place parent="ON" name="Brant"/>
<place parent="ON" name="Brantford"/>
<place parent="ON" name="Brockville"/>
<place parent="QC" name="Acton Vale"/>
<place parent="QC" name="Alma"/>
<place parent="QC" name="Amos"/>
<place parent="QC" name="Amqui"/>
<place parent="QC" name="Asbestos"/>
<place parent="MB" name="Brandon"/>
<place parent="MB" name="Dauphin"/>
<place parent="MB" name="Flin Flon"/>
<place parent="MB" name="Morden"/>
<place parent="MB" name="Portage la Prairie"/>
<place parent="PE" name="Charlottetown"/>
<place parent="PE" name="Summerside"/>
<place parent="PE" name="Alberton"/>
<place parent="PE" name="Borden-Carleton"/>
<place parent="PE" name="Cornwall"/>
<place parent="PE" name="Georgetown"/>
<place parent="PE" name="Kensington"/>
<place parent="PE" name="Montague"/>
<place parent="FR" id="LL" name="Newfoundland and Labrador"/>
<place id="FR" name="France"/>
<place id="JP" name="Japan"/>
</data>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!--This key matches "place" elements that have a "parent" attribute.
The "parent" attribute is used as the value of the key.
For example, <place parent="CA" id="ON" name="Ontario"/> would
have the key "CA" (along with "Quebec", "Nova Scotia", etc.).-->
<xsl:key name="places" match="place[@parent]" use="@parent"/>
<!--This template matches the root element "data".-->
<xsl:template match="/data">
<html>
<body>
<ul>
<!--We apply-templates only to "place" elements that do not
have a "parent" attribute (ie "Canada", "France", and
"Japan"). These elements will be processed in document
order. Since "Canada" appears first in the document, it
will be processed first.-->
<xsl:apply-templates select="place[not(@parent)]"/>
</ul>
</body>
</html>
</xsl:template>
<!--This template matches any "place" element.-->
<xsl:template match="place">
<li>
<xsl:value-of select="@name"/>
<!--This xsl:if is used to check to see if there
are any "place" elements with the key of the "id" attribute.
For example, if the current "place" element was
<place id="CA" name="Canada"/> the test would resolve to
"key('places','CA')". If there are "place" elements with
that key, we output a new "ul" and apply-templates to those
elements.-->
<xsl:if test="key('places',@id)">
<ul>
<!--Here is where we apply-templates (process) to elements
using the "id" attribute of the current "place" element.
For example, if the current "id" attribute was "CA", we'd
be processing any "place" elements with the "parent" attribute
value "CA" (which is what the key was created with ("use"
attribute of "xsl:key" above)). This all happens in document
order.-->
<xsl:apply-templates select="key('places',@id)"/>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
HTML输出
<html>
<body>
<ul>
<li>Canada
<ul>
<li>Ontario
<ul>
<li>Barrie</li>
<li>Belleville</li>
<li>Brampton</li>
<li>Brant</li>
<li>Brantford</li>
<li>Brockville</li>
</ul>
</li>
<li>Quebec
<ul>
<li>Acton Vale</li>
<li>Alma</li>
<li>Amos</li>
<li>Amqui</li>
<li>Asbestos</li>
</ul>
</li>
<li>Nova Scotia</li>
<li>New Brunswick</li>
<li>Manitoba
<ul>
<li>Brandon</li>
<li>Dauphin</li>
<li>Flin Flon</li>
<li>Morden</li>
<li>Portage la Prairie</li>
</ul>
</li>
<li>British Columbia</li>
<li>Prince Edward Island
<ul>
<li>Charlottetown</li>
<li>Summerside</li>
<li>Alberton</li>
<li>Borden-Carleton</li>
<li>Cornwall</li>
<li>Georgetown</li>
<li>Kensington</li>
<li>Montague</li>
</ul>
</li>
<li>Saskatchewan</li>
<li>Alberta</li>
<li>Newfoundland and Labrador</li>
</ul>
</li>
<li>France
<ul>
<li>Newfoundland and Labrador</li>
</ul>
</li>
<li>Japan</li>
</ul>
</body>
</html>
&#13;
这是样式表如何处理较小数据集的简化版本(忽略 结果树片段,序列化等):
<data>
<place id="CA" name="Canada"/>
<place parent="CA" id="ON" name="Ontario"/>
<place parent="ON" name="Barrie"/>
<place parent="FR" id="LL" name="Newfoundland and Labrador"/>
<place id="FR" name="France"/>
</data>
<data>
与第一个模板(match="/data"
)匹配。<place>
属性的parent
元素(加拿大和法国)。<place id="CA" name="Canada"/>
与第二个模板(match="place"
)匹配。name
属性值(&#34;加拿大&#34;)。id
元素的place
属性值)。 <place parent="CA" id="ON" name="Ontario"/>
)所以它会输出一个新的&#34; ul&#34;元件。 <place parent="CA" id="ON" name="Ontario"/>
与第二个模板(match="place"
)匹配。name
属性值输出(&#34; Ontario&#34;)。id
元素的place
属性值)。 <place parent="ON" name="Barrie"/>
)所以它会输出一个新的&#34; ul&#34;元件。 <place parent="ON" name="Barrie"/>
与第二个模板(match="place"
)匹配。name
属性值(&#34; Barrie&#34;)。place
元素没有id
元素。 <place id="CA" name="Canada"/>
的处理已完成。 place
属性的下一个parent
元素。 (基本上它会回到第3步继续处理。)<place id="FR" name="France"/>
与第二个模板(match="place"
)匹配。name
属性值输出(&#34; France&#34;)。id
元素的place
属性值)。 <place parent="FR" id="LL" name="Newfoundland and Labrador"/>
)所以它会输出一个新的&#34; ul&#34;元件。 <place parent="FR" id="LL" name="Newfoundland and Labrador"/>
与第二个模板(match="place"
)匹配。name
属性值输出(&#34;纽芬兰和拉布拉多&#34;)。id
元素的place
属性值)。 <place parent="FR" id="LL" name="Newfoundland and Labrador"/>
的处理完成了。place
个元素没有parent
属性可供处理,因此所有处理都已完成。希望我没有错过任何步骤。
另请参阅规范部分"5. Template Rules"以获取更多信息(尤其是5.1和5.8)。
答案 1 :(得分:0)
让我们先来看看你的代码错误的原因。
<xsl:template match="/">
...
<xsl:apply-templates select="//place"/>
...
</html>
在这里,您将处理所有地点,无论其在逻辑层次结构中的深度如何。
<xsl:template match="place[not(@parent)]">
<li> <xsl:value-of select="@name" /></li>
<xsl:apply-templates select="place[@parent='CA']"/>
</xsl:template>
在这里看起来好像您正在尝试通过输出地点的名称然后处理其子项来处理顶级地点。但是输入中没有任何地方有任何(XML)子元素,它们都是空元素。所以xsl:apply-templates
在这里什么都不做。如果它确实做了某些事情,它就会做错事,因为你会在两次处理非顶级位置,一次从根模板处理,一次从父模板处理。
我认为你想要做的是逻辑(地理)层次结构的递归下降,这与XML树层次结构不同。这样做的方法是,无论何时处理层次结构中的节点,它都应输出自己的详细信息,然后应用模板来处理其逻辑子节点:
<xsl:template match="place">
<li>
<p><xsl:value-of select="@name"/></p>
<ul>
<xsl:apply-templates select="(logical children)"/>
</ul>
</li>
</xsl:template>
选择&#34;逻辑子女的一种方法&#34;是select="//place[@parent=current()/@id]"
但除非您使用XSLT处理器(例如Saxon-EE)并使用非常好的优化器,否则您将通过定义密钥获得更好的性能:
<xsl:key name="k" match="place" use="@id"/>
然后
select="key('k', @parent)"