【问题标题】:Using xsl:accumulator to keep track of text nodes between two PIs使用 xsl:accumulator 跟踪两个 PI 之间的文本节点
【发布时间】: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都相关,成为标记,需要消除。最初的&lt;marker&gt;Base text&lt;/marker&gt; 来自哪里,最终的&lt;marker&gt;Base text&lt;/marker&gt; 在所需的输出中是哪里来的?
  • 在新累加器的计算中使用$value获得当前值
  • “基本文本”是默认状态,即范围内没有修改时。修改有一个开始 PI 和一个结束 PI。
  • 您的第二条评论解决了我的问题:我没有在任何地方找到 $value 参数,但这正是我需要让它全部工作的。使用文本累加器,我发现在最后一个关闭 PI 和当前打开 PI 之间是否有任何文本节点。如果没有可见文本并且 PI 用于相同的修改,我可以将两个范围合并为一个。感谢您快速而有用的回复。
  • 但是您有多个&lt;?MyPI Start Modification 1?&gt;,即具有相同的编号。这有关系吗?或者你只是在处理例如的两个兄弟姐妹。 &lt;?MyPI Start Modification n?&gt;&lt;?MyPI End Modification n?&gt;?

标签: xslt xslt-3.0 accumulator


【解决方案1】:

也许

<xsl:accumulator name="text" initial-value="()" as="xs:string?">
    <xsl:accumulator-rule match="processing-instruction('MyPI')" select="''"/>
    <xsl:accumulator-rule match="text()[normalize-space()]" select="$value || ."/>
</xsl:accumulator>

给你一个关于如何设置累加器来收集文本节点值的例子,我不确定我是否理解将累加器重置为空字符串的条件,所以这基本上是你的样本中的匹配,只是转录在(希望)可编译的 XSLT 3 中,如果有更多与开始或结束处理指令对或名称相关的条件,您可以进行调整。

关于解释$value 变量的规范,请参阅https://www.w3.org/TR/xslt-30/#accumulator-declaration

select 属性和包含的序列构造函数 xsl:accumulator-rule 元素是互斥的:如果选择 属性存在,则序列构造函数必须为空。这 xsl:accumulator-rule 的 select 属性中的表达式或 包含的序列构造函数使用静态上下文进行评估,该上下文 遵循样式表中表达式的一般规则,除了:

上下文中存在一个附加变量。这个名字 变量是value(在没有命名空间),它的类型是 出现在 xsl:accumulator 声明的 as 属性中。

用于评估表达式或序列的上下文项 构造函数将始终是与模式匹配的节点 匹配属性。

https://www.w3.org/TR/xslt-30/#accumulator-examples 中的两个示例也使用了$value

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    相关资源
    最近更新 更多