2009-06-04 4 views
3

내가 같은 일부 계층 XML있어 HTML 테이블에 XML 계층 구조를 평평하게하기 : 요소의XSLT는

<node text="a" value="1"> 
    <node text="gga" value="5"> 
    <node text="dh" value="9"> 
     <node text="tyfg" value="4"> 
     </node> 
    </node> 
    </node> 
    <node text="dfhgf" value="7"> 
    <node text="fdsg" value="2"> 
    </node> 
    </node> 
</node> 

이름 아래 같은 모든 방법 ("노드"), 그리고 깊이의 계층 구조는 미리 알 수 없습니다. 위의 샘플에서 가장 깊은 리프는 4 개이지만, 깊이가있을 수 있습니다.

내가해야 할 일은이 XML을 HTML 테이블로 전개하는 것입니다. 표의 열 수는 가장 깊은 요소의 깊이와 각 요소의 value 속성에 대한 열을 더한 값과 같아야합니다. "값"은 테이블의 가장 오른쪽 열에 나타나야하므로 출력 행에 가장자리가 울퉁불퉁 할 수 없습니다. 노드의 레벨에 관계없이 각 노드에 대한 행이 있어야합니다. 위의 예는 다음과 같이 변형되어야합니다 :

<table> 
    <tr> 
    <td>a</td> 
    <td></td> 
    <td></td> 
    <td></td> 
    <td>1</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td></td> 
    <td></td> 
    <td>5</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td></td> 
    <td>9</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td>tyfg</td> 
    <td>4</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td></td> 
    <td></td> 
    <td>7</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td>fdsg</td> 
    <td></td> 
    <td>2</td> 
    </tr> 
</table> 

아무도 이것을 얻을 수있는 영리한 XSLT가 있습니까?

+0

것 같습니다 부모 엘의 사슬을 반복하면서 구조를 시각화한다. 각 행에 ements. 당신이 정말로 그것이 테이블이 될 필요가 있습니까? 결과는 나에게 실제로 표의 데이터처럼 보이지 않습니다. – Rytmis

+0

예, 목표는 구조를 시각화하는 것입니다. 탁자가 나에게 가장 좋은 선택 인 것 같았지만 내 마음은 대안 제시가 열려 있습니다. 여러분이 말했듯이, 실제로 필요한 것은 각 행에있는 일련의 요소들입니다. – Matt

답변

3

그것은이다 확실히 당신이 필요합니다 (이 들쭉날쭉 테이블을 잎 때문에)하지만 여전히 HTML에서 일 것입니다 무엇을

<xsl:template match="/"> 
    <html> 
     <head> 
     </head> 
     <body> 
      <table> 
       <xsl:apply-templates select="//node" mode="row" /> 
      </table> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="node" mode="row"> 
    <tr> 
     <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/> 
     <xsl:apply-templates select="node[1]" mode="emptycell"/> 
    </tr> 
</xsl:template> 

<xsl:template match="node" mode="popcell"> 
    <td><xsl:value-of select="@text"/></td> 
</xsl:template> 

<xsl:template match="node" mode="emptycell"> 
    <td></td> 
    <xsl:apply-templates select="node[1]" mode="emptycell"/> 
</xsl:template> 

버전 2 : 글쎄, 그것으로 자기 만족 상당히 적은 해요 : P, 그러나 다음은 지그재그를 제거합니다.

<xsl:variable name="depth"> 
    <xsl:for-each select="//node"> 
     <xsl:sort select="count(ancestor::node)" data-type="number" order="descending"/> 
     <xsl:if test="position()=1"> 
      <xsl:value-of select="count(ancestor::node)+1"/> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:variable> 

<xsl:template match="/"> 
    <html> 
     <head> 
     </head> 
     <body> 
      <table> 
       <xsl:apply-templates select="//node" mode="row" /> 
      </table> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="node" mode="row"> 
    <tr> 
     <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/> 
     <xsl:call-template name="emptycells"> 
      <xsl:with-param name="n" select="($depth)-count(ancestor-or-self::node)"/> 
     </xsl:call-template> 
     <td><xsl:value-of select="@value"/></td> 
    </tr> 
</xsl:template> 

<xsl:template match="node" mode="popcell"> 
    <td><xsl:value-of select="@text"/></td> 
</xsl:template> 

<xsl:template name="emptycells"> 
    <xsl:param name="n" /> 
    <xsl:if test="$n &gt; 0"> 
     <td></td> 
     <xsl:call-template name="emptycells"> 
      <xsl:with-param name="n" select="($n)-1"/> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
