2013-06-04 1 views
1

현재 XML 파일을 특정 요소를 가져 와서 선택된 요소의 조상을 따라 이동하여 여러 출력 XML 파일로 변환하려고합니다.XSLT 2.0 : foreach를 사용하지 않고 모든 조상을 포함하는 요소 변환

예를 들어

:

소스 XML :

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <level_a> 
    <level_b> 
     <level_c> 
     <level_d> 
      <level_e/> 
     </level_d> 
     </level_c> 
    </level_b> 
    <level_b> 
     <level_c> 
     <level_d> 
      <level_e/> 
     </level_d> 
     </level_c> 
    </level_b> 
    <level_b> 
     <level_c> 
     <level_d> 
      <level_e/> 
      <level_e/> 
      <level_e/> 
     </level_d> 
     </level_c> 
    </level_b> 
    <level_b> 
     <level_c> 
     <level_d> 
      <level_d> 
      <level_e/> 
      </level_d> 
     </level_d> 
     </level_c> 
    </level_b> 
    </level_a> 
</root> 

출력 XML 파일 :

1 :

<output> 
     <output level="b"> 
      <output level="c"> 
      <output level="d"> 
       <output level="e"/> 
      </output> 
      </output> 
     </output> 
</output> 

2 :

<output> 
     <output level="b"> 
      <output level="c"> 
      <output level="d"> 
       <output level="e"/> 
      </output> 
      </output> 
     </output> 
</output> 

3 :

<output> 
     <output level="b"> 
      <output level="c"> 
      <output level="d"> 
       <output level="e"/> 
       <output level="e"/> 
       <output level="e"/> 
      </output> 
      </output> 
     </output> 
</output> 

4 :

<output> 
     <output level="b"> 
     <output level="c"> 
      <output level="d"> 
      <output level="d"> 
       <output level="e"/> 
      </output> 
      </output> 
     </output> 
     </output> 
</output> 

가 나는 다음의 XPath와 시퀀스를 생성하는 라인에 뭔가를 할 수 알고 :

(// level_d [하지 (level_d) ]) [last()]/ancestor :: * [self :: level_c | self :: level_b]

그리고 foreach를 사용하여 반복합니다. 결과가 문서 순서대로 표시됩니다. 하지만 난 정말 관심이 무엇인지, foreach는의 사용에 의지하지 않고 동일한을 달성하는 방법은, 어떤 솔루션은 내가 모든 요소가 반전 반환 생각할 수

...

어떤 힌트는 크게이다 감사

안부
Vlax

+0

'/ */*'와 일치하고 거기에서 결과 문서를 만들 수 없습니까? –

+1

질문을 정교하게 (또는 다른 질문을)해야 할 수도 있습니다. Daniel Haley의 접근 방식이 문제를 해결하지 못하는 이유는이 질문에서 분명하지 않습니다. 당신은 질문을 제기하는 관계없는 세부 사항을 단순화하기위한 포인트를 얻지 만 아인슈타인의 충고를 기억하십시오 : 가능한 한 간단하지만 간단한 것은 아닙니다! –

+0

이제는 단순화 된 예제를 변경했습니다. 실제 버전에는 실제 실제 XML 소스가 반영되어야합니다. 실제로 xml에는 루트 요소 다음에 2 개의 요소가있을 필요가 없습니다. 모든 요소는 하나의 숫자 또는 하나만 가질 수 있습니다. 내가 가진 유일한 확실성은 level_d 요소가 있고 특정 요소 (예 : xml의 element_a)까지 모든 조상 트리가있는 xml 파일을 출력하기 위해 추출되어야한다는 것입니다. – Vlax

답변

0

로 (이름 때문에 generate-id()을 다른 것) 변수 솔루션 인 경우 다음 값을 조정할 수 있습니다. level_a 또는 level_d가 변경됩니다.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="//level_d[not(ancestor::level_d)]"> 
      <xsl:result-document href="{concat('file_', count(preceding::*[self::level_d])+1,'.xml')}"> 
       <output> 
        <xsl:apply-templates select="ancestor-or-self::node()[parent::level_a]" mode="output"></xsl:apply-templates> 
       </output> 
      </xsl:result-document> 
    </xsl:template> 

    <xsl:template match="*" mode="output"> 
     <output level="{substring-after(local-name(),'level_')}"> 
      <xsl:apply-templates mode="output"/> 
     </output> 
    </xsl:template> 
</xsl:stylesheet> 

예상되는 결과와 같습니다.

+0

감사! 이것은 정확히 내가 찾고 있었던 것입니다. 항상 잘못된 것은 아닙니다 :) – Vlax

