3

以下 XSLT 片段用于使用给定的 @audience 属性包装/标记第一个和最后一个文本节点以进行突出显示。

<xsl:template match="text()">
    <xsl:if test=". = ((((ancestor::*[contains(@audience,'FLAG_')])[last()])/descendant::text())[1])">                  
        <xsl:call-template name="flagText"/>            
    </xsl:if>
    <xsl-value-of select="."/>
    <xsl:if test=". = ((((ancestor::*[contains(@audience,'FLAG_')])[last()])/descendant::text())[last()])">                 
        <xsl:call-template name="flagText"/>            
    </xsl:if>
</xsl:template>

伪代码
找到与标志条件匹配的最后一个(最近的)祖先元素,然后找到作为该元素后代的第一个和最后一个文本节点并对其进行标志。

逻辑是正确的,但实现是错误的。这确实找到了第一个和最后一个文本节点,但它匹配的是值而不是节点。这是标记与第一个或最后一个节点具有相同值的任何文本节点。

示例
The quick brown fox jumped over the lazy dog.

电流输出:
[FLAG]The quick brown fox jumped over [FLAG]the lazy dog[FLAG].

[1] 和 dog [last()] 已正确标记,但由于字符串匹配或等于第一个,它也在中间捕获了单词“the”。

编辑:
预期(期望)输出:
[FLAG]The quick brown fox jumped over the lazy dog.[FLAG]

如何重新组织我的语句以仅匹配第一个和最后一个节点?我不想比较我只想选择第一个和最后一个的字符串。

编辑:

示例源 XML

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept audience="Users" id="concept_lsy_5vg_kl"><title>Product ABC</title><conbody><p>This is a blurb about <ph>Product ABC</ph>. Since the text in the phrase (ph) matches the text node in the title (first text node) it will be flagged. I only want the first and last nodes flagged. Basically, I don't want to compare the contents of the nodes. <ph audience="Users">I also need to support inline cases such as this one. </ph>I just want the flags before and after the first and last text nodes for each audience match.</p></conbody></concept>

示例 XSLT

<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" >

    <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="text()">
        <xsl:if test=". = ((((ancestor::*[contains(@audience,'Users')])[last()])/descendant::text())[1])">          
            <xsl:text>[USERS]</xsl:text>            
        </xsl:if>
        <xsl:value-of select="."/>
        <xsl:if test=". = ((((ancestor::*[contains(@audience,'Users')])[last()])/descendant::text())[last()])">         
            <xsl:text>[/USERS]</xsl:text>           
        </xsl:if>
    </xsl:template> 



</xsl:stylesheet>

电流输出

[USERS]Product ABC这是关于[USERS]Product ABC的简介。由于短语 (ph) 中的文本与标题中的文本节点(第一个文本节点)匹配,它将被标记。我只想标记第一个和最后一个节点。基本上,我不想比较节点的内容。[USERS]我还需要支持这样的内联案例。[/USERS]我只想要每个观众匹配的第一个和最后一个文本节点之前和之后的标志。[/USERS]

期望的输出 [USERS]Product ABC 这是关于 Product ABC 的简介。由于短语 (ph) 中的文本与标题中的文本节点(第一个文本节点)匹配,它将被标记。我只想标记第一个和最后一个节点。基本上,我不想比较节点的内容。[USERS]我还需要支持这样的内联案例。[/USERS]我只想要每个观众匹配的第一个和最后一个文本节点之前和之后的标志。[/USERS]

谢谢。

4

2 回答 2

1

请原谅基本问题,但我不明白为什么当@audience 设置为用户时,您不使用 ditaval 文件突出显示文本?您基本上可以为文本着色,以便您的审阅者可以找到文本并进行验证。审核后,您可以关闭突出显示。

也许我误解了你的意图。

于 2013-09-06T02:30:12.097 回答
1

在您的表达式中,您将获得类名为“用户”的“最后一个”祖先,用于您所在的文本节点

...(ancestor::*[contains(@audience,'FLAG_')])[last()])...

但是你真的很想在这里拿到第一个。也就是说,最直接的祖先。祖先列表将从父节点开始,然后是祖父节点,等等......

...(ancestor::*[contains(@audience,'FLAG_')])[1])...

此外,您说您不想比较字符串,只需找出文本节点是第一个还是最后一个,但您当前的比较是检查字符串。因此,如果您有两个具有相同文本的文本节点(其中一个是第一个),那么您将获得一个流氓“[USER]”标签。要测试两个节点是否是同一个节点(而不是仅仅具有相同的内容),您可以使用 generate-id 函数。

generate-id() = generate-id(((ancestor::*[contains(@audience,'Users')][1])/descendant::text())[1])

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" >
  <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="text()">
    <xsl:if test="generate-id() = generate-id(((ancestor::*[contains(@audience,'Users')][1])/descendant::text())[1])">
      <xsl:text>[USERS]</xsl:text>
    </xsl:if>
    <xsl:value-of select="."/>
    <xsl:if test="generate-id() = generate-id(((ancestor::*[contains(@audience,'Users')][1])/descendant::text())[last()])">
      <xsl:text>[/USERS]</xsl:text>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

但是......也许你可以采取另一种方法。纯粹看您的 XML 和预期的输出,可以采取的另一种方法是使用一个模板来匹配任何具有“用户”类的元素,并使用xsl在其中简单地写出开始和结束 [USER] 标记:在两者之间应用模板以选择所有文本。

试试这个 XSLT 作为替代方案:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" >
  <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="*[contains(@audience,'Users')]">
    <xsl:text>[USERS]</xsl:text>
      <xsl:apply-templates />
    <xsl:text>[/USERS]</xsl:text>
  </xsl:template>
</xsl:stylesheet>
于 2013-09-06T07:27:07.650 回答