XSLT多个节点同名同一级别

时间:2010-07-28 01:54:45

标签: xml xslt

我有以下XML文档:

<ReportParameters SP="prRptActivityDetail">
    <Parameter>
        <Name>Period Start Date</Name>
        <Type>Date</Type>
        <Control>DateTextbox</Control>
        <ControlName>dtePeriodStartDate</ControlName>
        <Validators>
            <Validator>Required</Validator>
            <Validator>DataTypeCheck</Validator>
            <Validator>StartBeforeEnd</Validator>
        </Validators>
    </Parameter>
</ReportParameters>

我编写了一个XSLT文件来转换上面的内容:

<xsl:for-each select="ReportParameters/Parameter/Validators">
   <xsl:choose>
       <xsl:when test="Validator='Required'">
           <span>
               <REQUIRED VALIDATOR CONTROL HERE>
           </span>
       </xsl:when>
       <xsl:when test="Validator='DataTypeCheck'">
           <span>
               <DATA TYPE CHECK VALIDATOR CONTROL HERE>
           </span>
       </xsl:when>
   </xsl:choose>

为清晰起见,我遗漏了很多XSLT。

对于每个参数控件(在这种情况下为Period Start Date)我希望列出所有验证器(在本例中为3)作为验证器控件放在页面上,但是我在使用for-each时只得到第一个验证器。我知道为什么这是,但我是xslt的完全新手,并且不知道解决这个问题的语法。

任何帮助非常感谢,

4 个答案:

答案 0 :(得分:2)

我认为问题在于你正在循环'Validators'集合。您想要遍历'Validator'的所有实例。

尝试:(example I used in research

<xsl:for-each select="ReportParameters/Parameter/Validators/Validator">
   <xsl:choose>
       <xsl:when test=".='Required'">
           <span>
               <REQUIRED VALIDATOR CONTROL HERE>
           </span>
       </xsl:when>
       <xsl:when test=".='DataTypeCheck'">
           <span>
               <DATA TYPE CHECK VALIDATOR CONTROL HERE>
           </span>
       </xsl:when>
   </xsl:choose>

答案 1 :(得分:1)

在学习XSLT时,最好知道应该避免使用<xsl:for-each> ,除非这确实是必要的。

这是一个简单而简短的“无环路”方式,以纯粹的推送方式实现相同的目标:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:variable name="vrtfValidatorNames">
  <validator type="Required" name="REQUIRED"/>
  <validator type="DataTypeCheck" name="DATA TYPE CHECK"/>
  <validator type="StartBeforeEnd" name="START BEFORE END"/>
 </xsl:variable>

 <xsl:variable name="vValidatorNames" select=
  "document('')/*/xsl:variable[@name='vrtfValidatorNames']/*"/>

 <xsl:template match="Validator">
   &lt;<xsl:value-of select="$vValidatorNames[@type=current()]/@name"/> VALIDATOR CONTROL HERE>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<ReportParameters SP="prRptActivityDetail">
    <Parameter>
        <Name>Period Start Date</Name>
        <Type>Date</Type>
        <Control>DateTextbox</Control>
        <ControlName>dtePeriodStartDate</ControlName>
        <Validators>
            <Validator>Required</Validator>
            <Validator>DataTypeCheck</Validator>
            <Validator>StartBeforeEnd</Validator>
        </Validators>
    </Parameter>
</ReportParameters>

生成了想要的结果

   <REQUIRED VALIDATOR CONTROL HERE>

   <DATA TYPE CHECK VALIDATOR CONTROL HERE>

   <START BEFORE END VALIDATOR CONTROL HERE>

答案 2 :(得分:1)

我建议您将<xsl:for-each代码替换为:

<xsl:apply-templates select="ReportParameters/Parameter/Validators/Validator" />

并为每个模板添加模板:

<xsl:template match="Validator[text()='Required']">
  ...
</xsl:template>

<xsl:template match="Validator[text()='DataTypeCheck']">
  ..
</xsl:template>

 etc.

正如@kniemczak所说,你实际上只是在循环中通过父元素。

答案 3 :(得分:0)

对于此类任务,您无需显式循环元素。这不是XSLT的方式。在与树结构的匹配方面考虑更多。

这样的事情会起作用:

<xsl:if test="ReportParameters/Parameter/Validators/Validator='Required'">
    <span>
        <REQUIRED></REQUIRED>
     </span>
</xsl:if>
<xsl:if test="ReportParameters/Parameter/Validators/Validator='DataTypeCheck'">
    <span>
        <DATA></DATA>
    </span>
</xsl:if>

另请参阅创建子<xsl:template>并使用<xsl:apply-templates>调用它们来处理树的较小部分。对于大型变换,它应该更易于维护。