【问题标题】:XSLT Condition - If Details in Node A is true, display Details in Node BXSLT 条件 - 如果节点 A 中的详细信息为真,则在节点 B 中显示详细信息
【发布时间】:2012-08-07 23:41:01
【问题描述】:

我需要帮助来设置一个有效的 XSLT 条件:在贯穿问题节点的 for-each 循环中;如果节点 A 上的条件有效,则在节点 B 中显示详细信息。 XML 示例:

<Survey>
    <questions>
        <Number>1.0</Number>
        <Question>Was the show good?</Question>
        <Answer>Yes/No</Answer>
        <Details>N/A</Details>
    </questions>
    <questions>
        <Number>1.1</Number>
        <Question>Explain why</Question>
        <Answer>N/A</Answer>
        <Details>The actors were good</Details>
    </questions>
    <questions>
        <Number>2.0</Number>
        <Question>Was the food good?</Question>
        <Answer>Yes|No</Answer>
        <Details>N/A</Details>
    </questions>
    <questions>
        <Number>2.1</Number>
        <Question>Provide details</Question>
        <Answer>N/A</Answer>
        <Details>The pasta was too salty</Details>
    </questions>
</Survey>

我需要的是使用 for-each 的循环 仅当问题编号 = 1.0 且答案 =“是”时,在问题编号 1.1 中显示详细信息 仅当问题编号 = 2.0 且答案 =“否”时,在问题编号 2.1 中显示详细信息

我已经尝试了所有方法,例如 if,for each,choose/when,但没有奏效。 我检查了你的其他帖子,但找不到类似的东西。谢谢你,tubi。

对不起,应该是这样的:

    <Survey>     
        <questions>
            <Number>1.0</Number>
            <Question>Was the show good?</Question>
            <Answer>Yes</Answer>
            <Details>N/A</Details>     
    </questions>     
    <questions>
         <Number>1.1</Number>
         <Question>Explain why</Question>
         <Answer>N/A</Answer>         
         <Details>The actors were good</Details>
     </questions>     
     <questions>
         <Number>2.0</Number>
         <Question>Was the food good?</Question>         
         <Answer>Yes</Answer>
         <Details>N/A</Details>
     </questions>
     <questions>
         <Number>2.1</Number>
         <Question>Provide details</Question>
         <Answer>N/A</Answer>
         <Details>The pasta was too salty</Details>
     </questions>
 </Survey> 

