2011-01-07 9 views
2

xsltの動的xpath?私は、ファイルのセットをfollwingてい

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エクスプレッションをに維持するより一般的なスクリプトを書くことができます。動的なxpath以外の方法でこれを行うことはできますか?同じことを打ち明けるためのアイデアやヒントは非常に高く評価されます。

+1

最初のほぼ怪しい質問を簡略化したのは良い進歩ですが、この質問は依然として複雑すぎてよく定義されていません。それを言い換えて、それをさらに簡素化してみてください - 私はあなたがすべての詳細を必要としないと確信しています。特に、2つ以上のファイルを扱う必要があるため、誰もがその質問を理解しようとしてもあきらめてしまいます。あまりに複雑すぎる:私はこのようにXSLTアプリケーションを設計することは決してないだろうと私は信じている。開発者の99%がXSLTを使っていると信じられない複雑な複雑なXSLTアプリケーションがある。 –

+0

こんにちはDimitre、私が望むのは、外部ファイルからxpath値を実行することです。理由は、私は複数のexeternalファイルを持っているから、私はデータを取って元のソースファイルにそのデータを挿入したい。私は複数のテンプレートをハードコーディングすることでそれを行うことができますが、私はそれを避け、異なる結合やxpath値に基づいて複数のファイルから読み取る1つのテンプレートを外部ファイルの設定として定義します。 – atif

+0

@ Nick-Jonesの答えは正しいです:これはXSLT/XPath 2.0ではできません。次のバージョンで提供されるかもしれません。しかし、私は動的なXPath評価の必要性を非常に疑っています。問題をうまく記述すると解決できない場合があります。単純な形式で質問してみてください。「このXML文書に含まれているこの式をどのように評価するのですか?」純粋なXSLTソリューションは不可能ですが、私がこの問題を知っている少なくとも3つの異なる "ハイブリッド"ソリューションがあります。 –

答えて

11

ダイナミックXPath評価が純粋なXSLT 1.0は不可能ですか、 2.0。

"ハイブリッド" ソリューションでこれを行うには、少なくとも3つの方法があります。

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

1.0プロセッサがdyn:evaluate()を実装残念ながら、非常に少数のXSLTは。

II。 XSLTを使用してXMLドキュメントを処理し、XPath式を含む新しいXSLTファイルを生成してから、新しく生成された変換を実行します。

私の意見では、これは非常に少数の人が次の解決策より複雑です。

3。

アイデアを作品the XPath Visualizer方法は次のとおりです。としてスタイルシートをロードし、その後

<xsl:variable name="vExpression" select="dummy"/> 
    1. こののように定義されたXSLTスタイルシートでグローバル変数を持っていますDOMを使用してXML文書を作成し、vExpression変数の代わりにselect属性をacソースXML文書に含まれているXPath式を使用します。

    2. 最後に、ロードされたメモリと動的に更新されたxsltスタイルシートを使用して変換を開始します。

  • +0

    こんにちはDimitre、私はthridオプションを使用することができると思うが、これは自己それは少し複雑です。私は今、複数のテンプレートで作業しようとします。しかし、入力をありがとう。 – atif

    +0

    @atif:これはあまり複雑ではありません。XPathビジュアライザのソースコードをご覧になることをお勧めします。これはほんの数行のコードです。 –

    +0

    ここにアプローチ#1の例があります:http://stackoverflow.com/questions/230411/xslt-xalan-dynevaluate-example – Vadzim

    2

    はい、私たちは...少なくとも基本的には可能です。ここでは、「評価」機能が利用可能になるまでSaxon CE(XSLT 2.0)で使用する回避策を示します。たぶんこれは複雑なXML文書のすべての種類では機能しないかもしれませんが、必要に応じて "フィルタ"を調整することができます(属性などのクエリ)。

    私の特別な状況では、名前を含む要素への "フル"パスを記述するxPath式があります。トリックは、ダイナミックxPath式の最後の要素のみと組み合わせてワイルドカードを使用することです。 「第3」の代わりに「第1 /第2 /第3」の使用:

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

    を結果を制限するために(名前「第3」を持つすべての要素を選択することになる)あなたは、「最初の」祖先に照会しなければならないとします「秒」も。私の目的返される子ノードを持たない唯一の最初にマッチした要素については

    <!-- 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> 
    

    :たぶん、誰もが、特に、祖先の呼び出しを次のコードを簡素化するためのアイデアを持っています。おそらく、あなたの特定のニーズに合わせてこれを調整する必要があります。

    +0

    ''の使用は良い選択です。少なくとも選択肢が比較的短い場合は、私のダイナミズムの問題を数行で解決しました。 –

    関連する問題