1

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

上記の入力 XML ファイル要素セグメントid="ORC"はオプションです

id="ORC"の要素セグメントまたはid="OBR"の要素セグメントに基づいて、入力 XML ファイルをグループ化したい

上記の入力 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 と saxon パーサーを使用しています。

4

3 に答える 3

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>
于 2012-09-18T04:23:15.200 に答える
0

すぐに思いつく簡単な方法が 2 つあります。

(1) のテンプレートに、それぞれに命令を含むtest-message2 つのtest-message出力要素を含めます。1 回目と 2 回目の呼び出しを区別するためのパラメーターを指定しますapply-templatesapply-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) $flag = 1 で、このセグメントも先行する兄弟セグメントも の ID を持たない場合、または (b) $flag = 2 で、このセグメントまたは一部のセグメントの場合は、要素のコピーを書き出しOBRますORC。前の兄弟セグメントには、そのような があり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]"への 2 つの呼び出しに追加しxsl:apply-templatesます。

segment次に、その作業を行うためのテンプレートを作成し、その直後の兄弟で繰り返します。ロジックを単純にするために、いくつかのケースを区別します。まず、$flag=1OBR や 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 = 1OBR または ORC に直面しています。現在の要素をコピーせず、続行しないでください。最初のtest-message要素が完成しました。

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

3 つ目は、$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>

4 つ目は、$flag = 2OBR または ORC に遭遇したことです。現在の要素をコピーして続行します。フラグを 3 番目の値に切り替えます。これは、2 番目の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>
于 2012-09-17T22:59:21.217 に答える
0

シーケンスを常に正確に 2 つのグループに分割する場合は、次のようにします。

<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>
于 2012-09-18T08:11:57.800 に答える