XSLT:比较两个列表并选择唯一的特殊输出列表

时间:2018-02-06 00:30:39

标签: xml xslt xslt-2.0

我有一个XML文档,其中列出了4个可能的答案,然后列出了多选/多答案问题的正确答案。在执行转换时,我需要列出正确的答案,并将一个不正确的答案拉入其自己的元素中。如何比较"列表"解析出一个不正确的输出答案?

SOURCE XML:

<assessment>
<div class="question" id="s1">
    <div class="prompt" id="s2">
        <p id="s3">SELECT ALL THAT APPLY. Which of the following colors do I like?</p>
    </div>
    <div class="answer" id="s4">
        <div class="choice" id="s5">
            <div class="list" id="s6">
                <ul class="no-marker">
                    <li id="s7">Red</li>
                    <li id="s8">Blue</li>
                    <li id="s9">Green</li>
                    <li id="s10">Orange</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="response-processing" id="s11">
        <div class="condition" id="s12">
            <div class="correct" id="s13">
                <div class="response" id="s14">
                    <p><a class="answer-ref" id="s15" href="#s5">s7</a></p>
                    <p><a class="answer-ref" id="s16" href="#s5">s9</a></p>
                    <p><a class="answer-ref" id="s17" href="#s5">s10</a></p>
                </div>
            </div>
        </div>
    </div>
</div> 
</assessment>

使用XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">

<xsl:key name="answers" match="div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']" use="text()"/>

<xsl:template match="*">
    <xsl:call-template name="createItem"/>
</xsl:template>

<xsl:template name="createItem">
    <xsl:for-each select="div[@class='question']">
        <xsl:element name="item">
            <xsl:attribute name="ident" select="@id"/>
            <xsl:call-template name="createPresentation"/>
            <xsl:call-template name="createReprocessing"/>
        </xsl:element>
    </xsl:for-each>
</xsl:template>

<xsl:template name="createPresentation">

        <xsl:element name="presentation">
            <xsl:element name="flow">
                <xsl:attribute name="class" select="'Block'"/>
                <xsl:element name="flow">
                    <xsl:attribute name="class" select="'QUESTION_BLOCK'"/>
                    <xsl:element name="flow">
                        <xsl:attribute name="class" select="'FORMATTED_TEXT_BLOCK'"/>
                        <xsl:element name="material">
                            <xsl:element name="mat_extension">
                                <xsl:element name="mat_formattedtext">
                                    <xsl:attribute name="type" select="'SMART_TEXT'"/>
                                    <xsl:value-of select="div[@class='prompt']/p"/>
                                </xsl:element>
                            </xsl:element>
                        </xsl:element>
                    </xsl:element>
                </xsl:element>
                <xsl:element name="flow">
                    <xsl:attribute name="class" select="'RESPONSE_BLOCK'"/>
                    <xsl:element name="response_lid">
                        <xsl:attribute name="ident" select="div[@class='answer']/div[@class='choice']/@id"/>
                        <xsl:element name="render_choice">
                            <xsl:apply-templates select="div[@class='answer']/div[@class='choice']"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:element>
            </xsl:element>
        </xsl:element>

</xsl:template>

<xsl:template name="createReprocessing">
    <xsl:element name="respcondition">
        <xsl:attribute name="title" select="'correct'"/>
        <xsl:element name="conditionvar">
            <xsl:choose>
                <xsl:when test="count(div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']) &lt;= 1">
                    <!--Use for-each to output if there are multiple answers-->
                    <xsl:for-each select="div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']">
                        <xsl:element name="varequal">
                            <xsl:attribute name="respident" select="@href"/>
                            <xsl:value-of select="."/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:when>
                <xsl:when test="count(div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']) &gt; 1">
                    <xsl:element name="and">
                        <xsl:if test="*[not(key('answers', ./div[@class='answer']/div[@class='choice']/div[@class='list']/ul/li/@id))]">
                            <xsl:for-each select=".">
                                <xsl:element name="not">
                                    <xsl:element name="varequal">
                                        <xsl:attribute name="respident" select="./@href"/>
                                        <xsl:value-of select="key('answers',.)"/>
                                    </xsl:element> 
                                </xsl:element>
                            </xsl:for-each>
                        </xsl:if>  
                        <!--Use for-each to output if there are multiple answers-->
                        <xsl:for-each select="div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']">
                            <xsl:element name="varequal">
                                <xsl:attribute name="respident" select="@href"/>
                                <xsl:value-of select="."/>
                            </xsl:element>
                        </xsl:for-each>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="div[@class='choice']">
    <xsl:for-each select="div[@class='list']//li">
        <xsl:element name="flow_label">
            <xsl:attribute name="class" select="'Block'"/>
            <xsl:element name="response_label">
                <xsl:attribute name="ident" select="@id"/>
                <xsl:if test="@class='no-shuffle'">
                    <xsl:attribute name="rshuffle" select="'No'"/>
                </xsl:if>   
                <xsl:element name="flow_mat">
                    <xsl:attribute name="class" select="'FORMATTED_TEXT_BLOCK'"/>
                    <xsl:element name="material">
                        <xsl:element name="mat_extension">
                                <xsl:element name="mat_formattedtext">
                                    <xsl:attribute name="type" select="'SMART_TEXT'"/>
                                    <xsl:apply-templates/>
                                </xsl:element>
                        </xsl:element>
                    </xsl:element>
                </xsl:element>
            </xsl:element>

        </xsl:element>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

