树结构的Xsl模板

时间:2013-10-14 09:02:23

标签: xml xslt

我有一个xml结构。在每个list()中每个position()的xslt模板中,我需要找到属性@out = 1的位置, 然后我需要使用positon的@pid属性创建一个属于它的类别的树结构。

<?xml version="1.0" encoding="ISO-8859-1"?>
    <Good id = "2196">
    <lists>
        <list  num="1050" id = "2531" description="Список оборудования и материалов двойного назначения и соответствующих технологий, применяемых в ядерных целях">
          <part  num="1">
            <pos  isKey="0" id="2532" pid="2531" description="Раздел 1. Промышленное оборудование" />
            <pos  num="1.2." isKey="0" id="2554" pid="2532" description="Испытательное и производственное оборудование" />
            <pos  num="1.2.6." isKey="0" id="2591" pid="2554" description="Системы для вибрационных испытаний, оборудование и компоненты, такие, как:" />
            <pos  num="1.2.6.1." isKey="1" id="2592" pid="2591" description="Электродинамические системы для вибрационных испытаний" />
            <pos  num="1.2.6.4." isKey="1" id="2595" pid="2591" description="Конструкции для крепления испытуемой детали и электронные блоки" />
          </part>
        </list>
        <list  num="1090" id = "3029" description="Список оборудования, материалов и технологий, которые могут быть использованы при создании ракетного оружия">
          <part  num="2">
            <pos  isKey="0" id="3033" pid="3029" description="КАТЕГОРИЯ II" />
            <pos  isKey="0" id="3040" pid="3033" description="Раздел 9. Измерительное, навигационное и пеленгаторное оборудование и системы" />
            <pos  isKey="0" id="3041" pid="3033" description="Раздел 10. Системы управления полетом" />
            <pos  isKey="0" id="3043" pid="3033" description="Раздел 12. Оборудование для обеспечения пуска" />
            <pos  isKey="0" id="3046" pid="3033" description="Раздел 15. Испытательные системы и оборудование" />
            <pos  num="9.2." isKey="0" id="3333" pid="3040" description="Испытательное и производственное оборудование" />
            <pos  num="9.2.1." isKey="0" id="3334" pid="3333" description="Производственное, испытательное.." />
            <pos  num="9.2.1.2" isKey="0" id="3339" pid="3334" description="Испытательное оборудование для инерциальной аппаратуры:" />
            <pos  num="9.2.1.2.3." isKey="1" id="3342" pid="3339" description="Испытательный стенд стабилизирующего элемента ИИБ;" />
            <pos  num="9.2.1.2.5." isKey="1" id="3344" pid="3339" description="Установка для проверки и настройки гироскопа;" />
            <pos  num="9.2.1.2.9." isKey="1" id="3348" pid="3339" description="Центрифуга для проверки подшипников (опор) гироскопа;" />
            <pos  num="9.2.1.2.10." isKey="1" out="1" id="3349" pid="3339" description="Установка для осевой регулировки акселерометра;" />
            <pos  num="9.2.1.2.11." isKey="1" id="3350" pid="3339" description="Установка для проверки акселерометра" />
            <pos  num="9.2.2." isKey="0" id="3351" pid="3333" description="Испытательное, калибровочное и регулировочное оборудование:" />
            <pos  num="9.2.2.3." isKey="1" id="3354" pid="3351" description="Динамические моделирующие стенды/столы вращения)" />
            <pos  num="9.2.2.4." isKey="1" id="3355" pid="3351" description="Поворотные столы" />
            <pos  num="9.2.2.5." isKey="1" id="3356" pid="3351" description="Центрифуги, способные создавать ускорения более 100 g" />
            <pos  num="10.2." isKey="0" id="3373" pid="3041" description="Испытательное и производственное оборудование" />
            <pos  num="10.2.1." isKey="1" id="3374" pid="3373" description="Испытательное, калибровочное и регулировочное оборудование" />
            <pos  num="12.1." isKey="0" id="3399" pid="3043" description="Оборудование, сборочные единицы и комплектующие" />
            <pos  num="12.1.1." isKey="1" id="3400" pid="3399" description="Устройства и приборы, разработанные или модифицированные для обслуживания, проверки" />
        </part>
        </list>
        <list  num="1030" id="6648" description="Список товаров и технологий двойного назначения, которые могут быть использованы при создании вооружений и военной техники">
          <part  num="4">
            <pos  isKey="0" id="6679" pid="6648" description="Раздел 4. Товары и технологии, вывоз которых с территории РФ" />
            <pos  isKey="0" id="6681" pid="6679" description="Категория 2. Перспективные материалы" />
            <pos  num="2.2." isKey="0" id="11599" pid="6681" description="Испытательное, контрольное и производственное оборудование" />
            <pos  num="2.2.1." isKey="1" id="11600" pid="11599" description="Оборудование для тепловых испытаний образцов материалов с углерод-углеродным покрытием" />

                                                   

