2013-09-05 140 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文件時,我仍然希望對原始問題提供一些幫助。 謝謝。 –