2013-09-05 97 views
3

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

<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]和狗[最后()]被适当标记,但它也捕获在 '的' 这个词中间由于字符串匹配或等于第一个。

编辑:
预期(期望)输出:
[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> 

电流输出

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

所需的输出 [USERS]产品ABCThis是关于产品ABC Blurb的。由于短语(ph)中的文本与标题(第一个文本节点)中的文本节点相匹配,因此将被标记。我只想要标记第一个和最后一个节点。基本上,我不想比较节点的内容。 [用户]我也需要支持这样的内联案例。 [/ USERS]我只想在每个观众匹配的第一个和最后一个文本节点之前和之后的标志。[/ USERS]

谢谢。

+0

才有可能为您展现您的输入XML的副本(理想情况下对应于您当前出一个)。另外,你能否展示你的预期产出,只是为了说清楚。谢谢! –

+0

来源是一个DITAMAP,最终成为一个20页的PDF。我们基本上是突出显示或标记审阅者的文本,以便他们可以检查我们的条件(他们不读取XML)。我会尝试创建一个工作样本进行审查。谢谢。 –

+0

完成!我希望这个例子很有帮助。我很欣赏任何建议。 –

回答

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和期望的输出,另一种可以采取的方法是使用一个模板来匹配具有'用户'类的任何元素,并简单地写出开始和结束[USER]标签,其中包括一个xsl :在中间应用模板以选择所有文本。

试试这个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> 
+0

我还没有机会尝试替代解决方案,但是您在主响应中已经发现了。非常感谢。我的大部分工作都是基于错误的假设,祖先:: * [last()]是最接近我的过滤器的元素。 –

1

原谅基本的问题,但我不明白为什么你只是不使用一个ditaval文件来突出文本时,@ audience设置为用户?您可以基本上为文字着色,以便您的评论者可以找到文本并进行验证。审查之后,您可以关闭突出显示。

也许我误解了你的意图。

+0

带PDF的DITAVAL与DITA OT配合使用。 参见:https://github.com/dita-ot/dita-ot/issues/1396和https://github.com/dita-ot/dita-ot/issues/1175 这被标记为回答...在编写许多自定义XSLT文件时,我仍然希望对原始问题提供一些帮助。 谢谢。 –