2012-06-21 3 views
3

나는 이것을 둘러싼 내 머리를 감싸려고 노력하고 있으며, 가장 쉬운 방법은 아래에서 설명하는 것입니다. 나는 this을 보았습니다.하지만 실제로는 끝날 때 독립 실행 형 항목이 있기 때문에 항상 적용되지는 않습니다.XSLT 두 형제 사이의 요소 그룹화

겉으로보기 까다로운 부분은 Whatever3 to Whatever6이고, Whatever7 and Whatever8은 Whatever9의 새로운 위치입니다. 그룹화해야하고 원래 시퀀스가 ​​유지되어야합니다. (내 이름을 무시하면 xsl : sort를 사용할 방법이 없습니다)

xsl : for-each를 xsl : if로 간주했지만 문제는 얼마나 많은 "그룹"대 "아닌지"를 보장 할 수 없다는 것입니다 - 그룹 "항목이 있습니다.

감사합니다.

XML

<root> 
    <item> 
     <position>1</position> 
     <label>Whatever1</label> 
    </item> 
    <item> 
     <position>2</position> 
     <label>Whatever2</label> 
    </item> 
    <item> 
     <position>3</position> 
     <label>Whatever3</label> 
     <marker id="unique1">start_group</marker> 
    </item> 
    <item> 
     <position>4</position> 
     <label>Whatever4</label> 
    </item> 
    <item> 
     <position>5</position> 
     <label>Whatever5</label> 
    </item> 
    <item> 
     <position>6</position> 
     <label>Whatever6</label> 
     <marker>last_in_group</marker> 
    </item> 
    <item> 
     <position>7</position> 
     <label>Whatever7</label> 
     <marker id="unique2">start_group</marker> 
    </item> 
    <item> 
     <position>8</position> 
     <label>Whatever8</label> 
     <marker>last_in_group</marker> 
    </item> 
    <item> 
     <position>9</position> 
     <label>Whatever9</label> 
    </item> 
</root> 

결과 ====================== 여기

무엇을

<structure> 
    <item> 
     <position>1</position> 
     <label>Whatever1</label> 
    </item> 
    <item> 
     <position>2</position> 
     <label>Whatever2</label> 
    </item> 
    <group position="3" id="unique1"> 
     <item> 
      <position>1</position> 
      <label>Whatever3</label> 
     </item> 
     <item> 
      <position>2</position> 
      <label>Whatever4</label> 
     </item> 
     <item> 
      <position>3</position> 
      <label>Whatever5</label> 
     </item> 
     <item> 
      <position>4</position> 
      <label>Whatever6</label> 
     </item> 
    </group> 
    <group position="4" id="uniqueid2"> 
     <item> 
      <position>1</position> 
      <label>Whatever7</label> 
     </item> 
     <item> 
      <position>2</position> 
      <label>Whatever8</label> 
     </item> 
    </group> 
    <item> 
     <position>**5**</position> 
     <label>Whatever9</label> 
    </item> 
</structure> 

입니다

I 지금까지 내가 가진 유일한 문제는 (지저분한) Whatever4와 Whatever5가 그룹 외부에 나타나기 때문입니다.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:template match="root"> 
    <structure> 
    <xsl:apply-templates select="item[not(marker)] | item[marker='start_group']"/> 
    </structure> 
</xsl:template> 

    <xsl:template match="item[marker='start_group']"> 
    <group> 
    <xsl:variable name="currentPosition" select="number(position/text())"/> 
    <xsl:variable name="lastGroup" select="count(following-sibling::*[local-name() = 'item' and marker='last_in_group'][1]/preceding-sibling::*) + 1"/> 

    <xsl:attribute name="position"> 
     <xsl:value-of select="$currentPosition"/> 
    </xsl:attribute> 
    <xsl:attribute name="id"> 
     <xsl:value-of select="marker/@id"/> 
    </xsl:attribute> 

    <item> 
    <position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position> 
    <label><xsl:value-of select="label/text()"/></label> 
    </item> 

    <!-- position() gets reset in for-loop, so need to adjust with outer position --> 
    <xsl:for-each select="following-sibling::item[(position() + $currentPosition) &lt;= $lastGroup]"> 
     <item> 
       <position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position> 
       <label><xsl:value-of select="label/text()"/></label> 
     </item> 
    </xsl:for-each> 
    </group> 
</xsl:template> 

    <xsl:template match="item[not(marker)]"> 
    <item> 
    <position><xsl:value-of select="position/text()"/></position> 
    <label><xsl:value-of select="label/text()"/></label> 
    </item> 
</xsl:template> 

</xsl:stylesheet> 
+0

무엇을 시도 했습니까? xsl : for-each와 xsl : if를 고려하는 것 외에는. 지금까지 작성한 XSLT를 게시하십시오. – toniedzwiedz

