XSLT Путаница с xsl: apply-templates - PullRequest
0 голосов
/ 21 декабря 2010

У меня есть 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 ]

1 голос
/ 21 декабря 2010

Эта таблица стилей:

<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>

Примечание : встроенные данные для заголовков, параметр псевдопоследовательности для фильтрации и сортировки, режимы не дляобрабатывать один и тот же элемент по-разному, но обрабатывать разные элементы одинаково.

0 голосов
/ 29 декабря 2010

Я нашел решение, но уверен, что это не лучший способ сделать это. В шаблонах для каждого из моих ожидаемых полей я добавил:

<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>

Редактировать: Как я и подозревал, это не будет работать, когда нужно проанализировать более одного элемента каталога. Поэтому вместо того, чтобы захватывать первый элемент для каждого родительского элемента каталога, он захватывает первый элемент в документе каждый раз

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...