2017-10-20 128 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