需要忽略整个Body元素集的元素值

时间:2017-03-03 06:49:57

标签: xml xslt xslt-2.0

我想忽略整个Body元素集的特定实例的元素,

我的输入xml是:

<Body>
<p> </p>
<h1>Taking</h1>
<p>Your records.</p>
<h2>Blood Pressure?</h2>
<p>mmm.</p>
</Body>

XSL我用作:

<xsl:template match="Body">
      <xsl:for-each-group select="*" group-starting-with="h1">
         <topic>
            <xsl:attribute name="id">topic_<xsl:number count="h1 | h2"/></xsl:attribute>
            <title>
               <xsl:apply-templates select="node()"/>
            </title>

            <xsl:for-each-group select="current-group() except ." group-starting-with="h2">
               <xsl:choose>
                  <xsl:when test="self::h2">
                     <topic>
                        <xsl:attribute name="id">topic_<xsl:number count="h1 | h2"/></xsl:attribute>
                        <title>
                           <xsl:apply-templates select="node()"/>
                        </title>
                        <body><xsl:apply-templates select="current-group() except ."/></body>
                     </topic>
                  </xsl:when>
                  <xsl:otherwise>
                     <body><xsl:apply-templates select="current-group()"/></body>
                  </xsl:otherwise>
               </xsl:choose>
            </xsl:for-each-group>
            </topic>
      </xsl:for-each-group>
   </xsl:template>

   <xsl:template match="p">
   <p><xsl:apply-templates/></p>
   </xsl:template>

我的输出为:

<topic id="topic_">
   <title> </title>
</topic>
<topic id="topic_1">
   <title>Taking</title>
   <body>
      <p>Your records.</p>
   </body>
   <topic id="topic_2">
      <title>Blood Pressure?</title>
      <body>
         <p>mmm.</p>
      </body>
   </topic>
</topic>

预期输出为:

<topic id="topic_1">
   <title>Taking</title>
   <body>
      <p>Your records.</p>
   </body>
   <topic id="topic_2">
      <title>Blood Pressure?</title>
      <body>
         <p>mmm.</p>
      </body>
   </topic>
</topic>

由于<p> </p>的不需要的元素。我在输出中收到错误。我们如何通过使用Body模板来忽略该特定实例。请建议我代码。提前致谢

1 个答案:

答案 0 :(得分:1)

您的XSLT失败的原因是for-each-group操作方式(至少在 Saxon 引擎中)的一个奇怪细节。

如果源内容不是以group-starting-with中给出的元素开头,则之前的整个内容会创建第一个 false 输出组。

要解决此问题,您必须:

  • 读取当前输出组中的第一个节点。
  • 仅在其名称符合预期时才执行进一步操作。

下面你有一个有效的解决方案。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:template match="Body">
    <xsl:copy>
      <xsl:for-each-group select="*" group-starting-with="h1">
        <xsl:variable name="tag1" select="current-group()[1]"/>
        <xsl:if test="$tag1/name() = 'h1'">
          <topic id="topic_1">
            <title><xsl:value-of select="$tag1"/></title>
            <xsl:apply-templates select="current-group()[2]"/>
            <xsl:for-each-group select="current-group()" group-starting-with="h2">
              <xsl:variable name="tag1" select="current-group()[1]"/>
              <xsl:if test="$tag1/name() = 'h2'">
                <topic id="topic_2">
                  <title><xsl:value-of select="$tag1"/></title>
                  <xsl:apply-templates select="current-group()[name()='p']"/>
                </topic>
              </xsl:if>
            </xsl:for-each-group>
          </topic>
        </xsl:if>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="p">
    <body>
      <xsl:sequence select="."/>    
    </body>    
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>
</xsl:transform>

请注意,我为copy元素添加了Body。 否则,如果您的源包含多个h1元素,则会得到格式不正确的输出 (在第1级XML必须包含仅1 根标记)。

相关问题