2017-10-20 77 views
0

我使用XSLT格式化XML文件以生成HTML时遇到了问题。通常我想依次检索XML元素中包含的每个属性的值。 Currentlz它在XSLT中被硬编码,我意识到如果我的XML文件会改变,XSLT将无法完成它的工作。 我试图使用类似<xsl:value-of select="@(name(@*[1]))" />的东西来检索元素的第一个属性值,但它不起作用。XSLT从XML文件中顺序检索属性值

如何做到这一点?

在此先感谢。

这里是如何看起来像此刻:

<xsl:for-each select="testsuites/testsuite/testcase"> 
    <xsl:if test="@failure='PASSED'"> 
     <tr style="color:green;font-weight:bold"> 
      <td style="text-align:center"> 
       <xsl:value-of select="@classname" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@name" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@Plate" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@Distance" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@Side" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@Angle" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="@failure" /> 
      </td> 
      <td style="text-align:center"> 
       <xsl:value-of select="failure/@message" /> 
      </td> 
     </tr> 
    </xsl:if> 
    ... and so one 

这里是我的XML文件的一部分:

<testsuites disabled="0" errors="0" failures="1" passes="16" skipped="0"  tests="17" time="1"> 
    <testsuite disabled="0" id="0" name="Bok" time="1" tests="4"> 
     <testcase classname="XYZ" name="description" Plate="blah" Distance="A" Side="L" Angle="15" failure="PASSED"> 
      <system-out/> 
      <system-err/> 
     </testcase> 
     <testcase classname="XYZ" name="description" Plate="blah" Distance="A" Side="L" Angle="60" failure="PASSED"> 
      <system-out/> 
      <system-err/> 
     </testcase> 
     <testcase classname="XYZ" name="description" Plate="blah" Distance="A" Side="L" Angle="30" failure="PASSED"> 
      <system-out/> 
      <system-err/> 
     </testcase> 
     <testcase classname="XYZ" name="description" Plate="blah" Distance="A" Side="L" Angle="60" failure="PASSED"> 
      <system-out/> 
      <system-err/> 
     </testcase> 
    </testsuite> 
    ... and so one 

编辑: 好,因为@TimC回答我不知道需要括号和名称@(name(@*[1])),这对我来说很好。

现在的问题是如何使一个循环,这将是迭代的元素从1到让我们说7,我的意思是这样的:

<xsl:for-each select="$var=1 to 7"> 
    <td style="text-align:center"> 
     <xsl:value-of select="@*[$var]" /> 
    </td> 
</xsl:for-each> 
+0

在您的示例失败不是第一个属性,实际上没有失败但失败。 – derloopkat

+0

@derloopkat无论如何,属性是无序的,它们在源代码中的顺序并不意味着什么。 – Tomalak

+0

好吧,你说你想要第一个属性值 – derloopkat

回答

1

我已经得到了使用XSLT使HTML带格式的XML文件中的问题。 通常我想要依次检索包含在XML元素中的每个属性 的值。 Currentlz它在XSLT中被硬编码,并且我认识到如果我的XML文件将改变,XSLT将无法完成其工作。

这是对输入XML格式的改变,真的是您现在需要担心和考虑的事情吗?请考虑一下。在任何情况下,现有变换在改变输入XML格式的事实上是否能够正确地完成其工作取决于变换的工作应该是什么以及发生什么样的变化。

如果它的工作是以特定的顺序呈现一组特定的领域,那么它看起来像它会令人钦佩地工作。特别是,它将以一致的顺序显示所选字段,而不管它们在输入文档中的显示顺序如何,为实际不存在的属性发出空单元格。如果输出是打算供人消费的话,那么大概好的的东西。

我 尝试使用类似 检索元素的第一属性值,但它不工作。

好吧,正如@TimC回答,我不需要括号和名称@(名称(@ * [1])) ,这对我来说很好。

现在的问题是如何使一个循环,这将是迭代元素 从1到假设7

