Проблема с использованием функции xslt key ()

#xml #xslt #indexing #key

#xml #xslt #индексирование #Клавиша

Вопрос:

(отредактировано с учетом предложений Мартина Хоннена)

Всем привет,

Я пытался заставить функцию key корректно работать в таблице стилей ниже.

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date"
        xmlns:fo="http://www.w3.org/1999/XSL/Format"
        xmlns:m="http://mapping.tables" >


<xsl:key name="preferences" match="preferences/preference" use="@code"/>

<xsl:template match="Reservation/Detail" >
    <xsl:for-each select="Preferences/Preference">
        <xsl:if test ="string-length(./PreferenceCode)>0">

            amp;#160;amp;#160;amp;#160;amp;#160;* (<xsl:value-of select="./PreferenceCode"/>)

            <xsl:choose>
                <xsl:when test="./PreferenceCode!='PETS'">

                    <xsl:call-template name="prefmap">
                            <xsl:with-param name="code" select="./PreferenceCode"/>
                    </xsl:call-template>

                    <br/><br/>
                </xsl:when>
            </xsl:choose>
        </xsl:if>
    </xsl:for-each>
</xsl:template


<xsl:template name="prefmap">
        <xsl:param name="code"/>
        You got here (called template) with code <xsl:value-of select="$code"/>
              <xsl:for-each select="document('')">
        <xsl:value-of select="key('preferences',$code)"/>
    </xsl:for-each>
</xsl:template>

<m:Maps xmlns="">
<preferences>
        <preference code="ANT">
                Hypoallergenic Bedding
        </preference>
        <preference code="NSK">
                Non-smoking Room
        </preference>
        <preference code="SMK">
                Smoking Room
        </preference>
</preferences>
</m:Maps>

</xsl:stylesheet>
  

Он принимает входные данные (которые я не контролирую) и выдает это:

 * (ANT) You got here (called template) with code ANT


* (EARLY) You got here (called template) with code EARLY


* (NSK) You got here (called template) with code NSK
  

Когда я ожидал:

 * (ANT) You got here (called template) with code ANT
  Hypoallergenic Bedding

* (EARLY) You got here (called template) with code EARLY

* (NSK) You got here (called template) with code NSK
Non-smoking Room
  

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

             <xsl:for-each select="key('preferences',./PreferenceCode)">
                <p>
                    Code: <xsl:value-of select="@code"/><br />
                    Description: <xsl:value-of select="."/>
                </p>
            </xsl:for-each>
  

У меня проблема с моим определением ключа или с тем, как я пытаюсь его использовать?

Заранее всем спасибо.

Комментарии:

1. Не могли бы вы, пожалуйста, предоставить (минимально возможный) XML-документ, к которому можно применить это преобразование?

2. Ваша проблема не воспроизводима — я запустил ваше преобразование на 7 разных процессорах XSLT, которые я использую ежедневно. Все они выдали один и тот же правильный результат.

Ответ №1:

Вы пытаетесь поместить данные в свою таблицу стилей с помощью этих preferences/pref элементов? Разве они не должны находиться в отдельном пространстве имен? И ключи создаются для каждого документа, и key функция с XSLT 1.0 ищет узлы в документе, к которому принадлежит контекстный узел. Если вы хотите просмотреть узлы в самой таблице стилей, то сначала вам нужно изменить контекстный узел, например, <xsl:for-each select="document('')"><xsl:value-of select="key('preferences', $code)"/></xsl:for-each> . Затем удалите начало / из match значения атрибута и убедитесь, что вы поместили элементы в элемент контейнера в отдельном пространстве имен, например

 <xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date"
        xmlns:fo="http://www.w3.org/1999/XSL/Format"
        xmlns:m="http://mapping.tables" 
        xmlns:data="http://example.com/data">


<xsl:key name="preferences" match="preferences/pref" use="@code"/>

<data:data xmlns="">
<preferences>
        <pref code="ANT">
                Hypoallergenic Bedding
        </pref>
        <pref code="NSK">
                Non-smoking Room
        </pref>
        <pref code="SMK">
                Smoking Room
        </pref>
</preferences>
</data:data>
  

Комментарии:

1. Спасибо за быстрый ответ. Я применил ваши предложения к работе, но без радости. Теперь я получаю java.lang. Исключение NullPointException всякий раз, когда оно попадает в эту конкретную часть логики. К сожалению, у меня нет доступа ни к одному из серверных интерфейсов, кроме возможности загружать таблицу стилей, поэтому я не могу получить трассировку стека или какую-либо более подробную информацию об ошибках, пока администратор компьютера не свяжется со мной. Однако я буду продолжать работать.

2. Мартин, я не хочу показаться дотошным, но будет ли <xsl:for-each>, который ссылается на фрагмент документа («), который вы предлагаете, помещен в шаблон ‘prefmap’?

