如何计算忽略它们是 children 还是兄弟姐妹的元素?

How to count elements ignoring whether they are children or siblings?

这可能是一个新手问题,但话说回来,我是新手:-)

旧情况:

我有 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>

这里的逻辑是:如果前面有足够多的 兄弟姐妹,"Insert Some Stuff" 在 second-to-last 元素之前。

这段代码完成了工作并且工作正常。


新情况

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

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

这些文件的区别在于

元素可以随机出现,有时包含 元素,有时不包含。无法预测
元素何时何地出现。

尽管存在

元素,但我需要原始 XSL 模板以相同的方式处理此格式。所以这意味着 元素仍然需要以相同的方式计算,即使它们有时是 children 有时是兄弟姐妹。

总而言之,我需要旧代码的逻辑像以前一样工作,就好像它完全忽略了

元素的存在。

原始模板 应该重写什么才能使这个工作正常?

性能不是问题 - 这些是 manually-run ad-hoc 转换。

仅限 XSLT 1.0,请

谢谢。

如果没有看到完整的样式表和预期的 output/s,很难回答您的问题。

不会:

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

为你工作?


已添加:

If you're sure that what you've suggested should work for the example given in the question

好吧,问题中给出的示例没有所需的最小 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>

编辑

Is there a way to force it to be inserted once per chapter element?

是的,你可以这样做:

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

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