处理动态创建的孩子和兄弟姐妹的子女
我一直在编辑,看着这么久,我没有找到一个看似简单的解决方案。处理动态创建的孩子和兄弟姐妹的子女
一个元素(及其兄弟)将有任意数量的不同(动态)结果,我希望在HTML表格中显示每个cd文件对的一行。最初我认为我可以避免每个循环(似乎无论如何都会返回相同的结果),但我需要一种[更好的]方式来引用孩子。下面的来源与我工作的结构类似。
例如,某些“cd”和“文件”将包含更多元素,例如价格,有些可能没有信息。
XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.test2.xsl"?>
<catalog>
<rock>
<album>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
</cd>
<file>
<store>Apple</store>
<size>3823</size>
</file>
</album>
<album>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
</cd>
<file>
<store>Amazon</store>
<size>2123</size>
</file>
</album>
</rock>
</catalog>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#cccccc">
<th style="text-align:left">Title</th>
<th style="text-align:left">Artist</th>
<th style="text-align:left">Store</th>
<th style="text-align:left">Size</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="album">
<tr>
<xsl:apply-templates select="cd"/>
<xsl:apply-templates select="file"/>
</tr>
</xsl:template>
<xsl:template match="cd">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
<xsl:template match="file">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
结果
<table border="1">
<tbody>
<tr bgcolor="#cccccc">
<th style="text-align:left">Title</th>
<th style="text-align:left">Artist</th>
<th style="text-align:left">Store</th>
<th style="text-align:left">Size</th>
</tr>
<tr>
<td>
Empire Burlesque
Bob Dylan
</td>
<td>
Apple
3823
</td>
</tr>
<tr>
<td>
Hide your heart
Bonnie Tyler
</td>
<td>
Amazon
2123
</td>
</tr>
</tbody>
</table>
现在,我想我看到发生了什么。根据我的理解,在XSLT文件的“cd”和“文件”模板下,select="."
正在返回<td>
内的所有子项。我需要一种方法让每个人都有一个<td>
。我已经为“cd”和“file”模板中的每个“cd”和“file”以及for-each尝试了诸如call-template之类的东西。请注意,我还需要动态构建<th>
元素,现在它们是为测试目的而手动创建的。有什么建议么?
作为一个有教养的猜测(它不完全清楚你的预期输出是什么样子,输入文件的哪些方面是可变的),我想你需要以下内容。
没有必要以一般的方式明确地将模板应用到cd
和title
元素,只是apply-templates
。此外,您的样式表当前缺少store
,size
等的模板。据我所知,这些元素的内容应该在HTML输出中的td
元素内,所以你需要将它们与模板匹配,即使这些模板相当一般。
如果你不知道表头th
事先的名字,如果有那是album
孙子叶元素的变量数,这里是一个更“动态”的解决方案:
XSLT样式表
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes"
encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#cccccc">
<xsl:for-each select="distinct-values(catalog/rock/album/*/*/name())">
<th style="text-align:left">
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="album">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="album/*/*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
HTML输出
<!DOCTYPE html
PUBLIC "XSLT-compat">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#cccccc">
<th style="text-align:left">title</th>
<th style="text-align:left">artist</th>
<th style="text-align:left">store</th>
<th style="text-align:left">size</th>
</tr>
<tr>
<td>Empire Burlesque</td>
<td>Bob Dylan</td>
<td>Apple</td>
<td>3823</td>
</tr>
<tr>
<td>Hide your heart</td>
<td>Bonnie Tyler</td>
<td>Amazon</td>
<td>2123</td>
</tr>
</table>
</body>
</html>
渲染HTML
在线here尝试这种解决方案。
感谢您的解决方案和快速响应。我不想以“我是XSLT新手”开始我的问题,但这是我的第一个尝试解决方案后,我才意识到现代Web浏览器仍然使用XSLT 1.0!即便如此,我仍然确信这是最好的答案,幸运的是我的应用程序使用XSLT 2.0。 [link](http://xsltransform.net)的链接也很有用,我不知道这样的网站。再次感谢! – MasterWill
如果我猜正确,你想要做的事,如:与每一个叶节点
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/catalog">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr>
<xsl:apply-templates select="*/album[1]" mode="header"/>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="album">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="*[text()]" mode="header">
<th>
<xsl:value-of select="name()"/>
</th>
</xsl:template>
<xsl:template match="*[text()]">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
这对每个album
创建行和列文本节点。
请注意,这假定您的输入是常规的 - 即每个专辑具有相同的属性,顺序相同,并且它们都不是空的。
我没有测试过这个,但它看起来像XSLT 1.0的一个好开始。问题是,在我的情况下,专辑可能有不同的属性,按随机顺序排列,可能会有空的结果。 – MasterWill
那么这个和接受的答案都不适合你。 –
如何?接受的答案适合我的问题,并给了我进一步的见解,因为我是新来的这个非常令人沮丧但潜在非常有用的技术:) – MasterWill
我们需要一个更好的“动态”定义。例如,你可以说你想为每个叶节点添加一个文本值的列。但是,我没有看到一种方法可以避免硬编码哪些元素会产生一行。 –
我指的是动态而不是静态。 [列数]列将被动态创建,具体取决于API调用返回的内容。将会有0个或更多子元素,在这种情况下,叶子可能包含也可能不包含任何文本,并且可能具有不同的节点名称(顺序不同)(每个节点名称中应包含一列)。 – MasterWill
这是不够的,说什么会改变。您需要告诉我们什么不会 - 以便我们可以使用它来创建输出表的结构。如果没有限制,那么这个任务是不可能的。 –