首页 文章

是否可以使用XSLT 2.0将简约XML转换为完整的HTML表?

提问于
浏览
1

非常重要注意:我正在使用QtXmlPattern(一个没有完全实现的XSLT 2.0处理器,在实现的内容中有一些错误......)

我有一个格式良好的XML文件,其数据在四级数组中定义,如下所示:

<a>
  <b>
    <c day="20150221">
      <d>...</d>
      <e>...</e>
    </c>
    <c day="20150222">
      <d>...</d>
      <e>...</e>
    </c>
    <c day="20150223">
      <d>...</d>
      <e>...</e>
    </c>
  </b>
  <b>
    <c day="20150219">
      <d>...</d>
      <e>...</e>
    </c>
    <c day="20150221">
      <d>...</d>
      <e>...</e>
    </c>
    <c day="20150223">
      <d>...</d>
      <e>...</e>
    </c>
  </b>
  ...
</a>

结果应包括所有日期,但正如我们所看到的,每个 <b> 列表可能有不同的天数 . 然而,结果需要包含所有 <b> 标签的所有日期 . 如果数据不可用,则结果保持为空或零 .

我找到了一种方法来收集变量中的所有日子:

<xsl:variable name="days" select="distinct-values(/a/b/c/@day)"/>

但我不知道如何生成看起来像这样的最终结果:

<table>
  <th>
    <td>20150219</td>
    <td>20150221</td>
    <td>20150222</td>
    <td>20150223</td>
  </th>
  <tr>
    <td>data from <d> tag on 20150219</td>
    <td>data from <d> tag on 20150221</td>
    <td>data from <d> tag on 20150222</td>
    <td>data from <d> tag on 20150223</td>
  </tr>
  ...[repeat for various data and calculation on the data]...
</table>

我的问题是变量不是节点列表,只是一个字符串列表,我不太清楚如何循环遍历字符串列表 .

为了以防万一,对于那些不了解QXmlQuery解析器的人, xsl:for-each-group 命令不存在 .

2 回答

  • 2

    我不确定你需要什么,但有时候对尝试解决方案的评论比试图解释更容易 . 您必须使用密钥来查找不同的属性值 .

    不要循环遍历字符串列表,而是通过一系列 c 元素,这些元素相对于它们的 day 属性的值是唯一的(最后,它们是相同的) . 我使用的技术由Jeni Tennison here描述,因为它通常用于分组问题 .

    XML Input

    在我看来,合理的输入包括 d 元素的实际值:

    <?xml version="1.0" encoding="UTF-8"?>
    <a>
      <b>
        <c day="20150221">
          <d>data from day 20150221</d>
          <e>...</e>
        </c>
        <c day="20150222">
          <d>data from day 20150222</d>
          <e>...</e>
        </c>
        <c day="20150223">
          <d>data from day 20150223</d>
          <e>...</e>
        </c>
      </b>
      <b>
        <c day="20150219">
          <d>data from day 20150219</d>
          <e>...</e>
        </c>
        <c day="20150221">
          <d>data from day 20150221</d>
          <e>...</e>
        </c>
        <c day="20150223">
          <d>data from day 20150223</d>
          <e>...</e>
        </c>
      </b>
      <!--...-->
    </a>
    

    Stylesheet

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
    
        <xsl:key name="day-from-c" match="c" use="@day" />
    
        <xsl:template match="/">
          <hmtl>
            <xsl:apply-templates/>
          </hmtl>
        </xsl:template>
    
        <xsl:template match="a">
            <table>
    
                <xsl:variable name="days" select="b/c[generate-id() =
            generate-id(key('day-from-c', @day)[1])]"/>
    
                <xsl:for-each select="$days">
                    <xsl:sort select="@day"/>
                    <th>
                        <xsl:value-of select="@day"/>
                    </th>
                </xsl:for-each>
                <tr>
                    <xsl:for-each select="$days">
                        <xsl:sort select="@day"/>
                        <td>
                            <xsl:value-of select="/a/b/c[@day = current()/@day]/d"/>
                        </td>
                    </xsl:for-each>
                </tr>
            </table>
        </xsl:template>
    
    </xsl:transform>
    

    HTML Output

    我仍然不清楚如果同一天有多个 d 元素会发生什么 .

    <!DOCTYPE html
      PUBLIC "XSLT-compat">
    <hmtl>
       <table>
          <th>20150219</th>
          <th>20150221</th>
          <th>20150222</th>
          <th>20150223</th>
          <tr>
             <td>data from day 20150219</td>
             <td>data from day 20150221 data from day 20150221</td>
             <td>data from day 20150222</td>
             <td>data from day 20150223 data from day 20150223</td>
          </tr>
       </table>
    </hmtl>
    

    试试这个解决方案online on xsltransform .

  • 2

    你可以(使用XSLT 2.0,不确定你所选择的处理器是否支持那个)

    <xsl:variable name="main-doc" select="/">
    

    将主文档节点存储在稍后将要使用的变量中,然后定义一个键

    <xsl:key name="by-date" match="a/b/c/d" use="../@day"/>
    

    然后在一天中引用 d 项目

    <xsl:for-each select="$days">
      <xsl:variable name="d-on-day" select="key('by-date', ., $main-doc)"/>
    

    那个带有三个参数的 key() 调用在XSLT 2.0中是新的,如果不支持则尝试

    <xsl:for-each select="$days">
      <xsl:variable name="day" select="."/>
      <xsl:for-each select="$main-doc">
        <xsl:variable name="d-on-day" select="key('by-date', $day)"/>
        ...
      </xsl:for-each>
      ...
    </xsl:for-each>
    

    如果 key 函数不可用,那么您需要将引用写为例如

    <xsl:variable name="d-elements" select="/a/b/c/d"/>
    
    <xsl:for-each select="$days">
      <xsl:variable name="day" select="."/>
      <xsl:for-each select="$d-elements[../@day = $day]">...</xsl:for-each>
    </xsl:for-each>
    

相关问题