2012-09-17 84 views
1

我輸入XML文件看起來像XSLT分組值

<test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
     <segment id="ORC"/> 
     <segment id="OBR"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
    </test-message> 
在我上面的輸入XML文件中的元素 ID

= 「ORC」是可選

我想group我的輸入XML文件基於元素id =「ORC」或元素id =「OBR」

爲上述輸入的XML文件我想有以下結果,當元件段id爲「ORC」是本

<message-group> 
    <test-message> 
      <segment id="MSH"/> 
      <segment id="SFT"/> 
      <segment id="PID"/> 
      <segment id="NTE"/> 
      <segment id="NK1"/> 
      <segment id="PV1"/> 
</test-message> 
<test-message> 
      <segment id="ORC"/> 
      <segment id="OBR"/> 
      <segment id="NTE"/> 
      <segment id="OBX"/> 
      <segment id="NTE"/> 
      <segment id="SPM"/> 
     </test-message> 
</message-group> 

爲上述輸入的XML文件我想有下面結果,當元件段id爲「ORC」不存在

<message-group> 
    <test-message> 
      <segment id="MSH"/> 
      <segment id="SFT"/> 
      <segment id="PID"/> 
      <segment id="NTE"/> 
      <segment id="NK1"/> 
      <segment id="PV1"/> 
</test-message> 
<test-message> 
      <segment id="OBR"/> 
      <segment id="NTE"/> 
      <segment id="OBX"/> 
      <segment id="NTE"/> 
      <segment id="SPM"/> 
     </test-message> 
</message-group> 

我可以具有XSLT(2.0)模板或函數來處理上述場景

注:我利用XSLT 2.0和薩克森解析器

回答

1

這種轉變

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <message-group> 
    <xsl:for-each-group select="*" group-starting-with= 
    "segment[@id='ORC'][not(preceding-sibling::segment[1][@id='OBR'])] 
    | segment[@id='OBR'][not(preceding-sibling::segment[1][@id='ORC'])] 

    "> 

     <test-message><xsl:sequence select="current-group()"/></test-message> 
    </xsl:for-each-group> 
    </message-group> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
     <segment id="ORC"/> 
     <segment id="OBR"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
</test-message> 

產生想要的,正確的結果:

<message-group> 
    <test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
    </test-message> 
    <test-message> 
     <segment id="ORC"/> 
     <segment id="OBR"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
    </test-message> 
</message-group> 

當相同的變換(上文)此XML文檔( 'ORC' 不存在)上施加:

<test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
     <segment id="OBR"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
</test-message> 

再次有用,正確的結果產生

<message-group> 
    <test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
    </test-message> 
    <test-message> 
     <segment id="OBR"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
    </test-message> 
</message-group> 

如果對此XML文檔應用相同的轉換('OBR'不存在):

<test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
     <segment id="ORC"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
</test-message> 

再次通緝,正確的結果產生

<message-group> 
    <test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
    </test-message> 
    <test-message> 
     <segment id="ORC"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
    </test-message> 
</message-group> 

最後,當這兩個 'ORC' 和 'OBR' 都存在,但 'OBR' 先於 'ORC'

<test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
     <segment id="OBR"/> 
     <segment id="ORC"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
</test-message> 

同樣正確的,希望產生結果

<message-group> 
    <test-message> 
     <segment id="MSH"/> 
     <segment id="SFT"/> 
     <segment id="PID"/> 
     <segment id="NTE"/> 
     <segment id="NK1"/> 
     <segment id="PV1"/> 
    </test-message> 
    <test-message> 
     <segment id="OBR"/> 
     <segment id="ORC"/> 
     <segment id="NTE"/> 
     <segment id="OBX"/> 
     <segment id="NTE"/> 
     <segment id="SPM"/> 
    </test-message> 
</message-group> 
0

的有兩個是速速頭腦相當簡單的方式。 (1)在您的模板test-message中,包含兩個test-message輸出元素,每個元素包含apply-templates指令。給apply-templates一個參數來區分第一個和第二個調用。

說,類似的信息(未測試):

