XSLT从XML文件中顺序检索属性值

时间:2017-10-20 11:27:21

标签: xml xslt xpath

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

怎么做?

提前致谢。

目前的情况如下:

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

2 个答案:

答案 0 :(得分:1)

  

我在使用XSLT格式化XML文件时遇到了问题。   通常我想要按顺序检索每个属性的值   包含在XML元素中。 Currentlz它在XSLT和I中是硬编码的   意识到如果我的XML文件发生变化,XSLT就无法完成它的工作。

输入XML的格式是否真的需要担心和解决?想一想。在任何情况下,现有转换是否能够在改变输入XML格式的情况下正确地完成其工作取决于转换的工作应该是什么,以及发生什么样的改变。

如果它的工作是以特定的顺序呈现一组特定的字段,那么我认为它将会令人钦佩地完成它的工作。特别是,它将以一致的顺序显示所选字段,而不管它们在输入文档中出现的顺序如何,为实际不存在的属性发出空单元格。如果输出是供人类消费的,那么所有这些都可能是好的事物。

  

我   试图用类似的东西   检索元素的第一个属性值,但它不起作用。

     

好的,正如@TimC回答的那样,我不需要@中的括号和名字(名称(@ * [1]))   对我来说没问题。

     

现在的问题是如何创建一个迭代元素的循环   从1开始,让我们说7

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

例如,如果要处理每个&lt; testcase&gt;的所有属性上下文节点,然后您需要的是这样的:

<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&lt; td&gt;每个测试用例的元素,无论是否有很多属性,然后你要回到原始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>

答案 1 :(得分:0)

正如评论中所提到的,XML中的属性是无序的。如果你想要获得所有属性而不管订单如何,你可以这样做......

testcase

但是,对于多个<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> 元素,无法保证每行中的属性具有相同的顺序。但是如果你真的想让你的XSLT尽可能通用,你可以将订单基于第一行。

试试这个XSLT

private boolean hasNetworkAccess() {
    try {
        HttpURLConnection urlc = (HttpURLConnection) (new URL("http://www.screens.company").openConnection());
        urlc.setRequestProperty("User-Agent", "Test");
        urlc.setRequestProperty("Connection", "close");
        urlc.setConnectTimeout(3000);
        urlc.connect();
        return (urlc.getResponseCode() == 200);
    } catch (IOException e) {
        Log.e("NETWORK", "Error checking internet connection.");
    }
    return false;
}