我想使用XSLT 1.0實現此目的。小時以小時和分鐘表示(例如:10:30基本上是10小時30分鐘)。我需要將它轉換成只有幾小時(10.50),然後計算所有小時節點的總和。將以小時和分鐘表示的時間轉換爲十進制並使用xslt 1.0以小時計算總和
這裏是一個源XML文檔:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
</Record>
輸出:
我想使用XSLT 1.0實現此目的。小時以小時和分鐘表示(例如:10:30基本上是10小時30分鐘)。我需要將它轉換成只有幾小時(10.50),然後計算所有小時節點的總和。將以小時和分鐘表示的時間轉換爲十進制並使用xslt 1.0以小時計算總和
這裏是一個源XML文檔:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
</Record>
輸出:
請注意,Joepie的回答引起溶液編譯時語法錯誤在任何符合標準的XSLT 1.0
SAXON 6.5.4 from Michael Kay
Java version 1.6.0_31
Error at xsl:value-of on line 11 of file:/(Untitled):
Error in expression sum(hours/number(substring-before(., ':'))) + sum(hours/number(substring-after(., ':'))) div 60 : Unexpected token [<function>] in path expression
Transformation failed: Failed to compile stylesheet. 1 error detected.
Press any key to continue . . .
這裏是一個真正的工作,真X:處理器(它只能在不編譯錯誤若用XSLT 2.0處理程序執行) SLT 1.0溶液:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:variable name="vrtfTimes">
<xsl:for-each select="*">
<t>
<xsl:value-of select=
"substring-before(., ':') + substring-after(.,':') div 60"/>
</t>
</xsl:for-each>
</xsl:variable>
<TotalHours>
<xsl:value-of select="floor(sum(ext:node-set($vrtfTimes)/*))"/>
</TotalHours>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
當這個變換所提供的XML文檔應用:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
</Record>
有用,正確的結果產生:
<Record>
<TotalHours>42</TotalHours>
</Record>
備註:
如果你想獲得不僅從總和小時,還剩餘分鐘 - 爲分鐘:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:variable name="vrtfTimes">
<xsl:for-each select="*">
<t>
<xsl:value-of select=
"substring-before(., ':') + substring-after(.,':') div 60"/>
</t>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="vSum" select="sum(ext:node-set($vrtfTimes)/*)"/>
<TotalHours>
<xsl:value-of select="floor($vSum)"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="round(60* ($vSum - floor($vSum)))"/>
</TotalHours>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
當以下(稍微複雜)的XML應用這種轉變文檔:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
<hours>1:15</hours>
<hours>1:03</hours>
</Record>
正確的結果產生:
<Record>
<TotalHours>44:18</TotalHours>
</Record>
在XSLT 1.0:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="Record">
<Record>
<TotalHours>
<xsl:value-of select="
sum(hours/number(substring-before(., ':'))) +
sum(hours/number(substring-after(., ':'))) div 60
"/>
</TotalHours>
</Record>
</xsl:template>
</xsl:transform>
如果你也想在一個小時的分數代替紀要:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="Record">
<Record>
<TotalHours>
<xsl:value-of select="
concat(
sum(hours/number(substring-before(., ':'))) + floor(sum(hours/number(substring-after(., ':'))) div 60),
'.',
format-number(floor(sum(hours/number(substring-after(., ':'))) mod 60), '00')
)
"/>
</TotalHours>
</Record>
</xsl:template>
</xsl:transform>
Joepie,您在XSLT 1.0代碼中使用XPath 2.0語法 - 這隻能由XSLT 2.0處理器處理。請使用XSLT 1.0處理器運行此代碼以查看引發的語法錯誤。因此,按照OP的要求,這不是可用的XSLT 1.0解決方案。 –
嗨迪米特里,爲什麼說「這是一個真正可行的,真正的XSLT 1.0解決方案」。該解決方案使用默認變壓器中不可用的擴展?(您在功能xslt btw上工作的粉絲) – Joep
@Joepie,歡迎使用XSLT 1.0 - xxx:node-set()擴展功能是事實上的標準,可以大量使用。大多數情況下,使用它的解決方案更高效且易於編寫。在這種特殊情況下,我故意選擇提供更高效的非遞歸解決方案。一個遞歸解決方案是可能的,它不使用任何擴展,但是當遞歸列表的長度通常在1000左右時,遞歸解決方案存在由於(實際)堆棧溢出導致的效率低下和崩潰的問題。我強烈建議避免遞歸只要有可能。 –
@Joepie,我說「真正有效」,因爲與*你的*解決方案相反,這個解決方案使用XSLT 1.0處理器。 –