3. Саймон, for-each фрагмент должен заменить <xsl:value-of select="key('preferences',$code)"/> .

4. И убедитесь, что у вас есть xmlns="" на m:Maps элементе, содержащем эти preferences элементы, иначе ваш ключ не будет работать.

5. Спасибо. Я внес изменения выше, но я все еще получаю java.lang. Исключение NullPointerException при попытке выполнить поиск.

Ответ №2:

У меня проблема с моим определением ключа или с тем, как я пытаюсь его использовать?

Ни с одним из них проблем нет:

Я не могу воспроизвести сообщенный результат. Это означает, что если действительно есть какая-либо проблема, то она в коде, который нам не показан.

Предоставленное преобразование:

 <xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  xmlns:m="http://mapping.tables" >

    <xsl:key name="preferences" match="preferences/preference" use="@code"/>

    <xsl:template match="Reservation/Detail" >
        <xsl:for-each select="Preferences/Preference">
            <xsl:if test ="string-length(./PreferenceCode)>0">              amp;#160;amp;#160;amp;#160;amp;#160;* (
                <xsl:value-of select="./PreferenceCode"/>)              
                <xsl:choose>
                    <xsl:when test="./PreferenceCode!='PETS'">
                        <xsl:call-template name="prefmap">
                            <xsl:with-param name="code" select="./PreferenceCode"/>
                        </xsl:call-template>
                        <br/>
                        <br/>
                    </xsl:when>
                </xsl:choose>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    <xsl:template name="prefmap">
        <xsl:param name="code"/>         You got here (called template) with code 
        <xsl:value-of select="$code"/>
        <xsl:for-each select="document('')">
            <xsl:value-of select="key('preferences',$code)"/>
        </xsl:for-each>
    </xsl:template>
    <m:Maps xmlns="">
        <preferences>
            <preference code="ANT">
              Hypoallergenic Bedding
            </preference>
            <preference code="NSK">
             Non-smoking Room
            </preference>
            <preference code="SMK">
             Smoking Room
            </preference>
        </preferences>
    </m:Maps>
</xsl:stylesheet>
  

при применении к следующему XML-документу (в вопросе не был предоставлен XML-документ!):

 <Reservation>
    <Detail>
        <Preferences>
            <Preference>
              <PreferenceCode>ANT</PreferenceCode>
            </Preference>
            <Preference>
              <PreferenceCode>NSK</PreferenceCode>
            </Preference>
            <Preference>
              <PreferenceCode>SMK</PreferenceCode>
            </Preference>
            <Preference>
              <PreferenceCode>PETS</PreferenceCode>
            </Preference>
        </Preferences>
    </Detail>
</Reservation>
  

выдает именно ожидаемый результат:

 <?xml version="1.0" encoding="utf-8"?>
                      * (
                ANT)              
                         You got here (called template) with code 
        ANT
              Hypoallergenic Bedding
            <br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/><br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/>                  * (
                NSK)              
                         You got here (called template) with code 
        NSK
             Non-smoking Room
            <br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/><br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/>                  * (
                SMK)              
                         You got here (called template) with code 
        SMK
             Smoking Room
            <br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/><br xmlns="http://www.w3.org/1999/xhtml" xmlns:date="http://www.oracle.com/XSL/Transform/java/java.util.Date" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:m="http://mapping.tables"/>                  * (
                PETS)              
  

Обратите внимание:

Все следующие 7 процессоров XSLT выдают точно такой же результат (приведенный выше): MSXML3/ 4, XslCompiledTransform, XslTransform, Saxon 6.5.4, Saxon 9.1.05, AltovaXML (XMLSpy).

Комментарии:

1. Спасибо! Я укажу на это разработчику приложения, чтобы им было над чем работать. Выдающиеся усилия Дмитрия и с благодарностью!

2. @Simon: Рад, что мой вопрос был полезен. Здесь, в SO, официальной формой выражения благодарности является принятие правильного ответа. Это делается нажатием на зеленую галочку рядом с ответом. 🙂

3. Кстати, образец XML, который вы прогнали через преобразование, по сути, является именно тем, чем он должен быть как часть в «реальном» документе. Кроме того, если это вообще помогает, мы привыкли обрабатывать настройки с помощью блока <xsl:choose>, который работал довольно хорошо. Основная причина переключения — это просто огромное количество настроек, которые нам теперь нужно включить, которое увеличилось с 5 до 30. Сопоставление (key()) казалось наиболее приемлемым в долгосрочной перспективе, но мы открыты для любых других предложений.

4. @Simon: Как я доказал, это невозможно воспроизвести на основе предоставленных в данный момент данных.

5. Могу ли я принять оба ответа, поскольку оба были очень полезны? Я пытался проголосовать за оба, но моя репутация слишком низкая. 🙁