我正在尝试用XSLT构建一个注释系统。以下是已提交评论的XML输入:
<in:inputs xmlns:in="http://www.composite.net/ns/transformation/input/1.0">
<!-- Input Parameter, XPath /in:inputs/in:param[@name='story_id'] -->
<in:param name="story_id">182485599</in:param>
<!-- Function Call Result (0 ms), XPath /in:inputs/in:result[@name='LoggedInWebUserID'] -->
<in:result name="LoggedInWebUserID">233459</in:result>
<!-- Function Call Result (9 ms), XPath /in:inputs/in:result[@name='XML_Comment']/root -->
<in:result name="XML_Comment">
<root xmlns="">
<Comments CommentID="1" ResponseCommentID="0" WebUserID="123456" FULL_NAME="Osikhuemhe Abulume" Comment="test comment!!!!" DateSubmitted="Feb 20 2013 1:34PM"/>
<Comments CommentID="2" ResponseCommentID="0" WebUserID="261337" FULL_NAME="Phillip Lowe" Comment="test comment2!!!!" DateSubmitted="Feb 20 2013 5:14PM"/>
<Comments CommentID="3" ResponseCommentID="1" WebUserID="000007" FULL_NAME="Norman Abbott" Comment="my response" DateSubmitted="Feb 20 2013 5:14PM"/>
<Comments CommentID="4" ResponseCommentID="0" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="Not impressed..." DateSubmitted="Feb 20 2013 4:10PM"/>
<Comments CommentID="5" ResponseCommentID="0" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="blah blah blah. " DateSubmitted="Feb 20 2013 4:11PM"/>
<Comments CommentID="6" ResponseCommentID="0" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="dfsfs" DateSubmitted="Feb 20 2013 4:14PM"/>
<Comments CommentID="7" ResponseCommentID="5" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="this is a response to blah blah blah." DateSubmitted="Feb 20 2013 4:52PM"/>
<Comments CommentID="8" ResponseCommentID="3" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="I don't agree with Norman. Terrible response." DateSubmitted="Feb 20 2013 5:39PM"/>
<Comments CommentID="9" ResponseCommentID="4" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="I'm impressed." DateSubmitted="Feb 20 2013 5:43PM"/>
<Comments CommentID="10" ResponseCommentID="1" WebUserID="233459" FULL_NAME="Tamara Failor" Comment="I've got something to say!" DateSubmitted="Feb 20 2013 6:34PM"/>
</root>
</in:result>
这应该像任何其他新闻报道的评论系统一样工作(请参阅:http://www.npr.org/2013/02/20/172384724/when-a-bad-economy-means-working-forever)
也就是说,新的评论(ResponseCommentID=0)总是被推到左边。
对这些评论的回应将缩进在下面。(我现在不在乎缩进。我想得到评论的回复,让它们相互叠加)
有两个部分我被卡住了。第一部分是每个帖子应该如何命名:
<xsl:variable name="story_id" select="/in:inputs/in:param[@name='story_id']" />
<xsl:variable name="root" select="/in:inputs/in:result[@name='XML_Comment']/root" />
<xsl:for-each select="$root/Comments[@ResponseCommentID=0]">
<!-- call the template to plot the first comment down -->
<xsl:call-template name="thecomment">
<xsl:with-param name="CommentID"><xsl:value-of select="@CommentID" /></xsl:with-param>
<xsl:with-param name="ResponseCommentID"><xsl:value-of select="@ResponseCommentID" /></xsl:with-param>
</xsl:call-template>
<!-- if the comment has any responses, put those underneath the root -->
<xsl:for-each select="$root/Comments[current()/@CommentID = $root/Comments/@ResponseCommentID]">
<xsl:call-template name="thecomment">
<xsl:with-param name="CommentID"><xsl:value-of select="@CommentID" /></xsl:with-param>
<xsl:with-param name="ResponseCommentID"><xsl:value-of select="@ResponseCommentID" /></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
模板的(也是非常错误的)结束递归部分:
<xsl:if test="@CommentID = $root/Comments/@ResponseCommentID">
<xsl:call-template name="thecomment">
<xsl:with-param name="CommentID"><xsl:attribute name="value"><xsl:value-of select="@CommentID[@CommentID = $root/Comments/@ResponseCommentID]" /></xsl:with-param>
<xsl:with-param name="ResponseCommentID"><xsl:attribute name="value"><xsl:value-of select="@ResponseCommentID[@CommentID = $root/Comments/@ResponseCommentID]" /></xsl:with-param>
</xsl:call-template>
</xsl:if>
如果有人能把我推向正确的方向,我将不胜感激。如果需要更多信息,请告诉我。实际的模板"thecomment"只是接受传递给它的注释,并按照我想要的方式对其进行格式化。
您可以考虑将两者合并为一个xsl:apply-templates调用,而不是对每个使用xsl:for-each,然后调用一个命名模板。首先,您将选择ResponseCommentID属性为0的注释。
<xsl:apply-templates
select="in:inputs/in:result[@name='XML_Comment']/root/Comments[@ResponseCommentID='0']" />
然后,您将有一个模板来匹配Comments属性,在其中您将输出注释详细信息。然后你可以递归地得到这样的响应注释:
<xsl:apply-templates select="../Comments[@ResponseCommentID = current()/@CommentID]" />
这将只是递归地调用相同的Comments模板,直到不再有响应为止。
以下是本例中的完整XSLT(作为示例,我将注释作为HTML中的列表项输出)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:in="http://www.composite.net/ns/transformation/input/1.0" exclude-result-prefixes="in">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<ul>
<xsl:apply-templates select="in:inputs/in:result[@name='XML_Comment']/root/Comments[@ResponseCommentID='0']" />
</ul>
</xsl:template>
<xsl:template match="Comments">
<li>
<xsl:value-of select="@Comment" />
<xsl:if test="../Comments[@ResponseCommentID = current()/@CommentID]">
<ul>
<xsl:apply-templates select="../Comments[@ResponseCommentID = current()/@CommentID]" />
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
这给出了以下输出
<ul>
<li>test comment!!!!
<ul>
<li>my response
<ul>
<li>I don't agree with Norman. Terrible response.</li>
</ul>
</li>
<li>I've got something to say!</li>
</ul>
</li>
<li>test comment2!!!!</li>
<li>Not impressed...
<ul>
<li>I'm impressed.</li>
</ul>
</li>
<li>blah blah blah.
<ul>
<li>this is a response to blah blah blah.</li>
</ul>
</li>
<li>dfsfs</li>
</ul>
但是,在此处使用xsl:key来查找对注释的响应会更有效:
<xsl:key name="Comments" match="Comments" use="@ResponseCommentID" />
然后要获得顶级评论,你可以这样做:
<xsl:apply-templates select="key('Comments', '0')" />
为了在匹配模板中获得对给定评论的响应,您可以执行以下
<xsl:apply-templates select="key('Comments', @CommentID)" />
下面的XSLT也给出了相同的结果
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:in="http://www.composite.net/ns/transformation/input/1.0" exclude-result-prefixes="in">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Comments" match="Comments" use="@ResponseCommentID" />
<xsl:template match="/">
<ul>
<xsl:apply-templates select="key('Comments', '0')" />
</ul>
</xsl:template>
<xsl:template match="Comments">
<li>
<xsl:value-of select="@Comment" />
<xsl:if test="key('Comments', @CommentID)">
<ul>
<xsl:apply-templates select="key('Comments', @CommentID)" />
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
我想我想通了。以下是我的XLST现在的样子。它将浏览所有评论,但前提是它是第一篇帖子(@ResponseCommentID=0)。
<xsl:for-each select="$root/Comments">
<xsl:if test="@ResponseCommentID = 0 and @CommentID != $root/Comments/@ResponseCommentID">
<!-- call the template to first plot the comment down -->
<xsl:call-template name="thecomment">
<xsl:with-param name="CommentID"><xsl:value-of select="@CommentID" /></xsl:with-param>
<xsl:with-param name="ResponseCommentID"><xsl:value-of select="@ResponseCommentID" /></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
这是最后的递归部分。它查看所有注释,并为每个@ResponseCommentID属性调用模板,该属性等于当前的@CommentID。
<xsl:for-each select="$root/Comments[@ResponseCommentID = current()/@CommentID]">
<xsl:call-template name="thecomment">
<xsl:with-param name="CommentID"><xsl:value-of select="@CommentID" /></xsl:with-param>
<xsl:with-param name="ResponseCommentID"><xsl:value-of select="@ResponseCommentID" /></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
仍然不完全理解(我不得不在脑海中回放事件的顺序),但我相信这是有效的。:)