英文:
XSLT select only first node in repeated nested tree
问题
以下是您提供的XML的翻译输出:
一些表示存档层次规则的XML,简短示例:
<someXML>
<dependency-rules>
<name>FONDS
<dependency-rules>
<name>CATEGORY</name>
</dependency-rules>
</name>
</dependency-rules>
</someXML>
期望的输出应该反映层次结构,如下所示:
FONDS
CATEGORY
缩进表示FONDS可以有CATEGORYs。我在处理嵌套的重复dependency-rules/name结构时遇到困难。这个XML:
<?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>
<table>
<xsl:apply-templates select="//name" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="name" >
<tr>
<td><xsl:value-of select="count(ancestor::dependency-rules)" /></td>
<td><xsl:value-of select="." /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
生成了错误的结果:
1 FONDS CATEGORY
2 CATEGORY
当然,它匹配每个级别中的每个<name>。如何只获取每个<dependency-rules>节点中的第一个name?我似乎找不到正确的搜索词来找到类似的示例。解决方案可能非常简单,但对我来说很难找到。
更喜欢XSLT 1.0的解决方案,但不是必需的。
英文:
Some XML that represents the hierarchy rules of an archive, a short sample:
<someXML>
<dependency-rules>
<name>FONDS
<dependency-rules>
<name>CATEGORY</name>
</dependency-rules>
</name>
</dependency-rules>
</someXML>
Desired output should reflect the hierarchy, like this
FONDS
CATEGORY
The indentation means that a FONDS can have CATEGORYs. I'm struggling with the nested repeated dependency-rules/name construction. This
<?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>
<table>
<xsl:apply-templates select="//name" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="name" >
<tr>
<td><xsl:value-of select="count(ancestor::dependency-rules)" /></td>
<td><xsl:value-of select="." /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
produces this, which is wrong:
1 FONDS CATEGORY
2 CATEGORY
of course it matches on every <name>
in each level. How can I get only the first name in each <dependency-rules>
node? I can't seem to find the right words to google for to get a similar example. The solution is probably very easy, but for me, hard to find.
XSLT 1.0 solution preferred, but not vital.
答案1
得分: 2
Your XSLT attempts to create an HTML table, which is not well-suited to display a hierarchical structure such as your XML. If you want the result to be an HTML document, I think you might be better off using an unordered list instead. This would be very easy to generate:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/someXML">
<html>
<body>
<ul>
<xsl:apply-templates select="dependency-rules"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="dependency-rules">
<li>
<xsl:value-of select="normalize-space(name/text())"/>
<ul>
<xsl:apply-templates select="name/dependency-rules"/>
</ul>
</li>
</xsl:template>
</xsl:stylesheet>
Using your input example, the result would be:
<html>
<body>
<ul>
<li>FONDS
<ul>
<li>CATEGORY
<ul></ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
and a browser would display this as:
If you like, you can make it more pretty by adding some CSS.
P.S. If you're happy with a text result, you could reduce the code to only this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="dependency-rules">
<xsl:param name="indent"/>
<xsl:value-of select="$indent"/>
<xsl:value-of select="normalize-space(name/text())"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="name/dependency-rules">
<xsl:with-param name="indent" select="concat($indent, '	')"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
英文:
Your XSLT attempts to create an HTML table, which is not well-suited to display a hierarchical structure such as your XML. If you want the result to be an HTM document, I think you might be better off using an unordered list instead. This would be very easy to generate:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/someXML">
<html>
<body>
<ul>
<xsl:apply-templates select="dependency-rules"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="dependency-rules">
<li>
<xsl:value-of select="normalize-space(name/text())"/>
<ul>
<xsl:apply-templates select="name/dependency-rules"/>
</ul>
</li>
</xsl:template>
</xsl:stylesheet>
Using your input example, the result would be:
<html>
<body>
<ul>
<li>FONDS
<ul>
<li>CATEGORY
<ul></ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
and a browser would display this as:
If you like, you can make it more pretty by adding some CSS.
P.S. If you're happy with a text result, you could reduce the code to only this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="dependency-rules">
<xsl:param name="indent"/>
<xsl:value-of select="$indent"/>
<xsl:value-of select="normalize-space(name/text())"/>
<xsl:text>&#10;</xsl:text>
<xsl:apply-templates select="name/dependency-rules">
<xsl:with-param name="indent" select="concat($indent, '&#9;')"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
答案2
得分: 1
在每个 <dependency-rules>
节点中,你可以简单地将你的指令:
<xsl:value-of select="." />
替换为:
<xsl:value-of select="text()" />
同时,你可以将你的整个尝试简化为:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table>
<xsl:for-each select="//name">
<tr>
<td>
<xsl:value-of select="count(ancestor::dependency-rules)" />
</td>
<td>
<xsl:value-of select="text()" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
然而,这并不能让你更接近你希望通过缩进来表示层级的目标。为此,像 y.arazim 建议的无序列表会更好一些。
英文:
> How can I get only the first name in each <dependency-rules> node?
You could simply replace your instruction:
<xsl:value-of select="." />
with:
<xsl:value-of select="text()" />
At the same time you could simplify your entire attempt to just:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table>
<xsl:for-each select="//name">
<tr>
<td>
<xsl:value-of select="count(ancestor::dependency-rules)" />
</td>
<td>
<xsl:value-of select="text()" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
However, that doesn't get you any closer to your desired goal of representing the hierarchy by indentation. For this purpose, an unordered list as suggested by y.arazim would be much better.
答案3
得分: -3
为了实现所需的输出,您可以按以下方式修改您的XSLT样式表:
<?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"/>
<xsl:template match="/">
<xsl:apply-templates select="//name[not(ancestor::name)]"/>
</xsl:template>
<xsl:template match="name">
<xsl:param name="indent" select="''"/>
<xsl:value-of select="$indent"/>
<xsl:value-of select="normalize-space(.)"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="ancestor::dependency-rules">
<xsl:with-param name="indent" select="concat($indent, ' ')"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="dependency-rules">
<xsl:param name="indent"/>
<xsl:apply-templates select="name">
<xsl:with-param name="indent" select="$indent"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
此样式表使用递归模板来遍历XML层次结构,并生成带有正确缩进的所需输出。它首先选择顶级的name
元素,这些元素没有祖先name
,然后递归地应用模板到dependency-rules
元素,传递更新后的缩进值。
输出是通过<xsl:output method="text"/>
声明生成的,这确保了结果是纯文本而不是HTML。
使用给定的输入XML,输出将是:
FONDS
CATEGORY
该样式表通过正确处理嵌套的dependency-rules
并仅选择每个级别内的第一个name
,生成了预期的层次结构。
英文:
To achieve the desired output, you can modify your XSLT stylesheet as follows:
<?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"/>
<xsl:template match="/">
<xsl:apply-templates select="//name[not(ancestor::name)]"/>
</xsl:template>
<xsl:template match="name">
<xsl:param name="indent" select="''"/>
<xsl:value-of select="$indent"/>
<xsl:value-of select="normalize-space(.)"/>
<xsl:text>&#10;</xsl:text>
<xsl:apply-templates select="ancestor::dependency-rules">
<xsl:with-param name="indent" select="concat($indent, ' ')"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="dependency-rules">
<xsl:param name="indent"/>
<xsl:apply-templates select="name">
<xsl:with-param name="indent" select="$indent"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
This stylesheet uses recursive templates to traverse the XML hierarchy and generate the desired output with proper indentation. It starts by selecting the top-level name
elements that don't have an ancestor name
, and then applies templates recursively to the dependency-rules
elements, passing the updated indent value.
The output is produced using the <xsl:output method="text"/>
declaration, which ensures that the result is plain text rather than HTML.
With the given input XML, the output will be:
FONDS
CATEGORY
The stylesheet generates the expected hierarchical structure by correctly handling the nested dependency-rules
and selecting only the first name
within each level.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论