Генерация динамической таблицы HTML с помощью XSL - PullRequest
1 голос
/ 30 июня 2010

У меня есть следующие данные XML:

<Activity>
<ObjectGroup type="default">
<Object id="1874" name="PR1010Date" type="reference label" index="10" columnNo="0" dynamic="true">
      <Description>Date</Description>      
      <Value instance="0">30/06/2010</Value>
    </Object>
    <Object id="1875" name="PR1020LoggedBy" type="reference label" index="20" columnNo="1" dynamic="true">
      <Description>Request Logged By</Description>     
      <Value>Site Administrator</Value>
    </Object>
    <Object id="1876" name="PR1030Comments" type="large text box" index="30" columnNo="0" dataType="Text">
      <Description>Comments</Description>      
      <Value instance="0">Test</Value>
    </Object>
<ObjectGroup>
</Activity>

Мне нужно создать XSL, который будет производить следующий вывод:

<html>
<table>
<tr>
<td width="50%">30/06/2010</td>
<td width="50%">Site Admin</td>
</tr>
<tr>
<td width="100%">Test</td>
</tr>
</table>

В приведенном выше XML атрибут индекса вместе сcolumnNo определяет количество создаваемых строк и столбцов.Каков конечный результат определяется для ColumnNo, поэтому, если у ObjectGroup есть Objects с добавочным columnNo, то все они отображаются в одну строку с соответствующей шириной для каждого столбца.

Ответы [ 2 ]

1 голос
/ 01 июля 2010

После превосходного ответа от Dimitre, еще одной таблицы стилей без ключей.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="ObjectGroup">
        <html>
            <table border="1">
                <xsl:apply-templates select="Object[@columnNo=0]"/>
            </table>
        </html>
    </xsl:template>
    <xsl:template match="Object">
        <xsl:variable name="td"
                      select=".|following-sibling::*[@columnNo!=0][
                                      count(current()|
                                            preceding-sibling::*[@columnNo=0][1]
                                      )=1]"/>
        <tr>
            <xsl:apply-templates select="$td/Value">
                <xsl:with-param name="td-count" select="count($td)"/>
            </xsl:apply-templates>
        </tr>
    </xsl:template>
    <xsl:template match="Value">
        <xsl:param name="td-count"/>
        <td width="{100 div $td-count}%">
            <xsl:value-of select="."/>
        </td>
    </xsl:template>
</xsl:stylesheet>

Однако большинство процессоров XSLT допускают использование ключей.

Теперь для colspan:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:variable name="td-max">
        <xsl:call-template name="max">
            <xsl:with-param name="nodes" select="/*/*/Object[@columnNo=0]"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:template name="max">
        <xsl:param name="nodes"/>
        <xsl:if test="$nodes">
            <xsl:variable name="head"
                              select="count($nodes[1]/following-sibling::*[@columnNo!=0][
                                          count($nodes[1]|
                                                preceding-sibling::*[@columnNo=0][1]
                                          )=1])+1"/>
            <xsl:variable name="tail">
                <xsl:call-template name="max">
                    <xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:choose>
                <xsl:when test="$head > $tail or $tail=''">
                    <xsl:value-of select="$head"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$tail"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>
    <xsl:template match="ObjectGroup">
        <html>
            <table border="1">
                <xsl:apply-templates select="Object[@columnNo=0]"/>
            </table>
        </html>
    </xsl:template>
    <xsl:template match="Object">
        <xsl:variable name="td"
                          select=".|following-sibling::*[@columnNo!=0][
                                          count(current()|
                                                preceding-sibling::*[@columnNo=0][1]
                                          )=1]"/>
        <tr>
            <xsl:apply-templates select="$td/Value">
                <xsl:with-param name="td-count" select="count($td)"/>
            </xsl:apply-templates>
        </tr>
    </xsl:template>
    <xsl:template match="Value">
        <xsl:param name="td-count"/>
        <td width="{100 div $td-count}%">
            <xsl:if test="position()=last() and $td-max > $td-count">
                <xsl:attribute name="colspan">
                    <xsl:value-of select="$td-max - $td-count + 1"/>
                </xsl:attribute>
            </xsl:if>
            <xsl:value-of select="."/>
        </td>
    </xsl:template>
</xsl:stylesheet>

Редактировать : добавлен динамический colspan.Это может быть менее многословно, если вас не волнует кратное число colspan="1".

Редактировать 2 : лучший максимальный шаблон.

1 голос
/ 01 июля 2010

Это преобразование :

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

 <xsl:key name="kObjByCol" match="Object"
  use="@columnNo"/>

 <xsl:key name="kRow" match="Object[@columnNo != 0]"
  use="generate-id(preceding-sibling::Object
                                 [@columnNo = 0][1]
                   )"/>

 <xsl:template match="/*">
   <html>
     <table border="1">
       <xsl:apply-templates select=
       "key('kObjByCol', 0)"/>
     </table>
   </html>
 </xsl:template>

 <xsl:template match="Object">
   <xsl:variable name="vcellNodes"
    select=".|key('kRow',generate-id())"/>
   <tr>
     <xsl:apply-templates mode="row" select=
        "$vcellNodes">
       <xsl:with-param name="pCount"
            select="count($vcellNodes)"/>
     </xsl:apply-templates>
   </tr>
 </xsl:template>

 <xsl:template match="Object" mode="row">
   <xsl:param name="pCount"/>
   <td width="{100 div $pCount}%">
     <xsl:value-of select="Value"/>
   </td>
 </xsl:template>
</xsl:stylesheet>

применительно к предоставленному документу XML (исправлено, чтобы быть правильно сформированным):

<Activity>
    <ObjectGroup type="default">
        <Object id="1874" name="PR1010Date"
         type="reference label" index="10"
         columnNo="0" dynamic="true">
            <Description>Date</Description>
            <Value instance="0">30/06/2010</Value>
        </Object>
        <Object id="1875" name="PR1020LoggedBy"
         type="reference label" index="20"
         columnNo="1" dynamic="true">
            <Description>Request Logged By</Description>
            <Value>Site Administrator</Value>
        </Object>
        <Object id="1876" name="PR1030Comments"
         type="large text box" index="30"
         columnNo="0" dataType="Text">
            <Description>Comments</Description>
            <Value instance="0">Test</Value>
        </Object>
    </ObjectGroup>
</Activity>

дает желаемый, правильный результат :

<html>
    <table border="1">
        <tr>
            <td width="50%">30/06/2010</td>
            <td width="50%">Site Administrator</td>
        </tr>
        <tr>
            <td width="100%">Test</td>
        </tr>
    </table>
</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...