如何计算忽略它们是 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) > 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) > 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) > 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 > 5">
<INSERTED_NODE/>
</xsl:if>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
一个更有效的解决方案是在章节级别进行一次计数,并将其作为参数传递给段落。
这可能是一个新手问题,但话说回来,我是新手:-)
旧情况:
我有 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) > 13">
<!-- Insert Some Stuff -->
</xsl:if>
</xsl:template>
这里的逻辑是:如果前面有足够多的
这段代码完成了工作并且工作正常。
新情况
现在,由于我无法控制的原因,我需要调整该模板以处理以下类型的文件...
<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>
这些文件的区别在于
尽管存在
总而言之,我需要旧代码的逻辑像以前一样工作,就好像它完全忽略了
原始模板
性能不是问题 - 这些是 manually-run ad-hoc 转换。
仅限 XSLT 1.0,请
谢谢。
如果没有看到完整的样式表和预期的 output/s,很难回答您的问题。
不会:
<xsl:template match="para">
<xsl:if test="count(following::para) = 1 and count(preceding::para) > 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) > 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 > 5">
<INSERTED_NODE/>
</xsl:if>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
一个更有效的解决方案是在章节级别进行一次计数,并将其作为参数传递给段落。