+0

조금 줘, 내 XSLT가있는 곳으로 랩톱을 전환하고 실제 XML 형식에서 위의 모형으로 변환해야한다. –

+0

수정 된 원본 글. –

답변

3

I. XSLT 1.0 솔루션 :

이 변환 :

<root> 
    <item> 
     <position>1</position> 
     <label>Whatever1</label> 
    </item> 
    <item> 
     <position>2</position> 
     <label>Whatever2</label> 
    </item> 
    <item> 
     <position>3</position> 
     <label>Whatever3</label> 
     <marker id="unique1">start_group</marker> 
    </item> 
    <item> 
     <position>4</position> 
     <label>Whatever4</label> 
    </item> 
    <item> 
     <position>5</position> 
     <label>Whatever5</label> 
    </item> 
    <item> 
     <position>6</position> 
     <label>Whatever6</label> 
     <marker>last_in_group</marker> 
    </item> 
    <item> 
     <position>7</position> 
     <label>Whatever7</label> 
     <marker id="unique2">start_group</marker> 
    </item> 
    <item> 
     <position>8</position> 
     <label>Whatever8</label> 
     <marker>last_in_group</marker> 
    </item> 
    <item> 
     <position>9</position> 
     <label>Whatever9</label> 
    </item> 
</root> 
: 제공된 XML 문서에 적용

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kFollowing" 
    match="item[not(marker[. = 'start_group']) 
      and 
       preceding-sibling::*[marker][1]/marker = 'start_group' 
      ]" 
    use="generate-id(preceding-sibling::* 
        [marker[. = 'start_group']] 
        [1])"/> 

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

<xsl:template match="item[marker[. = 'start_group']]"> 
    <group position="{1 +count(preceding-sibling::*[. = 'start_group'])}" 
    id="{marker/@id}"> 
    <xsl:copy-of select=".|key('kFollowing', generate-id())"/> 
    </group> 
</xsl:template> 

<xsl:template match= 
    "item[not(marker[. = 'start_group']) 
     and 
     preceding-sibling::*[marker][1]/marker = 'start_group' 
     ]"/> 
</xsl:stylesheet> 

<root> 
    <item> 
     <position>1</position> 
     <label>Whatever1</label> 
    </item> 
    <item> 
     <position>2</position> 
     <label>Whatever2</label> 
    </item> 
    <group position="1" id="unique1"> 
     <item> 
     <position>3</position> 
     <label>Whatever3</label> 
     <marker id="unique1">start_group</marker> 
     </item> 
     <item> 
     <position>4</position> 
     <label>Whatever4</label> 
     </item> 
     <item> 
     <position>5</position> 
     <label>Whatever5</label> 
     </item> 
     <item> 
     <position>6</position> 
     <label>Whatever6</label> 
     <marker>last_in_group</marker> 
     </item> 
    </group> 
    <group position="1" id="unique2"> 
     <item> 
     <position>7</position> 
     <label>Whatever7</label> 
     <marker id="unique2">start_group</marker> 
     </item> 
     <item> 
     <position>8</position> 
     <label>Whatever8</label> 
     <marker>last_in_group</marker> 
     </item> 
    </group> 
    <item> 
     <position>9</position> 
     <label>Whatever9</label> 
    </item> 
</root> 

II :

이 원하는 정확한 결과를 생성합니다. XSLT 2.0 용액 :이 2.0 XSLT 변환 동일한 XML 문서 (위)에인가

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

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

<xsl:template match="/*"> 
    <root> 
    <xsl:for-each-group select="item" group-starting-with= 
    "*[marker eq 'start_group' 
    or 
     not(marker) 
    and 
     preceding-sibling::*[marker][1]/marker eq 'last_in_group' 
    ] 
    "> 
    <xsl:choose> 
     <xsl:when test="current-group()[1]/marker"> 
       <group position= 
       "{1 +count(current-group()[1] 
          /preceding-sibling::* 
            [marker = 'start_group'])}" 
       id="{marker/@id}"> 
       <xsl:apply-templates select="current-group()"/> 
       </group> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:apply-templates select="current-group()"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:for-each-group> 
    </root> 
</xsl:template> 
</xsl:stylesheet> 

같은 올바른 결과을 제조한다.

+0

감사합니다. Dimitre !! 완벽한, 당신은 뛰어난 있습니다. –

+0

XSLT 1.0 버전에서 변경해야하는 것은 단 한 가지뿐입니다. 일부 요소 (마커 요소가 출력에 나타나서는 안 됨)를 제거해야하므로 xsl : copy-of가 항목에 대해 작동하지 않습니다. –

+0

@JonathonHowey : 천만에. 그런 도전적인 질문을 계속하십시오. –