【发布时间】:2021-07-09 12:13:02
【问题描述】:
我正在学习 XSLT 3.0 中的累加器,但我没有找到任何可以帮助我解决当前问题的示例。我有大文件,其中处理指令用于标记修改。我需要将这些处理成可见的标记以供审查过程。使用累加器,我成功地跟踪了要显示的最新修改代码。到目前为止,一切顺利。
由于原始文件很大,我创建了一个简单的示例输入 XML,它显示了我的任务的本质,我调整了我的 XSL 以显示我正在尝试使用累加器。
简单的输入文件:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div>
<p>Paragraph 1</p>
<?MyPI Start Modification 1?>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<?MyPI End Modification 1?>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<?MyPI Start Modification 1?>
<p>Paragraph 5</p>
<?MyPI End Modification 1?>
</item>
<item>
<?MyPI Start Modification 1?>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<?MyPI End Modification 1?>
<?MyPI Start Modification 2?>
<p>Paragraph 8</p>
<?MyPI End Modification 2?>
</item>
</list>
<p>Paragraph 9</p>
</div>
</root>
我的 XSL 使用累加器进行当前修改:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:mode use-accumulators="#all"/>
<xsl:accumulator name="modifier" initial-value="'Base text'">
<xsl:accumulator-rule match="processing-instruction('MyPI')[contains(.,'Modification')]">
<xsl:choose>
<xsl:when test="contains(.,'Start')">
<xsl:value-of select="substring-after(.,'Start ')"/>
</xsl:when>
<xsl:otherwise>Base text</xsl:otherwise>
</xsl:choose>
</xsl:accumulator-rule>
</xsl:accumulator>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="processing-instruction('MyPI')">
<marker>
<xsl:value-of select="accumulator-after('modifier')"/>
</marker>
</xsl:template>
</xsl:stylesheet>
使用此 XSL 的输出:
<?xml version="1.0" encoding="UTF-8"?><root>
<div>
<p>Paragraph 1</p>
<marker>Modification 1</marker>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<marker>Base text</marker>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<marker>Modification 1</marker>
<p>Paragraph 5</p>
<marker>Base text</marker>
</item>
<item>
<marker>Modification 1</marker>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<marker>Base text</marker>
<marker>Modification 2</marker>
<p>Paragraph 8</p>
<marker>Base text</marker>
</item>
</list>
<p>Paragraph 9</p>
</div>
</root>
我遇到的问题是,当它们之间没有文本时,应该隐藏相同修改代码的关闭和打开标记。它们可能会立即相互跟随(这很简单),但它们之间也有一些非文本元素边界。我试图创建一个累加器来跟踪自上次修改标记以来的所有文本,但这会导致对同一累加器的嵌套调用,从而产生运行时错误。我正在寻找的是一种方法,该方法不断将文本添加到累加器,并在找到修改 PI 时将其重置为空字符串。这是我的试用累加器,导致嵌套调用过多:
<xsl:accumulator name="text" initial-value="''">
<xsl:accumulator-rule match="node()">
<xsl:choose>
<xsl:when test="self::processing-instruction('MyPI')"/>
<xsl:when test="self::text()">
<xsl:value-of select="concat(accumulator-after('text'),.)"/>
</xsl:when>
</xsl:choose>
</xsl:accumulator-rule>
</xsl:accumulator>
我想我还不明白累加器是如何工作的,这使得我很难得到我想要的结果。
上述简单 XML 所需的输出:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div>
<marker>Base text</marker>
<p>Paragraph 1</p>
<marker>Modification 1</marker>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<marker>Base text</marker>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<marker>Modification 1</marker>
<p>Paragraph 5</p>
</item>
<item>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<marker>Mpdification 2</marker>
<p>Paragraph 8</p>
</item>
</list>
<marker>Base text</marker>
<p>Paragraph 9</p>
</div>
</root>
希望有人能指出我正确的方向。我猜想积累文本节点,因为 XML 处理中的特定节点将是更多人需要解决的问题。在我目前的情况下,我不需要实际的文本内容,我只需要知道自上次 PI 以来是否有任何可见文本(即,我需要删除或忽略此检查中的任何空白)。
如果有其他方法不涉及累加器,那也可以。
提前感谢您的帮助
【问题讨论】:
-
我没弄明白,无论是从描述还是从代码,PI都相关,成为标记,需要消除。最初的
<marker>Base text</marker>来自哪里,最终的<marker>Base text</marker>在所需的输出中是哪里来的? -
在新累加器的计算中使用
$value获得当前值 -
“基本文本”是默认状态,即范围内没有修改时。修改有一个开始 PI 和一个结束 PI。
-
您的第二条评论解决了我的问题:我没有在任何地方找到 $value 参数,但这正是我需要让它全部工作的。使用文本累加器,我发现在最后一个关闭 PI 和当前打开 PI 之间是否有任何文本节点。如果没有可见文本并且 PI 用于相同的修改,我可以将两个范围合并为一个。感谢您快速而有用的回复。
-
但是您有多个
<?MyPI Start Modification 1?>,即具有相同的编号。这有关系吗?或者你只是在处理例如的两个兄弟姐妹。<?MyPI Start Modification n?>和<?MyPI End Modification n?>?
标签: xslt xslt-3.0 accumulator