выбрать все подходящие узлы, используя xpath и xslt (без дополнительных шаблонов или для каждого) - PullRequest
3 голосов
/ 06 июля 2010

У меня есть особая проблема, которую я не могу решить.

Можно ли выбрать все узлы, используя xpath и xslt без использования дополнительных шаблонов или для каждого?

Пример xml:

<aaa id="11">
    <aaa id="21"></aaa>
    <bbb id="22">
        <aaa id="31"></aaa>
        <bbb id="32"></bbb>
        <ccc id="33"></ccc>
        <ddd id="34"></ddd>
        <ddd id="35"></ddd>
        <ddd id="36"></ddd>
    </bbb>
    <ccc id="23"></ccc>
    <ccc id="24"></ccc>
</aaa>

Пользователь имеет возможность вводить выражение xpath через форму, например:

//aaa/bbb/ddd/@id

Пользователь ожидает получить идентификаторы из:

<ddd id="34"></ddd>
<ddd id="35"></ddd>
<ddd id="36"></ddd>

Вывод:

34 35 36

Единственный способ, которым я смог добиться этого, - это использовать дополнительные шаблоны и для каждого:

Для каждого пути:

<xsl:template match="/">
    <html>
        <body>
            <xsl:for-each select="//aaa/bbb/ddd">
                <tr>
                    <td>
                        <xsl:value-of select="@id" />
                    </td>
                </tr>
            </xsl:for-each>
        </body>
    </html>
</xsl:template>

Дополнительный способ шаблона:

    <xsl:template match="/">
    <html>
        <body>
            <xsl:apply-templates/>
        </body>
    </html>
</xsl:template>

<xsl:template match="//aaa/bbb/ddd">
    <xsl:value-of select="@id"/>
</xsl:template>

Каждый из этих примеров требует дополнительной работы для отделения @id от исходного выражения.Я хотел бы использовать введенное пользователем выражение как есть и просто подключить его куда-нибудь.

Я пробовал следующее, которое, как я думал, выберет все, но оно возвращает только первый экземпляр:

<xsl:template match="/">
    <html>
        <body>
            <xsl:value-of select="//aaa/bbb/ddd/@id"/>
        </body>
    </html>
</xsl:template>

Есть ли решение моей проблемы (то есть способ просто вставить введенное пользователем выражение как есть?)

РЕДАКТИРОВАТЬ: Примечание - мне нужно решение, которое будет работать с любымВыражение xpath, данное пользователем ... независимо от того, насколько оно сложное.

Дайте мне знать, если вам понадобятся какие-либо дополнительные разъяснения .. Я старался изо всех сил, чтобы объяснить это, но, возможно, я не оченьхорошо .. Заранее спасибо за ваше терпение!

Спасибо!:)

Ответы [ 4 ]

2 голосов
/ 07 июля 2010

В XSLT 1.0 это, вероятно, самый простой способ получить желаемый результат без «дополнительной работы по отсоединению @id от исходного выражения»:

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

 <xsl:template match="node()|@*">
   <xsl:apply-templates select="node()|@*"/>
 </xsl:template>

 <xsl:template match="aaa/bbb/ddd/@id">
   <xsl:value-of select="concat(., ' ')"/>
 </xsl:template>
</xsl:stylesheet>

Вот XPath 2.0однострочник :

//aaa/bbb/ddd/@id/string(.)

То же самое, завернутый в таблицу стилей XSLT 2.0 :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
   <xsl:sequence select="//aaa/bbb/ddd/@id/string(.)"/>
 </xsl:template>
</xsl:stylesheet>
2 голосов
/ 07 июля 2010

С помощью этой таблицы стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="node-set" select="/aaa/bbb//ddd/@id"/>
    <xsl:template match="/">
        <html>
            <body>
                <table>
                    <tr>
                        <th>Type</th>
                        <th>Name</th>
                        <th>Value</th>
                    </tr>
                    <xsl:apply-templates select="$node-set" mode="result"/>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="@*|node()" mode="result">
        <tr>
            <td>
                <xsl:choose>
                    <xsl:when test="self::*">Element</xsl:when>
                    <xsl:when test="self::text()">Text</xsl:when>
                    <xsl:when test="self::comment()">Comment</xsl:when>
                    <xsl:when test="self::processing-instruction()">PI</xsl:when>
                    <xsl:when test="count(.|/)=1">Root</xsl:when>
                    <xsl:when test="count(.|../@*)=count(../@*)">Attribute</xsl:when>
                    <xsl:when test="count(.|../namespace::*)=count(../namespace::*)">Namespace</xsl:when>
                </xsl:choose>
            </td>
            <td>
                <xsl:value-of select="name()"/>
            </td>
            <th>
                <xsl:value-of select="."/>
            </th>
        </tr>
    </xsl:template>
</xsl:stylesheet>

Результат:

<html>
    <body>
        <table>
            <tr>
                <th>Type</th>
                <th>Name</th>
                <th>Value</th>
            </tr>
            <tr>
                <td>Attribute</td>
                <td>id</td>
                <th>34</th>
            </tr>
            <tr>
                <td>Attribute</td>
                <td>id</td>
                <th>35</th>
            </tr>
            <tr>
                <td>Attribute</td>
                <td>id</td>
                <th>36</th>
            </tr>
        </table>
    </body>
</html>

Примечание : было бы ошибкой, если $ node-set не является набором узлов.

Редактировать : Добавлен полный тест типа узла, чтобы доказать, что эта таблица стилей работает с любым выражением XPath, имеющим значение для набора узлов.

Редактировать 2 : Добавлено template/@mode, чтобы не пропустить root.

0 голосов
/ 07 июля 2010

Насколько мне известно / опыт работы с XSL, @id очень специфичен для контекста, поэтому для доступа к этой информации вы должны сначала получить правильный контекст, как вы показали выше через select="foo" или template match="foo".Ранее я сталкивался с этой проблемой в своей собственной работе, и это были единственные решения, которые мне удалось найти.

Однако, безусловно, есть более знающие люди XSL, чем я, поэтому, возможно, есть какой-то причудливый способЯ не знаю о - если так, то я хотел бы услышать это!

0 голосов
/ 07 июля 2010

Что происходит, когда вы используете <xsl:copy-of> вместо <xsl:value-of>?

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