例如,对于数字为“9.2.1.2.10”的位置。我在word文档中需要一些输出:

 +-------------------------------------------------------------------------------+
 | Список оборудования, материалов и технологий, которые могут быть использованы |
 | при создании ракетного оружия                                                 |
 +-------------------------------------------------------------------------------+
 | КАТЕГОРИЯ II                                                                  |
 +-------------------------------------------------------------------------------+
 | Раздел 9. Измерительное, навигационное и пеленгаторное оборудование и системы |
 +-------------------------------------------------------------------------------+
 | 9.2.       | Испытательное и производственное оборудование                    |
 | 9.2.1.     | Производственное, испытательное..                                |
 | 9.2.1.2.   | Испытательное оборудование для инерциальной аппаратуры           |
 | 9.2.1.2.10.| Установка для осевой регулировки акселерометра                   |
 +-------------------------------------------------------------------------------+

但如果我想要4个位置有“9.2.1.2.10”,“10.2.1”,“2.2.1”,“2.2.2”,我需要一些输出:

 +-------------------------------------------------------------------------------+
 | Список оборудования, материалов и технологий, которые могут быть использованы |
 | при создании ракетного оружия                                                 |
 +-------------------------------------------------------------------------------+
 | КАТЕГОРИЯ II                                                                  |
 +-------------------------------------------------------------------------------+
 | Раздел 9. Измерительное, навигационное и пеленгаторное оборудование и системы |
 +-------------------------------------------------------------------------------+
 | 9.2.       | Испытательное и производственное оборудование                    |
 | 9.2.1.     | Производственное, испытательное..                                |
 | 9.2.1.2.   | Испытательное оборудование для инерциальной аппаратуры           |
 | 9.2.1.2.10.| Установка для осевой регулировки акселерометра                   |
 +-------------------------------------------------------------------------------+
 | Раздел 10. Системы управления полетом                                         |
 +-------------------------------------------------------------------------------+
 | 10.2.      | Испытательное и производственное оборудование                    |
 | 10.2.1     | Испытательное, калибровочное и регулировочное оборудование       |
 +-------------------------------------------------------------------------------+


 +-------------------------------------------------------------------------------+
 | Список товаров и технологий двойного назначения, которые могут быть           |
 |использованы при создании вооружений и военной техники                         |
 +-------------------------------------------------------------------------------+
 | Раздел 4. Товары и технологии, вывоз которых с территории РФ                  |
 +-------------------------------------------------------------------------------+
 | Категория 2. Перспективные материалы                                          |
 +-------------------------------------------------------------------------------+
 | 2.2.       | Испытательное, контрольное и производственное оборудование       |
 | 2.2.1.     | Оборудование для тепловых испытаний образцов материалов...       |
 | 2.2.2.     | Оборудование для тепловых испытаний образцов материалов...       |
 +-------------------------------------------------------------------------------+

到目前为止,我尝试过这样的事情:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


<xsl:template match="/">

  <html>
  <body>
  <h2>Lists</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Id</th>
        <th>parentID</th>
      </tr>
<xsl:apply-templates select="/goods/good/list/part/pos[@out=1]"/>
    </table>
  </body>
  </html>
</xsl:template>

<xsl:template match="/goods/good/list/part/pos[@out=1]">
<xsl:variable name="pid" select="./@pid" />
  Key node: <span style="color:#ff0000">
  <xsl:value-of select="./@num"/><xsl:text>, id =  </xsl:text>
<xsl:value-of select="./@id"/><xsl:text>, pid =  </xsl:text>
<xsl:value-of select="./@pid"/>
</span><br/>
<xsl:call-template name = "while">
 <xsl:with-param name="param" select="$pid"/>
</xsl:call-template>


  <br />
</xsl:template>



<xsl:template name = "while">
<xsl:param name="param"/>
<xsl:variable name="pid" select="../pos[@id = $param]/@pid"/>

