2017-08-01 20 views
1

我是新的xslt轉換,我遇到了一些麻煩。 我需要排序和過濾元素,在下面的例子中,我設法用兩個xlt轉換對輸入xml進行排序和過濾。 我的問題是:如何對一個xsl文件進行排序然後過濾排序後的數據? 在此先感謝。xslt在排序後的數據上應用模板

XML輸入:

<?xml version="1.0" encoding="UTF-8"?> 
 
<root> 
 
    <data> 
 
     <id>00000_1111_2222</id> 
 
     <startedAt>2017-08-21T11:55:08.382Z</startedAt> 
 
     <endedAt>2017-08-21T12:07:08.539Z</endedAt> 
 
     <positions> 
 
      <timestamp>2017-08-21T11:55:28.041Z</timestamp> 
 
      <latitude>40.2407009</latitude> 
 
      <longitude>10.7750499</longitude>  
 
     </positions> 
 
     <positions> 
 
      <timestamp>2017-08-21T11:55:28.041Z</timestamp> 
 
      <latitude>40.2409364</latitude> 
 
      <longitude>10.7748426</longitude> 
 
     </positions> 
 
     <positions> 
 
      <timestamp>2017-08-21T11:55:38.041Z</timestamp> 
 
      <latitude>40.240409</latitude> 
 
      <longitude>10.7751432</longitude>  
 
     </positions> 
 
    </data> 
 
</root>

XSL排序:

<?xml version="1.0" encoding="UTF-8"?> 
 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 
    exclude-result-prefixes="xs" version="2.0"> 
 
    
 
    <xsl:template match="@*|node()"> 
 
     <xsl:copy> 
 
      <xsl:apply-templates select="@*|node()" /> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
    <xsl:template match="data"> 
 
     <xsl:copy> 
 
      <xsl:apply-templates select="*[not(self::positions)]"/> 
 
      <xsl:apply-templates select="positions"> 
 
       <xsl:sort select="timestamp" order="descending"/> 
 
      </xsl:apply-templates> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
    
 
</xsl:stylesheet>

XSL濾波:

<?xml version="1.0" encoding="UTF-8"?> 
 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 
    exclude-result-prefixes="xs" 
 
    version="2.0"> 
 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
 
    <xsl:template match="@*|node()"> 
 
     <xsl:copy> 
 
      <xsl:apply-templates select="@*|node()" /> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
    <xsl:template match="data"> 
 
     <xsl:copy> 
 
      <xsl:apply-templates select="*[not(self::positions)]" /> 
 
      <xsl:copy-of select="positions[position() &lt;= 4]"/> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
</xsl:stylesheet>

如果我想保留原始的XMLStructure,是corret這個XSL?

<?xml version="1.0" encoding="UTF-8"?> 
 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 
    exclude-result-prefixes="xs" 
 
    version="1.0"> 
 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
 
    <xsl:output omit-xml-declaration="no" indent="yes"/> 
 
    <xsl:strip-space elements="*"/> 
 
    
 
    <!-- Identity template --> 
 
    <xsl:template match="@*|node()"> 
 
     <xsl:copy> 
 
      <xsl:apply-templates select="@*|node()"/> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
    
 
    <!-- Sort and filter positions elements --> 
 
    <xsl:template match="data"> 
 
     <xsl:copy> 
 
      <xsl:for-each select="positions"> 
 
       <xsl:sort select="timestamp" order="descending"/> 
 
       <xsl:if test="position() &lt;= 2"> 
 
        <xsl:apply-templates select="."/> 
 
       </xsl:if> 
 
      </xsl:for-each> 
 
     </xsl:copy> 
 
    </xsl:template> 
 
</xsl:stylesheet>

我的預期輸出XML是:

<?xml version="1.0" encoding="UTF-8"?> 
 
<root> 
 
    <data> 
 
     <id>00000_1111_2222</id> 
 
     <startedAt>2017-08-21T11:55:08.382Z</startedAt> 
 
     <endedAt>2017-08-21T12:07:08.539Z</endedAt> 
 
     
 
     <positions> 
 
     <timestamp>2017-08-21T11:55:38.041Z</timestamp> 
 
     <latitude>40.240409</latitude> 
 
     <longitude>10.7751432</longitude> 
 
     </positions> 
 
     <positions> 
 
     <timestamp>2017-08-21T11:55:28.041Z</timestamp> 
 
     <latitude>40.2407009</latitude> 
 
     <longitude>10.7750499</longitude> 
 
     </positions> 
 
    </data> 
 
</root>

但這種方式我失去所有的元素沒有 「位置」 元素的子:ID ,開始了,結束了。 因此,我試圖在<xsl:template match="data">之後加上:<xsl:apply-templates select="* [not(self :: positions)] />,但是如果所有的NOT「position」child都在position元素後面呢? XML結構/訂單。有沒有辦法來實現一種通用的方式最後這件事? 謝謝。

回答

1

鑑於XSLT 2.0可以使用

<xsl:variable name="sorted-positions" as="element(positions)*"> 
    <xsl:perform-sort select="positions"> 
    <xsl:sort select="timestamp" order="descending"/> 
    </xsl:perform-sort> 
</xsl:variable> 

,然後<xsl:copy-of select="$sorted-positions[position() le 4]"/>(或應用模板上那些元素當然)

或者你可以使用例如

 <xsl:apply-templates select="positions"> 
      <xsl:sort select="timestamp" order="descending"/> 
     </xsl:apply-templates> 

然後

<xsl:template match="positions"> 
    <xsl:if test="position() le 4"> 
    <xsl:next-match/> 
    </xsl:if> 
</xsl:template> 

使用XSLT 1.0,當然你可以使用例如

<xsl:for-each select="positions"> 
    <xsl:sort select="timestamp" order="descending"/> 
    <xsl:if test="position() &lt;= 4"> 
    <xsl:apply-templates select="."/> 
    </xsl:if> 
</xsl:for-each> 

當然也具有有使用copy-of代替apply-templates的的選擇。

最後用XSLT 3。爲sort功能0和支持(https://www.w3.org/TR/xpath-functions-31/#func-sort),您可以直接apply-templates的排序序列(或在您的情況下,在reverseð排序序列有順序降序)和過濾序列:

<xsl:template match="data"> 
    <xsl:copy> 
     <xsl:apply-templates select="* except positions, reverse(sort(positions,(), function($p) { $p/timestamp}))[position() le 4]"/> 
    </xsl:copy> 
</xsl:template> 
+0

謝謝你侑很好的答案,只是一件事:如果我會保留原始的XML文件結構?如何保護其他節點?我將舉一個編輯示例 – Daniel

+0

好吧,您的原始方法以及您的評論有一個方法,即在要處理其他子節點的位置添加一個「apply-templates」。至於更通用的解決方案,我認爲如果您提出一個顯示某些輸入樣本的新問題會更好,我認爲我們需要了解輸入可以存在哪些變體(「位置」之前和/或之後的內容,與內容混合的內容'職位'),然後你如何重新排列元素(所有'位置'一起?)。還請明確說明您是否可以使用XSLT 2.0。 –