+0

+1 놀라운 xslt입니다. –

+0

감사합니다. 때때로 XSLT의 우아함은 정말 놀랍습니다. – annakata

+0

안녕하세요 annakata, 감사합니다! 그것은 내가 필요로하는 것에 가깝다. 불행히도 들쭉날쭉 한 테이블은 문제 다. 질문의 첫 번째 초안에서 나는 나의 문제를 단순화했다. 나는 그것을 지금 개정 했으므로 가장자리를 들쭉날쭉하게 만들 수없는 이유는 분명해야합니다. – Matt

0

이 XSLT 1.0 솔루션이이를 수행합니다.

  • 에는 재귀

XSLT 코드를 사용하지

  • 잘 형성된 HTML 테이블을 생성합니다

    출력이
    <xsl:stylesheet 
        version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    > 
    
        <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 
    
        <!-- some preparation --> 
        <xsl:variable name="vAllNodes" select="//node" /> 
    
        <!-- find out the deepest nested node --> 
        <xsl:variable name="vMaxDepth"> 
        <xsl:for-each select="$vAllNodes"> 
         <xsl:sort 
         select="count(ancestor::node)" 
         data-type="number" 
         order="descending" 
         /> 
         <xsl:if test="position() = 1"> 
         <xsl:value-of select="count(ancestor-or-self::node)" /> 
         </xsl:if> 
        </xsl:for-each> 
        </xsl:variable> 
    
        <!-- select a list of nodes, merely to iterate over them --> 
        <xsl:variable name="vIteratorList" select=" 
        $vAllNodes[position() &lt;= $vMaxDepth] 
        " /> 
    
        <!-- build the table --> 
        <xsl:template match="/"> 
        <table> 
         <!-- the rows will be in document order --> 
         <xsl:apply-templates select="$vAllNodes" /> 
        </table> 
        </xsl:template> 
    
        <!-- build the rows --> 
        <xsl:template match="node"> 
        <xsl:variable name="self" select="." /> 
        <tr> 
         <!-- iteration instead of recursion --> 
         <xsl:for-each select="$vIteratorList"> 
         <xsl:variable name="vPos" select="position()" /> 
         <td> 
          <!-- the ancestor axis is indexed the other way around --> 
          <xsl:value-of select=" 
          $self/ancestor-or-self::node[last() - $vPos + 1]/@text 
          " /> 
         </td> 
         </xsl:for-each> 
         <td> 
         <xsl:value-of select="@value" /> 
         </td> 
        </tr> 
        </xsl:template> 
    
    </xsl:stylesheet> 
    

    : 당신이하려는 것처럼

    <table> 
        <tr> 
        <td>a</td> 
        <td></td> 
        <td></td> 
        <td></td> 
        <td>1</td> 
        </tr> 
        <tr> 
        <td>a</td> 
        <td>gga</td> 
        <td></td> 
        <td></td> 
        <td>5</td> 
        </tr> 
        <tr> 
        <td>a</td> 
        <td>gga</td> 
        <td>dh</td> 
        <td></td> 
        <td>9</td> 
        </tr> 
        <tr> 
        <td>a</td> 
        <td>gga</td> 
        <td>dh</td> 
        <td>tyfg</td> 
        <td>4</td> 
        </tr> 
        <tr> 
        <td>a</td> 
        <td>dfhgf</td> 
        <td></td> 
        <td></td> 
        <td>7</td> 
        </tr> 
        <tr> 
        <td>a</td> 
        <td>dfhgf</td> 
        <td>fdsg</td> 
        <td></td> 
        <td>2</td> 
        </tr> 
    </table> 
    
  • +0

    Tomalak에게 감사드립니다. 아주 잘 작동합니다. 을 - 나는 내가 원하는 출력을 얻기 위해 하나의 작은 변화를 만들어 : value-of select = "$ vNodes [$ vPos]/@ text"/> 그렇지 않으면 행의 텍스트 셀이 역순입니다 (예 : 리프 노드 텍스트가 가장 왼쪽 열에 있음) – Matt

    +0

    사실, 일어날거야.$ vNodes는 조상 축을 기준으로합니다. 즉, $ vNodes [1]은 잎이어야합니다. 어떤 XSLT 프로세서를 사용하고 있습니까? – Tomalak

    +0

    Visual Studio 2008 – Matt

    관련 문제