XSLT与xsl混淆:apply-templates

时间:2010-12-20 21:10:39

标签: xslt

我有一个这种格式的XML文件:

<?xml version="1.0" encoding="utf-8" ?>
<OpacResult>
<valueObjects class="list">
    <Catalog>
        <notes>
            Daily newsletter available via e-mail.&#xd;
            IP authenticated. Login not needed within firm.
        </notes>
        <title>Health law360. </title>
        <url>http://health.law360.com/</url>
        <catalogTitles class="list">
            <CatalogTitle>
                <uuid>e5e2bc53ac1001f808cddc29f93ecad8</uuid>
                <timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
                <timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
                <whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
                <whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
                <updateSearchIndex>true</updateSearchIndex>
                <corpId>RopesGray</corpId>
                <catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
                <type>O</type>
                <title>Law 360. Health law.</title>
            </CatalogTitle>
            <CatalogTitle>
                <uuid>e5e2bc53ac1001f808cddc299ddfe49d</uuid>
                <timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
                <timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
                <whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
                <whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
                <updateSearchIndex>true</updateSearchIndex>
                <corpId>RopesGray</corpId>
                <catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
                <type>O</type>
                <title>Health law 360</title>
            </CatalogTitle>
            <CatalogTitle>
                <uuid>e5e2bc53ac1001f808cddc29ec1d959b</uuid>
                <timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
                <timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
                <whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
                <whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
                <updateSearchIndex>true</updateSearchIndex>
                <corpId>RopesGray</corpId>
                <catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
                <type>O</type>
                <title>Health law three hundred sixty</title>
            </CatalogTitle>
        </catalogTitles>
        <catalogUrls class="list"/>
        <gmd>
            <uuid>f8f123acc0a816070192e296a6a71715</uuid>
            <timeChanged class="sql-timestamp">2006-10-10 15:23:37.813</timeChanged>
            <timeEntered class="sql-timestamp">2005-01-27 00:00:00.0</timeEntered>
            <whoChanged>25db9fcd3fd247f4a20485b40cc134ad</whoChanged>
            <whoEntered>user</whoEntered>
            <updateSearchIndex>true</updateSearchIndex>
            <corpId>RopesGray</corpId>
            <isRuleDefault>false</isRuleDefault>
            <ruleName>text</ruleName>
            <term>electronic resource</term>
            <preferCollection>false</preferCollection>
            <isTechnicalManual>false</isTechnicalManual>
            <sip2IsMagnetic>false</sip2IsMagnetic>
        </gmd>
        <issues class="list"/>
    </Catalog>
</valueObjects>
</OpacResult>

正如您所看到的,兄弟节点下还有其他元素,但我不关心这些,只想看第一个。

我正在使用此代码调用一个模板,其中包含所需元素的字符串作为参数 和一个循环通过星号分隔的字符串参数的模板:(title * url * notes *)

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="columns" />
<xsl:template match="/OpacResult/valueObjects">
    <html>
        <body>
            <table border="1">

                <!-- Header row -->
                <tr>
                    <xsl:call-template name="print-headers">
                        <xsl:with-param name="columns" select="$columns"/>
                    </xsl:call-template>
                </tr>

                <!-- Value rows -->
                <xsl:for-each select="Catalog">
                    <tr>
                        <xsl:call-template name="print-values">
                            <xsl:with-param name="columns" select="$columns"/>
                        </xsl:call-template>
                    </tr>
                </xsl:for-each>
            </table>
        </body>
    </html>
</xsl:template>

<!-- Split up string of column names and create header field names based on element names-->
<xsl:template name="print-headers">
    <xsl:param name="columns"/>

    <xsl:variable name="newList" select="$columns"/>
    <xsl:variable name="first" select="substring-before($newList, '*')" />
    <xsl:variable name="remaining" select="substring-after($newList, '*')" />

    <th>
        <xsl:apply-templates select="Catalog/*[name()=$first]">
            <xsl:with-param name="header">true</xsl:with-param>
        </xsl:apply-templates>
    </th>

    <xsl:if test="$remaining">
        <xsl:call-template name="print-headers">
            <xsl:with-param name="columns" select="$remaining"/>
        </xsl:call-template>
    </xsl:if>

