2011-01-07 54 views
2

我已經follwing文件集:xslt中的動態xpath?

SourceFile.xml:

 <?xml version="1.0" encoding="utf-8" ?> 
    <Employees> 
    <Employee id="1"> 
      <firstname relationship="headnote">Atif</firstname> 
      <lastname relationship="lname">Bashir</lastname> 
      <age relationship="age">32</age> 
      </Employee> 
    </Employees> 

ParamerterSettings.xml

 <?xml version="1.0" encoding="utf-8"?> 
     <Settings> 
     <Employee id="1"> 
      <sourceFile>Lookup1.xml</sourceFile> 
      <sourceXpathfield>Employees/Employee[@id</sourceXpathfield> 
      <lookupXpathfield>Employees/Employee[@id='1']</lookupXpathfield> 
      <elementstoinsert>xyz</elementstoinsert> 
      </Employee> 
     </Settings> 

Lookup.xml

<?xml version="1.0" encoding="utf-8"?> 
<Employees> 
    <Employee id="1"> 
     <department code="102">HR</department> 
    </Employee> 
    </Employees> 

transform.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="2.0"> 

    <xsl:include href="identity.xsl"/> 

    <xsl:param name="EmployeeId" select="'1,2'" /> 
    <xsl:variable name="FileSettings" select="document('test3.xml')" /> 
    <xsl:variable name="SuppressSetting" select="$FileSettings/Settings/Employee[@id = tokenize($EmployeeId, ',')]" /> 

    <xsl:template match="Employee"> 
    <xsl:copy> 
    <xsl:apply-templates select="@*"/> 
    <xsl:apply-templates select="publisher" /> 
    <xsl:apply-templates select="node() except publisher"/> 
    <xsl:variable name="outerfile" select="document($SuppressSetting/sourceFile)"></xsl:variable> 
    <xsl:variable name="outerfiledetails" select="$outerfile/$SuppressSetting/lookupXpathfield"></xsl:variable> 
    <xsl:value-of select="$outerfiledetails"></xsl:value-of> 
</xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

輸出應該是:

 <?xml version="1.0" encoding="utf-8" ?> 
    <Employees> 
    <Employee id="1"> 
      <firstname relationship="headnote">Atif</firstname> 
      <lastname relationship="lname">Bashir</lastname> 
      <age relationship="age">32</age> 
      HR 
      </Employee> 
    </Employees> 

我改變了下面的線Transform.xsl

<xsl:variable name="outerfiledetails" select="$outerfile/$SuppressSetting/lookupXpathfield"></xsl:variable> 

然後我得到我的輸出,但我想將SourceFile.xmlLookup.xml的XPath表達式保留爲ParamerterSettings.xml,以便我可以編寫更通用的腳本。這可以通過任何其他方式完成,然後動態xpath?任何想法或暗示推動相同將高度讚賞。

+1

這是你已經簡化您最初的幾乎可怕的問題了良好的進展,但這個問題仍然過於複雜和不明確。嘗試改變它並進一步簡化它 - 我相信你不需要所有的細節。尤其是,如果要處理兩個以上的文件,每個人都會放棄嘗試理解問題。太複雜了:我永遠不會用這種方式設計XSLT應用程序,並相信我,我有XSLT應用程序的複雜性非常具有挑戰性,99%的開發人員不相信XSLT可能會這樣做。 – 2011-01-07 20:58:20

+0

嗨Dimitre,我想要的是從外部文件執行xpath值。原因是我有多個exeternal文件,我想從中獲取數據並將該數據插回到主源文件中。我可以通過對多個模板進行硬編碼來實現,但我想避免這種情況,並根據不同的連接或xpath值將多個文件中的一個模板定義爲外部文件中的設置。 – atif 2011-01-08 02:26:49

+0

@ Nick-Jones的答案是正確的:這不能在XSLT/XPath 2.0中完成,它可能由下一個版本提供。但是,我非常懷疑動態XPath評估的必要性 - 如果您很好地描述了您的問題,那麼可能有一個解決方案不需要這樣做。爲什麼不直接以最簡單的形式提出問題:「我如何評估此XML文檔中包含的這個表達式?」。雖然純粹的XSLT解決方案是不可能的,但至少有三種不同的「混合」解決方案,我知道這個問題。 – 2011-01-10 14:18:30

回答

11

動態XPath計算純XSLT是不可能的1.0 2.0。

至少有三個方面的 「混合」 解決方案做到這一點:

I.使用EXSLT功能dyn:evaluate()

遺憾的是,很少有XSLT 1.0處理器實現dyn:evaluate()

二,使用XSLT處理XML文檔並生成包含XPath表達式的新XSLT文件 - 然後執行新生成的轉換

很少有人這樣做,在我看來,這比下一個解決方案更復雜。

三,the XPath Visualizer工作

的想法的方式是:

  1. 有這樣定義XSLT樣式表中的全局變量:

    <xsl:variable name="vExpression" select="dummy"/> 
    
  2. 然後,裝入樣式表作爲使用DOM的XML文檔,並與AC替換vExpression變量的select屬性包含在源XML文檔中的tual XPath表達式。

  3. 最後,啓動轉換使用加載到內存和動態更新xslt樣式表。

2

是的,我們可以...至少rudimentarily。這是一個解決方案,我使用Saxon CE(XSLT 2.0),直到「評估」功能可用。也許這不適用於各種複雜的XML文檔,但可能可以根據需要調整「過濾器」(查詢屬性等)。

在我的特殊情況下,我有一個描述爲「滿」的路徑元素,包括他們的姓名,唯一的辦法是結合使用通配符只有動態XPath表達式的最後一個元素,例如XPath表達式使用「第三」,而不是「第一/二/三」:

<xsl:variable name="value" select="//*[name() = 'third']" /> 

爲了限制的結果(會選擇名稱爲「第三」的所有元素),你將不得不對祖先「第一」查詢和「第二」也是。也許任何人有一個想法,以簡化下面的代碼,特別是祖先的呼喚:

<!-- global variable which holds a XML document with root node "data" --> 
<xsl:variable name="record" select="document('record.xml')/data"/> 

<!-- select elements from the global "record" variable using dynamic xpath expressions --> 
<xsl:function name="utils:evaluateXPath"> 

    <xsl:param name="xpath" as="xs:string"/> 

    <xsl:choose> 

     <xsl:when test="function-available('evaluate')"> 

      <!-- modify the code if the function has been implemented :-) --> 
      <xsl:value-of select="'function evaluate() can be used ...'"/> 

     </xsl:when> 

     <xsl:otherwise> 

      <!-- get a list of elements defined in the xpath expression --> 
      <xsl:variable name="sequence" select="tokenize($xpath, '/')" /> 

      <!-- get the number of ancestors for the last element --> 
      <xsl:variable name="iAncestors" select="count($sequence)-1" as="xs:integer" /> 

      <!-- get the last element from the xpath expression --> 
      <xsl:variable name="lastElement" select="if ($iAncestors > 0) then $sequence[last()] else $xpath" /> 

      <!-- try to find the desired element as defined in xpath expression --> 
      <!-- use parenthesis to grab only the first occurrence --> 
      <xsl:value-of select=" 
       if ($iAncestors = 0) then 
        ($record//*[name() = $lastElement and not(*)])[1] 
       else if ($iAncestors = 1) then 
        ($record//*[name() = $lastElement and not(*) and (name(..) = $sequence[1])])[1] 
       else if ($iAncestors = 2) then 
        ($record//*[name() = $lastElement and not(*) and (name(..) = $sequence[2]) and (name(../..) = $sequence[1])])[1] 
       else if ($iAncestors = 3) then 
        ($record//*[name() = $lastElement and not(*) and (name(..) = $sequence[3]) and (name(../..) = $sequence[2]) and (name(../../..) = $sequence[1])])[1] 
       else if ($iAncestors = 4) then 
        ($record//*[name() = $lastElement and not(*) and (name(..) = $sequence[4]) and (name(../..) = $sequence[3]) and (name(../../..) = $sequence[2]) and (name(../../../..) = $sequence[1])])[1] 
       else if ($iAncestors = 5) then 
        ($record//*[name() = $lastElement and not(*) and (name(..) = $sequence[5]) and (name(../..) = $sequence[4]) and (name(../../..) = $sequence[3]) and (name(../../../..) = $sequence[2]) and (name(../../../../..) = $sequence[1])])[1] 
       else 'failure: too much elements for evaluating dyn. xpath ... add another level!'" 
      /> 

     </xsl:otherwise> 

    </xsl:choose> 

</xsl:function> 

至於我的目的只是其中有沒有返回子節點的第一個匹配的元素。可能你必須根據你的具體需求來調整它。