<tr>
<td><xsl:value-of select="../pos[@id = $param]/@id"/></td>
<td><xsl:value-of select="../pos[@id = $param]/@pid"/></td>
</tr>

Param: <span style="color:#ff0000">
<xsl:value-of select="$param"/>
</span>

Inner var: <span style="color:#ff0000">
<xsl:value-of select="$pid"/>
</span>


<xsl:if test="$pid">
<br/>
<xsl:call-template name = "while">
 <xsl:with-param name="param" select="$pid"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

可能有更好的方法来完成这项任务吗?

1 个答案:

答案 0 :(得分:2)

pidid链接链后,您似乎需要为pos元素设置两个单独的列,这些列具有num属性和一个两个-column-spanning td用于其他案例(pos元素没有num,或者元素未调用pos)。您可以使用跟踪链:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes" />

  <!-- key to look up any element with an id attribute based on the value of
       that id -->
  <xsl:key name="elementById" match="*[@id]" use="@id" />

  <xsl:template match="/">
    <html>
      <body>
      <h2>Lists</h2>
        <xsl:apply-templates select="//*[@out = '1']" mode="table" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="*" mode="table">
    <table>
      <xsl:apply-templates select="." />
    </table>
  </xsl:template>

  <!-- the main recursive logic - first produce the output for the next
       item in the pid->id chain, then produce a row for this element -->
  <xsl:template match="*">
    <xsl:apply-templates select="key('elementById', @pid)" />
    <tr>
      <td colspan="2"><xsl:value-of select="@description" /></td>
    </tr>
  </xsl:template>

  <!-- special case for pos elements with a @num - produce two columns -->
  <xsl:template match="pos[@num]">
    <xsl:apply-templates select="key('elementById', @pid)" />
    <tr>
      <td><xsl:value-of select="@num" /></td>
      <td><xsl:value-of select="@description" /></td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

当我们到达没有pid属性的元素时,递归会自动停止,因为在这种情况下,键将不匹配任何内容。


如果你想对树中的父链接进行去复制和分组,那么你必须自上而下工作而不是自下而上,反过来链接:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes" />

  <!-- key to look up any element with an id attribute based on the value of
       that id -->
  <xsl:key name="elementsByPid" match="*[@pid]" use="@pid" />

  <xsl:template match="/">
    <html>
      <body>
      <h2>Lists</h2>
        <xsl:apply-templates select="/Good/lists/list" mode="table" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="*" mode="table">
    <xsl:variable name="shouldOutput">
      <xsl:apply-templates select="." mode="shouldOutput" />
    </xsl:variable>
    <xsl:if test="string-length($shouldOutput)">
      <table>
        <xsl:apply-templates select="." />
      </table>
    </xsl:if>
  </xsl:template>

  <!-- the main recursive logic - first produce output for this row, then
       process any of the children (in the id->pid chain) that need to be
       output -->
  <xsl:template match="*">
    <xsl:apply-templates select="." mode="row" />
    <xsl:for-each select="key('elementsByPid', @id)">
      <xsl:variable name="shouldOutput">
        <xsl:apply-templates select="." mode="shouldOutput" />
      </xsl:variable>
      <xsl:if test="string-length($shouldOutput)">
        <xsl:apply-templates select="." />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="*" mode="row">
    <tr>
      <td colspan="2"><xsl:value-of select="@description" /></td>
    </tr>
  </xsl:template>

  <!-- special case for pos elements with a @num - produce two columns -->
  <xsl:template match="pos[@num]" mode="row">
    <tr>
      <td><xsl:value-of select="@num" /></td>
      <td><xsl:value-of select="@description" /></td>
    </tr>
  </xsl:template>


  <!-- check whether this node should be output by checking whether it, or any
       of its descendants in the id->pid tree, has @out=1.  The template will
       return an empty RTF for nodes that should not be output, and an RTF
       containing a text node with one or more "1" characters for nodes that
       should.  -->
  <xsl:template match="*[@out='1']" mode="shouldOutput">1</xsl:template>
  <xsl:template match="*" mode="shouldOutput">
    <xsl:apply-templates select="key('elementsByPid', @id)"
         mode="shouldOutput"/>
  </xsl:template>

</xsl:stylesheet>

对于大型输入文档而言,这将是相当低效的,因为它必须在每个级别跟随整个id-&gt; pid链接到底部,以检查当前节点是否具有 any out="1"链中的后代。如果您可以预先处理文档以提前计算出这些链,并使用out="1"标记链中的每个链接,那么逻辑将更加简单和高效。