如何计算忽略他们是孩子还是兄弟姐妹的元素?

时间:2015-07-15 19:03:03

标签: xslt-1.0

这可能是一个新手问题,但是,我再说一遍: - )

旧情况:

我有以这种格式的XML文件:

<chapter>
  <title>chapter title</title>
  <para>p1</para>
  <para>p2</para>
  <para>p3</para>

    <!-- ....and so on for a lot of para elements -->

</chapter>

...由像这样的XSL模板处理......

<xsl:template match="para">   
   <xsl:if test="count(following-sibling::para) = 1 and count(preceding-sibling::para) &gt; 13">
       <!-- Insert Some Stuff -->
   </xsl:if>
</xsl:template>

这里的逻辑是:如果前面有足够的&lt; para&gt;,则在倒数第二个元素之前插入一些东西。兄弟姐妹。

此代码完成工作并正常工作。

新情况

现在,由于我无法控制的原因,我需要调整该模板以处理以下类型的文件......

<chapter>
  <title>chapter title</title>
  <para>p1</para>
  <para>p2</para>
  <para>p3</para>
  <section>
     <para>p4</para>
     <para>p5</para>
  </section>
  <para>p6</para>
  <section>
     <title>section title</title> 
  </section>
  <para>p7</para>
  <section>
     <para>p8</para>
  </section>

  <!-- ....and so on for a lot of para elements -->

</chapter>

与这些文件的区别在于&lt; section&gt;元素可以随机出现,有时包含&lt; para&gt;元素,有时不是。没有办法预测何时何地&lt; section&gt;元素将出现。

我需要原始的XSL模板以相同的方式使用这种格式,尽管&lt; section&gt;元素在那里。这意味着&lt; para&gt;即使他们有时是孩子,有时也是兄弟姐妹,他们仍然需要以相同的方式计算。

总之,我需要旧代码的逻辑像以前一样工作,好像它完全忽略了&lt; section&gt;的存在。元件。

原始模板&lt; xsl:if test =“...”&gt;应该是什么?被重写以使其成功?

性能不是问题 - 这些都是手动运行的临时转换。

仅限XSLT 1.0,

感谢。

1 个答案:

答案 0 :(得分:1)

如果没有看到完整的样式表和预期的输出,很难回答你的问题。

不会:

<xsl:template match="para">   
   <xsl:if test="count(following::para) = 1 and count(preceding::para) &gt; 13">
       <!-- Insert Some Stuff -->
   </xsl:if>
</xsl:template>

为你工作?

加了:

  

如果您确定您建议的内容应该适用于该示例   在问题中给出

嗯,问题中给出的示例没有所需的最小para个节点 - 但是如果我们降低了阈值:

XSLT 1.0

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

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

<xsl:template match="para"> 
    <xsl:if test="count(following::para) = 1 and count(preceding::para) &gt; 5">
        <INSERTED_NODE/>
    </xsl:if>
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

测试输入A

<chapter>
  <title>Section Title 1</title>
  <para>Para 1</para>
  <para>Para 2</para>
  <para>Para 3</para>
  <section>
    <title>Section Title 2</title>
    <para>Para 4</para>
    <para>Para 5</para>
  </section>
  <para>Para 6</para>
  <section>
    <title>Section Title 3</title>
    <para>Para 7</para>
    <para>Para 8</para>
  </section>
  <para>Para 9</para>
  <para>Para 10</para>
</chapter>

结果A

<?xml version="1.0" encoding="UTF-8"?>
<chapter>
   <title>Section Title 1</title>
   <para>Para 1</para>
   <para>Para 2</para>
   <para>Para 3</para>
   <section>
      <title>Section Title 2</title>
      <para>Para 4</para>
      <para>Para 5</para>
   </section>
   <para>Para 6</para>
   <section>
      <title>Section Title 3</title>
      <para>Para 7</para>
      <para>Para 8</para>
   </section>
   <INSERTED_NODE/>
   <para>Para 9</para>
   <para>Para 10</para>
</chapter>

测试输入B

<chapter>
  <title>Section Title 1</title>
  <para>Para 1</para>
  <para>Para 2</para>
  <para>Para 3</para>
  <section>
    <title>Section Title 2</title>
    <para>Para 4</para>
    <para>Para 5</para>
  </section>
  <para>Para 6</para>
  <section>
    <title>Section Title 3</title>
    <para>Para 7</para>
    <para>Para 8</para>
  </section>
  <para>Para 9</para>
</chapter>

结果B

<?xml version="1.0" encoding="UTF-8"?>
<chapter>
   <title>Section Title 1</title>
   <para>Para 1</para>
   <para>Para 2</para>
   <para>Para 3</para>
   <section>
      <title>Section Title 2</title>
      <para>Para 4</para>
      <para>Para 5</para>
   </section>
   <para>Para 6</para>
   <section>
      <title>Section Title 3</title>
      <para>Para 7</para>
      <INSERTED_NODE/>
      <para>Para 8</para>
   </section>
   <para>Para 9</para>
</chapter>

修改

  

有没有办法强制每章元素插入一次?

是的,你可以这样做:

<xsl:template match="para"> 
    <xsl:variable name="i">
        <xsl:number count="para" from="chapter" level="any"/>
    </xsl:variable>
    <xsl:variable name="n" select="count(ancestor::chapter//para)" />   
    <xsl:if test="$i + 1 = $n and $n &gt; 5">
        <INSERTED_NODE/>
    </xsl:if>
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

更有效的解决方案是在章级别进行一次计数,并将其作为参数传递给参数。