<xsl:template match="test-message"> 
    <test-message> 
    <xsl:apply-templates> 
     <xsl:with-param name="flag" select="1"/> 
    </xsl:apply-templates> 
    </test-message> 
    <test-message> 
    <xsl:apply-templates> 
     <xsl:with-param name="flag" select="2"/> 
    </xsl:apply-templates> 
    </test-message> 
</xsl:template> 

在模板segment,寫出來的元素的副本如果(a)$標誌= 1和既不該段也沒有任何前述同級段具有OBRORC的標識,否則如果(b)$ flag = 2並且該段或某個前面的兄弟段具有這樣的id。像

<xsl:template match="segment"> 
    <xsl:param name="flag"/> 
    <xsl:if test="(
        $flag = 1 
        and not(@id = ('ORC', 'OBR')) 
        and not(preceding-sibling::segment 
         [@id=('ORC','OBR')]) 
       ) or (
        $flag = 2 
        and ((@id = ('ORC', 'OBR')) 
         or preceding-sibling::segment 
         [@id=('ORC','OBR')] 
       )"> 
    <xsl:copy-of select="."/> 
</xsl:if> 

的東西(2)使test-message模板上面,但增加select="./segment[1]"兩個調用xsl:apply-templates

然後讓segment的模板完成其工作,然後在其緊隨其後的同級中重複使用。爲了保持邏輯簡單,我們區分了幾種情況:首先,$flag=1,但我們還沒有看到OBR或ORC:複製當前元素並繼續前進。

<xsl:template match="segment"> 
    <xsl:param name="flag"/> 
    <xsl:choose> 
    <xsl:when test="$flag=1 and not(@id=('OBR', 'ORC'))"> 
     <xsl:copy-of select="."/> 
     <xsl:if test="not(@id=('OBR','ORC'))"> 
     <xsl:apply-templates select="following-sibling::*[1]"> 
      <xsl:with-param name="flag" select="$flag"/> 
     </xsl:apply-templates> 
     </xsl:if> 
    </xsl:when> 

二,$flag = 1我們現在遇到了OBR或ORC。不要複製當前元素,也不要繼續;第一個test-message元素現在完成。

<xsl:when test="$flag=1 and @id=('OBR', 'ORC')"> 
     <!--* do nothing, stop recursion *--> 
    </xsl:when> 

三,$flag = 2我們還沒有遇到過OBR或ORC。繼續。

<xsl:when test="$flag=2 and not(@id=('OBR', 'ORC'))"> 
     <!--* don't copy yet, keep looking for OBR/ORC *--> 
     <xsl:apply-templates select="following-sibling::*[1]"> 
     <xsl:with-param name="flag" select="$flag"/> 
     </xsl:apply-templates> 
    </xsl:when> 

四,$flag = 2我們現在遇到了OBR或ORC。複製當前元素並繼續;旗切換到第三值,這意味着我們在第二test-message元素,我們已經看到OBR或ORC:

<xsl:when test="$flag=2 and @id=('OBR', 'ORC')"> 
     <xsl:copy-of select="."/> 
     <xsl:apply-templates select="following-sibling::*[1]"> 
     <xsl:with-param name="flag" select="3"/> 
     </xsl:apply-templates> 
    </xsl:when> 

最後,如果$flag = 3那麼我們剛纔複製的當前元素並保持下去。

<xsl:when test="$flag=3"> 
     <xsl:copy-of select="."/> 
     <xsl:apply-templates select="following-sibling::*[1]"> 
     <xsl:with-param name="flag" select="3"/> 
     </xsl:apply-templates> 
    </xsl:when> 
    </xsl:choose> 
</xsl:template> 
0

如果你總是分裂成序列正好有兩個組,那麼我想我會做到這一點:

<xsl:variable name="split" select="segment[@id=('ORC', 'OBR')][1]"/> 
<test-message> 
    <xsl:copy-of select="$split/preceding-sibling::*"/> 
</test-message> 
<test-message> 
    <xsl:copy-of select="$split, $split/following-sibling::*"/> 
</test-message>