+0

사실 "// level_d [not (ancestor :: level_d)]"대신 "level_d [ancestor :: level_d]"라고 쓸 수 있습니다. – Vlax

3

당신이 위에서 아래로 대신 바닥을 가서 왜 확실하지. 내가 /*/*과 일치하고 거기에 결과 문서를 만듭니다.

예 ...

XML 입력

<root> 
    <level_a> 
     <level_b> 
      <level_c> 
       <level_d> 
        <level_e/> 
       </level_d> 
      </level_c> 
     </level_b> 
    </level_a> 
    <level_b> 
     <level_c> 
      <level_d> 
       <level_d> 
        <level_e/> 
       </level_d> 
      </level_d> 
     </level_c> 
    </level_b> 
</root> 

XSLT 2.0

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

    <xsl:template name="output"> 
     <output level="{substring-after(name(),'level_')}"> 
      <xsl:apply-templates/> 
     </output>  
    </xsl:template> 

    <xsl:template match="/*/*" priority="1"> 
     <xsl:result-document href="{generate-id()}.xml"> 
      <output> 
       <xsl:call-template name="output"/>    
      </output> 
     </xsl:result-document> 
    </xsl:template> 

    <xsl:template match="*[starts-with(name(),'level_')]"> 
     <xsl:call-template name="output"/> 
    </xsl:template> 

</xsl:stylesheet> 

파일 1 (이름 때문에 generate-id()의 다른 것)

<output> 
    <output level="a"> 
     <output level="b"> 
     <output level="c"> 
      <output level="d"> 
       <output level="e"/> 
      </output> 
     </output> 
     </output> 
    </output> 
</output> 

파일 2

<output> 
    <output level="b"> 
     <output level="c"> 
     <output level="d"> 
      <output level="d"> 
       <output level="e"/> 
      </output> 
     </output> 
     </output> 
    </output> 
</output> 
+0

답변 해 주셔서 감사합니다.하지만 제가 예를 지나치게 간소화했을 수 있습니다. 실제 "xml"이 훨씬 더 복잡하기 때문에 실제로 "level_d"에서 시작해야합니다. 원한다면 좀 더 실제적인 예를 재현 해 볼 수 있습니다. 근본적으로 조상 : : * 또는 부모 : : * 재귀 적으로 사용해야합니다. – Vlax

+0

@Vlax - 자손 "level_d"가 있는지 확인할 수 있습니까? ('match = "/ */* [descend :: level_d] "')? 구체적으로 일치시킬 템플릿을 추가하여 "level_d"에서 처리를 중단 할 수 있습니다. 업데이트 된 예제는 트리를 거꾸로 가지려는 이유를 이해하는 데 도움이 될 수 있습니다. –

+0

내 첫 번째 버전의 xml에 대해 죄송합니다. 이제는 실제 xml을 더 잘 반영해야합니다. 마지막 버전을 살펴보면 첫 번째 level_b 요소에 해당 트리의 많은 level_d 요소가 있음을 알 수 있습니다. 그래서 내 생각은 모든 level_d 요소를 찾아 조상을 추출하고 자식을 얻는 것이 었습니다. 각 레벨 _d는 별도의 파일에 있습니다. 중첩 된 레벨 _d에서 트리의 마지막 부분 만 신경 써야합니다. 다른 레벨의 상위 레벨은 트리가 별도의 파일을 필요로하지 않으며 조상으로 간주됩니다. – Vlax

관련 문제