XSLT - 分析以下连续节点
XSLT - analyze following successive nodes
我有一个这样的xml,
<doc>
<para>texttext<page>1</page>texttext<page>1</page>texttext</para>
<para>texttext<page>1</page><page>2</page>texttext</para>
<para>texttext<page>1</page><page>2</page><page>3</page>texttext<page>4</page><page>5</page><page>6</page>texttext</para>
<para>texttext<page>1</page><page>2</page><page>3</page><page>4</page>texttext</para>
</doc>
我需要使用 xsl 转换将 <page>
个节点转换为 <link>
,并且需要考虑以下规则,
- 如果只有一个
<page>
节点出现(没有跟随任何页面节点)它只是转换为 <link>
- 如果连续放置两个
<page>
节点(上述示例中的场景 2)',' 必须在输出 <link>
节点之间添加
- 如果连续放置3个或更多
<page>
个节点(上面示例中的场景3和4),只需添加以'-'分隔的页面节点的第一个和最后一个内容
所以,输出应该是这样的,
<doc>
<para>texttext<link>1</link>texttext<link>1</link>texttext</para>
<para>texttext<link>1</link>,<link>2</link>texttext</para>
<para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para>
<para>texttext<link>1</link>-<link>4</link>texttext</para>
</doc>
我写了下面的 xsl 来完成这个任务,
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<link>
<xsl:apply-templates/>
</link>
</xsl:template>
<xsl:template match="page[following-sibling::node()[1][self::page]]">
<link>
<xsl:apply-templates/>
</link>
<xsl:text>,</xsl:text>
<link>
<xsl:apply-templates select="following-sibling::*[1]"/>
</link>
</xsl:template>
<xsl:template match="page[following-sibling::node()[1][self::page]][following-sibling::node()[2][self::page]]">
<link>
<xsl:apply-templates/>
</link>
<xsl:text>-</xsl:text>
<link>
<xsl:apply-templates select="following-sibling::*[2]"/>
</link>
</xsl:template>
但是这个方法并没有起作用,因为它在连续出现 3 个 <page>
节点时添加 ',',如果连续出现更多 <page>
个节点,则此方法效率不高。
任何人都可以在 xslt 中提出一个好的方法来分析以下兄弟姐妹形成 xslt 并完成此任务..
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page[not(preceding-sibling::node()[1][self::page])]">
<xsl:variable name="pages" select="following-sibling::page[
preceding-sibling::node()[1][self::page]
and generate-id(current()) = generate-id(preceding-sibling::page[
not(preceding-sibling::node()[1][self::page])
][1])
]" />
<xsl:apply-templates select="." mode="link" />
<xsl:if test="count($pages) = 1">,</xsl:if>
<xsl:if test="count($pages) > 1">-</xsl:if>
<xsl:apply-templates select="$pages[last()]" mode="link" />
</xsl:template>
<xsl:template match="page" />
<xsl:template match="page" mode="link">
<link>
<xsl:apply-templates select="@*|node()"/>
</link>
</xsl:template>
</xsl:transform>
结果
<doc>
<para>texttext<link>1</link>texttext<link>1</link>texttext</para>
<para>texttext<link>1</link>,<link>2</link>texttext</para>
<para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para>
<para>texttext<link>1</link>-<link>4</link>texttext</para>
</doc>
这里,
<xsl:template match="page[not(preceding-sibling::node()[1][self::page])]">
匹配以 "range" 个连续页面开头的任何 <page>
。
选择连续范围的剩余页面有点棘手,但可以这样做:
- 在所有以下同级页面中,select
- 本身紧跟
<page>
(即 "part of a range")和
- 最接近的前面
<page>
本身没有直接在另一个 <page>
前面(即 "the closest <page>
that starts a range")与当前节点相同.
鉴于我们只处理 <page>
个开始此模板范围的节点,这相当于 "is part of the current range".
用XPath术语来说,如上所示:
following-sibling::page[
preceding-sibling::node()[1][self::page]
and generate-id(current()) = generate-id(preceding-sibling::page[
not(preceding-sibling::node()[1][self::page])
][1])
]
我有一个这样的xml,
<doc>
<para>texttext<page>1</page>texttext<page>1</page>texttext</para>
<para>texttext<page>1</page><page>2</page>texttext</para>
<para>texttext<page>1</page><page>2</page><page>3</page>texttext<page>4</page><page>5</page><page>6</page>texttext</para>
<para>texttext<page>1</page><page>2</page><page>3</page><page>4</page>texttext</para>
</doc>
我需要使用 xsl 转换将 <page>
个节点转换为 <link>
,并且需要考虑以下规则,
- 如果只有一个
<page>
节点出现(没有跟随任何页面节点)它只是转换为<link>
- 如果连续放置两个
<page>
节点(上述示例中的场景 2)',' 必须在输出<link>
节点之间添加 - 如果连续放置3个或更多
<page>
个节点(上面示例中的场景3和4),只需添加以'-'分隔的页面节点的第一个和最后一个内容
所以,输出应该是这样的,
<doc>
<para>texttext<link>1</link>texttext<link>1</link>texttext</para>
<para>texttext<link>1</link>,<link>2</link>texttext</para>
<para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para>
<para>texttext<link>1</link>-<link>4</link>texttext</para>
</doc>
我写了下面的 xsl 来完成这个任务,
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<link>
<xsl:apply-templates/>
</link>
</xsl:template>
<xsl:template match="page[following-sibling::node()[1][self::page]]">
<link>
<xsl:apply-templates/>
</link>
<xsl:text>,</xsl:text>
<link>
<xsl:apply-templates select="following-sibling::*[1]"/>
</link>
</xsl:template>
<xsl:template match="page[following-sibling::node()[1][self::page]][following-sibling::node()[2][self::page]]">
<link>
<xsl:apply-templates/>
</link>
<xsl:text>-</xsl:text>
<link>
<xsl:apply-templates select="following-sibling::*[2]"/>
</link>
</xsl:template>
但是这个方法并没有起作用,因为它在连续出现 3 个 <page>
节点时添加 ',',如果连续出现更多 <page>
个节点,则此方法效率不高。
任何人都可以在 xslt 中提出一个好的方法来分析以下兄弟姐妹形成 xslt 并完成此任务..
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page[not(preceding-sibling::node()[1][self::page])]">
<xsl:variable name="pages" select="following-sibling::page[
preceding-sibling::node()[1][self::page]
and generate-id(current()) = generate-id(preceding-sibling::page[
not(preceding-sibling::node()[1][self::page])
][1])
]" />
<xsl:apply-templates select="." mode="link" />
<xsl:if test="count($pages) = 1">,</xsl:if>
<xsl:if test="count($pages) > 1">-</xsl:if>
<xsl:apply-templates select="$pages[last()]" mode="link" />
</xsl:template>
<xsl:template match="page" />
<xsl:template match="page" mode="link">
<link>
<xsl:apply-templates select="@*|node()"/>
</link>
</xsl:template>
</xsl:transform>
结果
<doc>
<para>texttext<link>1</link>texttext<link>1</link>texttext</para>
<para>texttext<link>1</link>,<link>2</link>texttext</para>
<para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para>
<para>texttext<link>1</link>-<link>4</link>texttext</para>
</doc>
这里,
<xsl:template match="page[not(preceding-sibling::node()[1][self::page])]">
匹配以 "range" 个连续页面开头的任何 <page>
。
选择连续范围的剩余页面有点棘手,但可以这样做:
- 在所有以下同级页面中,select
- 本身紧跟
<page>
(即 "part of a range")和 - 最接近的前面
<page>
本身没有直接在另一个<page>
前面(即 "the closest<page>
that starts a range")与当前节点相同.
- 本身紧跟
鉴于我们只处理 <page>
个开始此模板范围的节点,这相当于 "is part of the current range".
用XPath术语来说,如上所示:
following-sibling::page[
preceding-sibling::node()[1][self::page]
and generate-id(current()) = generate-id(preceding-sibling::page[
not(preceding-sibling::node()[1][self::page])
][1])
]