2013-06-08 5 views
1

경로를 나타내는 level 요소를 기반으로 플랫 XML에서 중첩 된 계층 구조를 만들려고합니다. 각 level 요소와 그 소속의 형제 (이름과 번호가 다릅니다)는 '레코드'요소에 래핑되어야하므로 트리 구조가 만들어집니다. 이 소스에서XSLT : 경로를 기반으로하는 중첩 된 계층 구조로의 XML

(간체) :

<?xml version="1.0" encoding="UTF-8"?>
  
<record>
  
    <level>first</level>
  
    <unitid>0001</unitid> 
    <a-few-more-siblings/>
  
    <level>first/second</level>
  
    <unitid>0002</unitid>
  
    <many-more-siblings/> 
    <level>first/second/third</level>
  
    <unitid>0003a</unitid> 
    <some-more-siblings/>
  
    <level>first/second/third</level> 
    
<unitid>0003b</unitid> 
    <many-more-siblings/> 
    <level>first/second/third</level>
  
    <unitid>0003c</unitid> 
    <some-more-siblings/>
 
    <level>first</level>
  
    <unitid>0004</unitid>
 
    <again-more-siblings/>
  
</record> 

내가 다음 원하는 출력 생성하고 싶습니다 :

<Record level="first">
 
    <level>first</level> 
    <unitid>001</unitid> 
    <a-few-more-siblings/> 
    <Record level="second">
 
     <level>second</level> 
     <unitid>002</unitid> 
     <many-more-siblings/> 
     <Record level="third"> 
      <level>third</level> 
      <unitid>003a</unitid> 
      <some-more-siblings/> 
     </Record> 
     <Record level="third">
 
      <level>third</level> 
      <unitid>003b</unitid> 
      <many-more-siblings/> 
     </Record> 
     <Record level="third">
 
      <level>third</level> 
      <unitid>003c</unitid> 
      <some-more-siblings/> 
     </Record> 
    </Record>  
</Record> 
<Record level="first"> 
    <level>first</level> 
    <unitid>0004</unitid> 
    <again-more-siblings/> 
</Record> 

지금까지 생산할 수있는 가장 가까운입니다 :

<record level="first"> 
    <level>first</level> 
    <unitid>0001</unitid> 
    <some-other-siblings/> 
    <record level="second"> 
     <level>first/second</level> 
     <unitid>0002</unitid> 
     <some-other-siblings/> 
     <record level="third"> 
      <level>first/second</level> 
      <unitid>0002</unitid> 
      <some-other-siblings/> 
     <level>first/second/third</level> 
     <unitid>0003a</unitid> 
     <some-other-siblings/> 
     </record> 
     <record level="third"> 
      <level>first/second</level> 
      <unitid>0002</unitid> 
      <some-other-siblings/> 
      <level>first/second/third</level> 
      <unitid>0003a</unitid> 
      <some-other-siblings/> 
     <level>first/second/third</level> 
     <unitid>0003b</unitid> 
     <some-other-siblings/> 
     </record> 
     <record level="third"> 
     <level>first/second/third</level> 
     <unitid>0003c</unitid> 
     <some-other-siblings/> 
     </Record> 
    </record> 
</record> 

