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

有两种相当简单的方法很快就会浮现在脑海中。

(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>

在 for 的模板中segment,如果 (a) $flag = 1 并且此段和任何前面的兄弟段的 id 都不是OBRor ORC,或者如果 (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>
于 2012-09-17T22:59:21.217 回答
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>
于 2012-09-18T08:11:57.800 回答