2011-01-07 4 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> 

내가

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

다음

에 Transform.xsl에 아래 라인을 변경 내 출력을 얻고 있지만 내가 원하는 SourceFile.xmlLookup.xml에 대한 XPath 노출을에 유지하려면그래서 좀 더 일반적인 스크립트를 작성할 수 있습니다. 다른 방법으로 동적 xpath를 수행 할 수 있습니까? 동일한 아이디어를 구현하기위한 아이디어 나 힌트는 매우 높이 평가 될 것입니다.

+1

초기의 거의 괴물 같은 질문을 간소화 했음에도 불구하고이 질문은 여전히 ​​너무 복잡하고 잘 정의되어 있지 않습니다. 그것을 강조하고 그것을 더 단순화 시키십시오 - 당신이 모든 세부 사항을 필요로하지 않는다고 확신합니다. 특히 두 개 이상의 파일로 작업해야만 모든 사람들이 그 질문을 이해하려고 애를 씁니다. 너무 복잡하다. 나는 이런 식으로 XSLT 앱을 디자인하지 않을 것이며, 나를 믿는다. 99 %의 개발자가 XSLT로 할 수 없다고 생각하는 정말 어려운 복잡성의 XSLT 앱이있다. –

+0

안녕하세요 Dimitre, 내가 원하는 건 외부 파일에서 xpath 값을 실행하는 것입니다. 이유는 내가 여러 개의 exeternal 파일을 가지고 나는 데이터를 가져 와서 그 데이터를 다시 메인 소스 파일에 삽입하려고한다. 여러 템플릿을 하드 코딩하여 할 수 있지만 그것을 피하고 다른 조인 또는 xpath 값을 기반으로 여러 파일에서 읽는 한 템플릿을 외부 파일의 설정으로 정의 할 싶습니다. – atif

+0

@ Nick-Jones의 대답은 정확합니다. XSLT/XPath 2.0에서는이 작업을 수행 할 수 없으며 다음 버전에서 제공 될 수도 있습니다. 그러나 나는 동적 인 XPath 평가의 필요성에 대해 매우 의문스러워합니다. 문제를 잘 설명하면 해결책이 될 수 있습니다. 왜 "XML 문서에 포함 된이 표현식을 평가할 수 있습니까?"라는 간단한 형태로 질문을 던지십시오. 순수 XSLT 솔루션이 가능하지는 않지만이 문제에 대해 적어도 아는 3 가지 "하이브리드"솔루션이 있습니다. –

답변

11

동적 XPath를 평가 순수한 XSLT에 불가능하다 1.0 2.0.

I. 사용 1.0 프로세서 dyn:evaluate()을 구현하는 EXSLT의 불행하게도 기능 dyn:evaluate()

, 거의 XSLT :

는 "하이브리드"솔루션에서이 작업을 수행하려면 적어도 세 가지 방법이 있습니다.

II. XSLT로 XML 문서를 처리하고 XPath 표현식을 포함하는 새 XSLT 파일을 생성 한 다음 새로 생성 된 변환을 실행합니다.

매우 소수의 사람들이 이것을하고 있으며 내 의견으로는 다음 해결책보다 복잡합니다.

3.

아이디어를 작동 the XPath Visualizer 방법은 다음과 같습니다

  1. 같이 정의 XSLT 스타일 시트에 전역 변수 유무 :

    <xsl:variable name="vExpression" select="dummy"/> 
    
  2. 그런
  3. , AS를 스타일 시트를로드 DOM을 사용하여 XML 문서를 만들고 vExpression 변수select 변수로 바꿉니다. 소스 XML. 서에 포함 된 XPath 표현식.

  4. 마지막으로 메모리에로드되고 동적으로 업데이트 된 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 표현식의 마지막 요소와 함께 와일드 카드를 사용하는 것입니다. "세 번째"대신 "1 차/2 차/제"의 사용

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

: 어쩌면 사람이, 특히 조상의 호출을 다음 코드를 단순화하는 아이디어가있다. 아마 당신은 당신의 특정 요구에 맞게 조정해야합니다.

+0

''을 사용하는 것이 좋은 생각입니다. 적어도 선택이 비교적 짧다면, 내 역 동성 문제를 몇 줄에서 해결할 수 있습니다. –