2013-10-08 43 views
2

我有一個簡單的xml文本和一個小人物。我想找到文中提到的所有「人物」,並使用個人資料中的信息加以標記。 我的文字是這樣的:如何使用xslt使用外部xml數據自動編碼文本

<text> 
    <div> 
     <p>Mohandas Ghandi was an Indian lawyer, born in 1869.</p> 
     <p>Albert Einstein was a German physicist, born in 1879.</p> 
     <p>Helen Keller was an American author, born in 1880.</p> 
     <p>Joan Baez is an American singer/songwriter, born in 1941.</p> 
    </div> 
</text> 

和我personography看起來是這樣的:

<people> 
    <person id="ghandi"> 
     <name>Mohandas Ghandi</name> 
     <birthPlace>Porbandar, India</birthPlace> 
    </person> 
    <person id="einstein"> 
     <name>Albert Einstein</name> 
     <birthPlace>Ulm, Germany</birthPlace> 
    </person> 
    <person id="keller"> 
     <name>Helen Keller</name> 
     <birthPlace>Tuscumbia, USA</birthPlace> 
    </person> 
</people> 

到目前爲止,我有這個XSLT(2.0):

<xsl:variable name="personography" select="doc('people.xml')"/> 
<xsl:variable name="pName" select="$personography//person[1]/name"/> 
<xsl:variable name="pId" select="$personography//person[1]/@id"/> 

<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:apply-templates/> 
    </xsl:copy> 
</xsl:template>  

<xsl:template name="encNames" match="text()"> 
    <xsl:analyze-string select="." regex="{$pName}"> 
     <xsl:matching-substring> 
      <persName corresp="{concat('people.xml#',$pId)}"> 
       <xsl:value-of select="."/> 
      </persName> 
     </xsl:matching-substring> 
     <xsl:non-matching-substring> 
      <xsl:copy-of select="."/> 
     </xsl:non-matching-substring> 
    </xsl:analyze-string> 
</xsl:template> 

和我回到這裏:

<text> 
    <div> 
     <p><persName corresp="people.xml#ghandi">Mohandas Ghandi</persName> was an Indian lawyer, born in 1869.</p> 
     <p>Albert Einstein was a German physicist, born in 1879.</p> 
     <p>Helen Keller was an American author, born in 1880.</p> 
     <p>Joan Baez is an American singer/songwriter, born in 1941.</p> 
    </div> 
</text> 

所以,我的問題是,我如何在文字中標記其餘的人?我認爲它需要一個使用跟隨兄弟的功能,但我沒有得到更多的進一步的。我錯過了什麼?我至少在正確的軌道上? 謝謝。

回答

0

這是一個有點冗長,可能可以優化或重構,但工程。

該模板將迭代每個人並應用分析字符串。結果存儲在一個名爲$person-matches的變量中,每個人都有一個<match>

如果存在包含<persName>的匹配項,請使用該匹配項。否則,請使用模板中匹配的原始文本。

<xsl:template match="text()"> 
    <xsl:variable name="txt" select="."/> 

    <xsl:variable name="person-matches"> 
     <xsl:for-each select="$personography/person"> 
     <xsl:variable name="person" select="."/> 
      <match> 
      <xsl:analyze-string select="$txt" regex="({$person/name})"> 
       <xsl:matching-substring> 
        <persName corresp="{concat('people.xml#',$person/@id)}"> 
         <xsl:value-of select="regex-group(1)"/> 
        </persName> 
       </xsl:matching-substring> 
       <xsl:non-matching-substring> 
        <xsl:value-of select="."/> 
       </xsl:non-matching-substring> 
      </xsl:analyze-string> 
      </match> 
     </xsl:for-each> 
    </xsl:variable> 

    <xsl:choose> 
     <xsl:when test="$person-matches/match[persName]"> 
      <xsl:sequence select="$person-matches/match[persName]/node()"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:copy-of select="."/> 
     </xsl:otherwise> 
    </xsl:choose> 

</xsl:template> 
+0

感謝的Mads。我不得不做一些調整,但我得到了滿意的結果。由於表演的原因,我給了你勝利 - 在我的更大的「真實文本」上,這個成績幾乎是丹尼爾速度的兩倍。對不起,我無法註冊 - 我的時間不夠長。 – Greg

1

我會做的是改變pName返回一個名稱序列,而不是第一個人的名字。然後,我會使用該序列構造一個新的正則表達式。

例...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:preserve-space elements="p"/> 

    <xsl:variable name="personography" select="doc('people.xml')"/> 
    <xsl:variable name="pName" select="$personography/*/person/name"/> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="text()" priority="1"> 
     <xsl:analyze-string select="." regex="({string-join($pName,'|')})"> 
      <xsl:matching-substring> 
       <persName corresp="{concat('people.xml#',$personography/*/person[name=current()]/@id)}"> 
        <xsl:value-of select="."/> 
       </persName> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:copy-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

</xsl:stylesheet> 
+0

感謝Daniel的優雅解決方案。我沒有選擇它的唯一原因是因爲表現(請參閱對Mads的評論)。儘管它在我提供的小樣本上完美工作,但在處理更大的集合時,字符串連接確實會消耗內存。 – Greg

+0

@Greg - 性能是選擇其他解決方案的一個很好的理由。我很驚訝,字符串連接是瓶頸。是一個更大的「人物」,輸入XML還是兩者? –

+0

說實話,我不知道**字符串連接是一個瓶頸。你的解決方案需要約38秒。而馬茲的解決方案花了21秒。 (我使用Saxon-PE 9.5在oXygen中運行它)。 輸入XML文件約爲3MB,個人中約有300人 - 最終這需要擴展到大約2000人。 雖然我真的很喜歡你的解決方案 - 它簡短而優雅,而對於較小的任務,完成時間的差異是無關緊要的。 再次感謝! – Greg