(제 3의 레벨에있는 바람직하지 않은 형제들에 추가적으로 들여 쓰기되어 있음;

비슷한 문제 ("평면에서 계층 적", "형제 자매까지"등)에 제안 된 접근법의 다양한 변형을 시도했지만 결국 너무 많은 형제 자매가 붙어 있습니다. 특정 위치 또는 세 번째 레벨의 첫 번째 레코드 만 출력합니다.

도움을 주시면 대단히 감사하겠습니다.

답변

2

이렇게하는 한 가지 방법은 키를 사용하는 것입니다. 요소 level의 형제를 가져 오기 시작하려면 가장 먼저 앞에 오는 level 요소로 요소를 그룹화하는 키를 정의 할 수 있습니다 (즉, 그룹은 모든 형제가됩니다).

<xsl:key name="siblings" 
    match="*[not(self::level)]" 
    use="generate-id(preceding-sibling::level[1])" /> 

또한 (짧은 이름을 가진 최초의 가장 앞의 수준에 의해 그룹을 각 레벨 즉,)를 level 요소의 즉각적인 '후손'을 얻을 수있는 키를 정의 할 수 있습니다. 당신은 출력의 열쇠 모두를 활용할 수있는 곳 그런 다음 '첫 번째'레벨 요소

<xsl:apply-templates select="level[. = 'first']" /> 

을 선택하여 간단하게 시작할 것이다 당신의 XSLT에서

<xsl:key name="nextlevel" 
    match="level" 
    use="generate-id(preceding-sibling::level[starts-with(current(), concat(., '/'))][1])" /> 

당신은 다음 level 요소와 일치하는 일반적인 템플릿을 것 형제와 다음 레벨 요소

<xsl:template match="level"> 
    <Record level="{.}"> 
     <xsl:copy-of select="." /> 
     <xsl:apply-templates select="key('siblings', generate-id())" /> 
     <xsl:apply-templates select="key('nextlevel', generate-id())" /> 
    </Record> 
</xsl:template> 

는 다음 XSLT를 시도

당신의 예상 출력에 싸여 두 개의 '첫 번째' level 요소를 가지고 있기 때문에 당신의 XML에 적용
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> 
    <xsl:key name="siblings" match="*[not(self::level)]" use="generate-id(preceding-sibling::level[1])" /> 

    <xsl:key name="nextlevel" match="level" use="generate-id(preceding-sibling::level[starts-with(current(), concat(., '/'))][1])" /> 

    <xsl:template match="record"> 
     <xsl:apply-templates select="level[. = 'first']" /> 
    </xsl:template> 

    <xsl:template match="level"> 
     <Record level="{.}"> 
      <xsl:copy-of select="." /> 
      <xsl:apply-templates select="key('siblings', generate-id())" /> 
      <xsl:apply-templates select="key('nextlevel', generate-id())" /> 
     </Record> 
    </xsl:template> 

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

다음은 출력

<Record level="first"> 
    <level>first</level> 
    <unitid>0001</unitid> 
    <a-few-more-siblings/> 
    <Record level="first/second"> 
     <level>first/second</level> 
     <unitid>0002</unitid> 
     <many-more-siblings/> 
     <Record level="first/second/third"> 
      <level>first/second/third</level> 
      <unitid>0003a</unitid> 
      <some-more-siblings/> 
     </Record> 
     <Record level="first/second/third"> 
      <level>first/second/third</level> 
      <unitid>0003b</unitid> 
      <many-more-siblings/> 
     </Record> 
     <Record level="first/second/third"> 
      <level>first/second/third</level> 
      <unitid>0003c</unitid> 
      <some-more-siblings/> 
     </Record> 
    </Record> 
</Record> 
<Record level="first"> 
    <level>first</level> 
    <unitid>0004</unitid> 
    <again-more-siblings/> 
</Record> 

이 매우 당신이 현재 예상 출력으로 보여주고있다되지 않는 것입니다 단일 Record 요소 ('세 번째'level 요소의 경우 별도의 Record 요소와 비교).당신의 예상 출력이 정말 당신이 기대하는 경우, 대신에이 두 가지 템플릿을 record 일치하는 템플릿을 교체해보십시오 :

<xsl:template match="record"> 
    <Record level="first"> 
     <xsl:apply-templates select="level[. = 'first']" /> 
    </Record> 
</xsl:template> 

<xsl:template match="level[. = 'first']"> 
    <xsl:copy-of select="." /> 
    <xsl:apply-templates select="key('siblings', generate-id())" /> 
    <xsl:apply-templates select="key('nextlevel', generate-id())" /> 
</xsl:template> 
+0

완벽한, 대단히 감사합니다. 그리고 '첫 번째'레벨 요소에 관한 아주 좋은 관찰. 실제로 형제 자매가 더 높은 수준에 속할 수 있음을 설명하기 위해 나중에 두 번째 것을 추가했지만 나 혼란 스러웠습니다. – user9775