这是我的一段代码:(对不起,这实际上是别人的代码。当上一个问题具体回答“是”或“否”时,我需要修改显示下一个问题的部分

<fo:table-body start-indent="0pt">
    <xsl:for-each select="../Survey">
        <xsl:for-each select="questions">
        <xsl:sort select="Number" data-type="number" order="ascending"/>
            <fo:table-row>
                <xsl:choose>
                    <xsl:when test="ends-with(Number,'0')">
                        <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center">
                       <fo:block text-align="right">
                                <xsl:for-each select="Number"> ...
                           </xsl:for-each>
                            </fo:block>
                        </fo:table-cell>
                        <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center">
                            <fo:block text-align="left">
                                <xsl:for-each select="Description"> ...
                                </xsl:for-each>
                            </fo:block>
                        </fo:table-cell>
                        <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center"> 
                            <fo:block text-align="left" color="blue">
                               <xsl:for-each select="Answer"> ...
                               </xsl:for-each>
                            </fo:block>
                        </fo:table-cell>                                   </xsl:when>  
                    <xsl:when test="Number='1.1'">
                        <xsl:if test="//questions/Number='1.0' and //questions/Answer='No'">
                           <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center">
                               <fo:block text-align="right">
                                    <xsl:for-each select="Number"> ...
                                    </xsl:for-each>
                               </fo:block>
                           </fo:table-cell>
                           <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center">
                               <fo:block text-align="left">
                                   <xsl:for-each select="Question">  .....
                                   </xsl:for-each>
                               </fo:block>
                           </fo:table-cell>
                           <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center"> 
                              <fo:block text-align="left" color="blue">  ....
                                   <xsl:for-each select="Details">
                                   </xsl:for-each>
                              </fo:block>
                           </fo:table-cell>                                      </xsl:if>  
                       </xsl:when>  
                       <xsl:otherwise>do something</xsl:otherwise>                        </xsl:choose>
               </fo:table-row>
            </xsl:if>
        </xsl:for-each>
    </xsl:for-each>
</fo:table-body>            

【问题讨论】:

  • 是否允许在 XML 的同一字段中提供多个答案?我注意到你有一些说“是/否”和“是|否”。
  • 请给出所需输出的示例。这将消除需求的歧义。此外,如果您在句子之间加上句号,您的“我需要什么”段落将不会那么混乱。
  • 如果您展示您尝试过的一种方法,然后描述它在什么方面不起作用(实际发生了什么以及它与您想要的有什么不同),也会有所帮助。

标签: xml xslt xpath


【解决方案1】:

我会改变你的

<xsl:when test="Number='1.1'">
   <xsl:if test="//questions/Number='1.0' and //questions/Answer='No'">

<xsl:when test="Number='1.1'">
   <xsl:if test="../questions[Number = '1.0']/Answer = 'No'">

假设对于任何问题,您没有一般的方法可以知道是否应该在“是”答案或“否”答案上显示更多详细信息,因此每个 *.0 问题都有一个单独的 &lt;xsl:when&gt; 案例。

附:奇怪的是,XSL 在每个 &lt;fo:block&gt; 中使用了 &lt;xsl:for-each select="Number"&gt; 等,因为在您的示例输入中只有一个 &lt;Number&gt; 子级 &lt;questions&gt;。所做的只是更改上下文节点。也许意图是使用&lt;xsl:apply-templates select="Number" /&gt;

【讨论】:

  • 您好,我已经尝试过您的建议,效果非常好。非常感谢您的帮助。老实说,我是 XSLT 的新手。使用调查进行编程总是很忙。调查报告的逻辑总是这样:对于每个以 0 结尾的问题,显示答案。对于每个问题以 1 结尾,如果 1.0 的答案是 Yes,则在 1.1 Details 1 -> Explanation 1 中显示 Details(可以从复选框中多选。) Details 2 -> Explanation 2 如果 2.0 的答案是 No ,在2.1中显示详情 感谢大家抽空回答我的问题。
  • @TuBiLe:不客气。 Tomalak 是对的:与其为每个问题设置单独的条件,不如在输入 XML 中编码是否应在“是”或“否”上显示详细信息。这样您的 XSLT 就可以简单且一致。
  • 感谢您的建议。问题是我无法控制 XML。这是我公司购买的供应商应用程序。我的工作是在我无法访问代码或数据的情况下自定义报告:只有这个 XSLT 文件才能让事情正常工作。
  • @TuBiLe:明白。有时,XML 的供应商与您的目标不同(或不在乎)。
【解决方案2】:

根据经验。如果您的代码包含大量重复项,则说明您做错了。 XSLT 也不例外。

<!-- index followup questions (no zero after the dot) -->
<xsl:key 
  name="kFollowupQuestions"
  match="questions[number(substring-after(Number, '.')) != 0]" 
  use="number(substring-before(Number, '.'))"
/>

<!-- the <Survey> becomes the <fo:table-body> -->
<xsl:template match="Survey">
  <fo:table-body start-indent="0pt">
    <!-- only select main questions (with a zero after the dot) -->
    <xsl:apply-templates select="questions[number(substring-after(Number, '.')) = 0]">
      <xsl:sort select="Number" data-type="number" order="ascending" />
    </xsl:apply-templates>
  </fo:table-body>
</xsl:template>

<!-- each <questions> becomes a <fo:table-row> -->
<xsl:template match="questions">
  <xsl:variable name="qNum"   select="number(substring-before(Number, '.'))" />
  <xsl:variable name="subNum" select="number(substring-after(Number, '.'))" />
  <fo:table-row>
    <xsl:apply-templates select="Number" />
    <xsl:apply-templates select="Question" />
    <xsl:apply-templates select="Answer" />
    <xsl:apply-templates select="Details" />
  </fo:table-row>
  <!-- for main question answered with 'Yes', display followup-questions --> 
  <xsl:if test="Answer = 'Yes' and $subNum = 0">
    <xsl:apply-templates select="key('kFollowupQuestions', $qNum)">
      <xsl:sort select="Number" data-type="number" order="ascending" />
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<!-- the <questions> children become <fo:table-cell>s -->
<xsl:template match="questions/*">
  <fo:table-cell border="solid 1pt gray" padding="1pt" display-align="center">
    <fo:block text-align="right">
      <xsl:value-of select="." /><!-- or whatever -->
    </fo:block>
  </fo:table-cell>
</xsl:template>

http://www.xmlplayground.com/K4VHM2

【讨论】:

  • +1 用于 key() 和 DRY 原则。请注意,Answer='Yes' 与显示后续问题之间的相关性因问题而异。有时仅针对 Answer='No' 显示跟进。我认为这是重复的部分原因。虽然当然可以减少一些。
  • @LarsH 然后输入的 XML 应该包含一个信息,什么答案会触发后续。根据幻数(问题编号)做出这个决定是一个相当愚蠢的想法。在任何情况下,&lt;xsl:if&gt; 都可以像test="$subNum = 0 and (($qNum = 1 and Answer = 'Yes') or ($qNum = 2 and Answer = 'No'))" 一样轻松增强,但这会让我的大脑受伤。
  • 愚蠢的想法?这不是理想的情况,但有时要求并不是您想要的。也许 OP 可以控制输入 XML 的内容,也许没有。
  • @LarsH 是的。不过,即使他不受控制,这个想法也不会变得更聪明。 ;) 我知道有时事情有时是无能为力的,这并不是一种侮辱。
  • 非常感谢您,托马拉克。
    我完全同意你的看法:我不应该一个一个地硬编码*.1问题
    我正在学习你使用模板编码的方式。这是我可以很容易理解的最好的例子:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 2013-09-21
  • 1970-01-01
  • 2022-01-16
相关资源
最近更新 更多