号如果你真的想这样做,则停止思考像一个程序的程序员。 XSLT没有循环,本身。其操作模式涉及选择一个或多个节点,然后将每个节点依次用作实例化模板的上下文。缺少任何排序指令,它将按文档顺序处理节点。你试图让它变得比它需要的更难。

例如,如果你想处理每个<测试用例>上下文节点的所有属性,那么所有你需要的是这样的:

<xsl:for-each select="@*"> 
    <td style="text-align:center"> 
     <xsl:value-of select="." /> 
    </td> 
</xsl:for-each> 

如果你想只处理第7,而不管的有多少,然后在选择指定:

<xsl:for-each select="@*[position() < 8]"> 
    <td style="text-align:center"> 
     <xsl:value-of select="." /> 
    </td> 
</xsl:for-each> 

如果,另一方面,你要保证你发出正好为7 < TD>元素对每个测试用例,是否有许多属性或者不是,那么无论你又回到了沿着原来的XSL线的东西:

<td style="text-align:center"> 
    <xsl:value-of select="@*[1]" /> 
</td> 
<td style="text-align:center"> 
    <xsl:value-of select="@*[2]" /> 
</td> 
<!-- ... --> 

,否则你需要编写一个模板来执行迭代,也许是这样的:

<xsl:call-template name="iterate-testcase-attributes"> 
    <xsl:with-param name="up-to" select="7"/> 
</xsl:call-template> 

...

<xsl:template name="iterate-testcase-attributes"> 
    <xsl:param name="current" select="1"/> 
    <xsl:param name="up-to" select="1"/><!-- the select value is only a default --> 
    <td style="text-align:center"> 
    <!-- will produce nothing if the context node has no such attribute --> 
    <xsl:value-of select="@*[position() = $current]" /> 
    </td> 
    <xsl:if test="$current < $up-to"> 
    <xsl:call-template name="iterate-testcase-attributes"> 
     <xsl:with-param name="current" select="$current + 1"/> 
     <xsl:with-param name="up-to" select="$up-to"/> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
+0

感谢您的建议,我必须密切关注它们,通常我不太熟悉XSLT编码所以这就是为什么我问这个问题;) – asdator1213

+0

我的意图是创建一个XSLT,在有人向XML中添加更少或更多的新属性后,不需要进行很多更改。 无论如何,再次感谢您的帮助。 – asdator1213

+0

@ asdator1213,我认为你需要澄清一下,至少对你自己来说,如果(1)你当前期望的某个属性没有提供,或者(2)提供了附加属性,或者(3)属性的显示顺序与您以前看到的顺序不同。没有这些,你无法评估候选样式表。 –

0

正如在评论中提到,在XML属性是未排序。如果你想想不顾一切属性的顺序,你可以这样做......

<xsl:for-each select="@*"> 
    <td style="text-align:center"> 
    <xsl:value-of select="." /> 
    </td> 
</xsl:for-each> 

但是,与多个testcase元素,也不能保证每一行的属性会以相同的顺序。但是如果你真的想让你的XSLT尽可能通用,你可以将订单放在第一行。

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:template match="/"> 
    <table border="1"> 
     <xsl:variable name="attrs" select="testsuites/testsuite[1]/testcase[1]/@*" /> 
     <tr> 
     <xsl:for-each select="$attrs"> 
      <th> 
      <xsl:value-of select="local-name()" /> 
      </th> 
     </xsl:for-each> 
     </tr> 
     <xsl:for-each select="testsuites/testsuite/testcase[@failure='PASSED']"> 
     <xsl:variable name="currentCase" select="." />  
     <tr style="color:green;font-weight:bold"> 
      <xsl:for-each select="$attrs"> 
      <xsl:variable name="currentAttr" select="local-name()" />  
      <td style="text-align:center"> 
       <xsl:value-of select="$currentCase/@*[local-name() = $currentAttr]" /> 
      </td> 
      </xsl:for-each> 
     </tr> 
     </xsl:for-each> 
    </table> 
    </xsl:template> 
</xsl:stylesheet> 
+0

谢谢您的回答;) – asdator1213