0

我正在尝试使用 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>

如果有人能把我推向正确的方向,我将非常感激。如果需要更多信息,请告诉我。实际的模板“注释”只是简单地将注释传递给它并按照我想要的方式对其进行格式化。

4

2 回答 2

2

您可以考虑将两者组合成一个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>
于 2013-02-21T23:20:07.233 回答
0

我想我想通了。这是我的 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>

这是最后的递归部分。它查看所有评论,并为每个等于当前@CommentID 的@ResponseCommentID 属性调用模板。

        <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>

仍然不完全理解它(我一直不得不在脑海中重播一系列事件),但我相信这是可行的。:)

于 2013-02-21T23:08:40.733 回答