</xsl:template>

<xsl:template name="print-values">
    <xsl:param name="columns"/>

    <xsl:variable name="newList" select="$columns"/>
    <xsl:variable name="first" select="substring-before($newList, '*')" />
    <xsl:variable name="remaining" select="substring-after($newList, '*')" />

    <td>
        <xsl:apply-templates select="Catalog/*[name()=$first]"/>
    </td>

    <xsl:if test="$remaining">
        <xsl:call-template name="print-values">
            <xsl:with-param name="columns" select="$remaining"/>
        </xsl:call-template>
    </xsl:if>

</xsl:template>

<xsl:template match="title">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>Title</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <a>
                <xsl:attribute name="href">
                    <xsl:value-of select="//*[name()='url']"/>
                </xsl:attribute>
                <xsl:value-of select="//*[name()='title']"/>
            </a>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="url">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>URL</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <a>
                <xsl:attribute name="href">
                    <xsl:value-of select="//*[name()='url']"/>
                </xsl:attribute>
                <xsl:value-of select="//*[name()='url']"/>
            </a>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="notes">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>Notes</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="//*[name()='notes']"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="holdingNotes">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>Holding Notes</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="//*[name()='holdingNotes']"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="relatedUrl">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>Related URL</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="//*[name()='relatedUrl']"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="bibliographicType/hasDataFile">
    <xsl:param name="header"/>

    <xsl:choose>
        <xsl:when test="$header='true'">
            <xsl:text>File</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="Catalog/*[name()='hasDataFile']"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

我可以访问此模板的唯一方法是使用// * [name()= $ first]语法根据$ first参数中的名称提取元素的值。

非常感谢任何帮助。首先十分感谢。不包括完整的XML,因为有数千行不必要的文本。

2 个答案:

答案 0 :(得分:1)

此样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:h="header"
 exclude-result-prefixes="h">
    <h:h>
        <title>Title</title>
        <url>URL</url>
        <notes>Notes</notes>
    </h:h>
    <xsl:param name="pColumns" select="'title url notes'"/>
    <xsl:template match="/OpacResult/valueObjects">
        <html>
            <body>
                <table border="1">
                    <tr>
                        <xsl:apply-templates
                             select="document('')/*/h:h"
                             mode="filter"/>
                    </tr>
                    <xsl:apply-templates/>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="Catalog">
        <tr>
            <xsl:call-template name="filter"/>
        </tr>
    </xsl:template>
    <xsl:template match="h:h/*">
        <th>
            <xsl:value-of select="."/>
        </th>
    </xsl:template>
    <xsl:template match="Catalog/*">
        <td>
            <xsl:value-of select="."/>
        </td>
    </xsl:template>
    <xsl:template match="node()" mode="filter" name="filter">
        <xsl:apply-templates select="*[contains(
                                          concat(' ',$pColumns,' '),
                                          concat(' ',name(),' '))]">
            <xsl:sort select="substring-before(
                                 concat(' ',$pColumns,' '),
                                 concat(' ',name(),' '))"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

输出:

<html>
    <body>
        <table border="1">
            <tr>
                <th>Title</th>
                <th>URL</th>
                <th>Notes</th>
            </tr>
            <tr>
                <td>Health law360. </td>
                <td>http://health.law360.com/</td>
                <td>             Daily newsletter available via e-mail.
             IP authenticated. Login not needed within firm.         </td>
            </tr>
        </table>
    </body>
</html>

注意:标题的内联数据,用于过滤和排序的伪序列参数,不以不同方式处理相同元素但以相同方式处理不同元素的模式。

答案 1 :(得分:0)

我找到了解决方案,但我确信这不是最好的方法。在每个预期字段的模板中,我添加了:

<xsl:if test=position()=1">
    .. process data here ..
</xsl:if>

理想情况下,有一种方法可以告诉它只处理它找到的第一个元素:

<th>
    <xsl:apply-templates select="//*[name()=$first]">
        <xsl:with-param name="header">true</xsl:with-param>
    </xsl:apply-templates>
</th>

编辑:我怀疑,当要解析多个Catalog元素时,这将不起作用。因此,不是抓住每个目录父元素的第一个元素,而是每次都抓住文档中的第一个元素