XML OUTPUT(注意元素中所需输出的注释):

<item ident="s1">
<presentation>
    <flow class="Block">
        <flow class="QUESTION_BLOCK">
            <flow class="FORMATTED_TEXT_BLOCK">
                <material>
                    <mat_extension>
                        <mat_formattedtext type="SMART_TEXT">SELECT ALL THAT APPLY. Which of the
                            following colors do I like?</mat_formattedtext>
                    </mat_extension>
                </material>
            </flow>
        </flow>
        <flow class="RESPONSE_BLOCK">
            <response_lid ident="s5">
                <render_choice>
                    <flow_label class="Block">
                        <response_label ident="s7">
                            <flow_mat class="FORMATTED_TEXT_BLOCK">
                                <material>
                                    <mat_extension>
                                        <mat_formattedtext type="SMART_TEXT"
                                            >Red</mat_formattedtext>
                                    </mat_extension>
                                </material>
                            </flow_mat>
                        </response_label>
                    </flow_label>
                    <flow_label class="Block">
                        <response_label ident="s8">
                            <flow_mat class="FORMATTED_TEXT_BLOCK">
                                <material>
                                    <mat_extension>
                                        <mat_formattedtext type="SMART_TEXT"
                                            >Blue</mat_formattedtext>
                                    </mat_extension>
                                </material>
                            </flow_mat>
                        </response_label>
                    </flow_label>
                    <flow_label class="Block">
                        <response_label ident="s9">
                            <flow_mat class="FORMATTED_TEXT_BLOCK">
                                <material>
                                    <mat_extension>
                                        <mat_formattedtext type="SMART_TEXT"
                                            >Green</mat_formattedtext>
                                    </mat_extension>
                                </material>
                            </flow_mat>
                        </response_label>
                    </flow_label>
                    <flow_label class="Block">
                        <response_label ident="s10">
                            <flow_mat class="FORMATTED_TEXT_BLOCK">
                                <material>
                                    <mat_extension>
                                        <mat_formattedtext type="SMART_TEXT"
                                            >Orange</mat_formattedtext>
                                    </mat_extension>
                                </material>
                            </flow_mat>
                        </response_label>
                    </flow_label>
                </render_choice>
            </response_lid>
        </flow>
    </flow>
</presentation>
<respcondition title="correct">
    <conditionvar>
        <and>
            <not>
                <!-- Instead of an empty varequal within <not> I want <varequal respident="#s5">s8</varequal>  -->
                <varequal respident=""/>
            </not>
            <varequal respident="#s5">s7</varequal>
            <varequal respident="#s5">s9</varequal>
            <varequal respident="#s5">s10</varequal>
        </and>
    </conditionvar>
</respcondition>
</item>

认为 key()是要走的路,但我不确定如何让它发挥作用。提前谢谢。

1 个答案:

答案 0 :(得分:1)

你的密钥(我会把它简化为

<xsl:key name="answers"
  match="div[@class='response-processing']/div[@class='condition']/div[@class='correct']/div[@class='response']/p/a[@class='answer-ref']"
  use="."/>

允许您检查答案li是否有相应的响应,以便检查key调用key('answers', @id)是否提供空节点集或序列,然后您可以将答案视为:

  <xsl:template match="div[@class = 'answer']//li[not(key('answers', @id))]">
      <incorrect id="{@id}"></incorrect>
  </xsl:template>