Тест XSL на наборе узлов?

#xslt #xpath

#xslt #xpath

Вопрос:

У меня есть набор узлов «file» с атрибутом type

 <files>
    <file type="main">asdf</file>
    <file type="main_en">asdf</file>
    <file type="main_fr">asdf</file>
    <file type="pdf">asdf</file>
</files>
  

Как мне проверить на наборе файлов, имеет ли один из узлов хотя бы 1 атрибут, начинающийся с «main».
Я думал что-то вроде:

 <xsl:when test="contains(string(files/file[@type]),'main')">
  

Но все известные мне функции или тесты, похоже, предназначены только для определенного узла, а не для набора узлов.
Я бы предпочел избежать использования решения a для каждого типа.

Ответ №1:

Как мне проверить на наборе файлов, имеет ли один из узлов хотя бы 1 атрибут, начинающийся с «main».

Использовать:

 boolean(/*/file[@*[starts-with(., 'main')]])
  

Это вычисляется true() точно, когда есть хотя бы один file элемент, который является дочерним элементом верхнего элемента XML-документа и который имеет хотя бы один атрибут, строковое значение которого начинается со строки "main"

При использовании в test атрибуте ( <xsl:if> или <xsl:when> ) или в качестве предиката ссылка на boolean() функцию необязательна и может быть опущена:

 /*/file[@*[starts-with(., 'main')]]
  

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

1. По какой-то причине он возвращает false, когда я пытаюсь это сделать.

2. Я подумал, есть ли способ, которым я мог бы объединить все типы с разделителем в переменную и просто выполнить contains($var,’main’). Но я не уверен, как это сделать.

3. Да, я использовал fn: starts-with вместо starts-with .. не думал, что это что-то изменит. Спасибо 🙂

4. @Jaycuse: Рад, что вы нашли причину своей проблемы. Может быть, пришло время подумать о том, чтобы принять лучший ответ? 🙂

Ответ №2:

 <xsl:when test="files/file[contains(@type, 'main')]">
  

Или, еще лучше:

 <xsl:when test="files/file[starts-with(@type, 'main')]">
  

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

1. Хм, не знаю, как за это проголосовали… Я проверял имя атрибута вместо его значения! Исправление.

2. Я попробовал это, и это выдало мне эту ошибку: java.lang. Исключение NoSuchMethodException: для функции расширения не удалось найти метод org.apache.xpath.objects. XNodeSet.StartsWith([ExpressionContext,] #СТРОКА).

3. Интересно — я понятия не имею, почему вы получили эту ошибку, но после просмотра xpath, который был результатом моего первого исправления, это все еще было немного сложно. Я только что исправил это, но понятия не имею, устранит ли это описанную вами ошибку — боюсь, у меня нет среды Xalan для игры.

4. По сравнению с ответом Димитра было бы то, что добавление / перед файлами сделало бы его таким же, за исключением более конкретного. И это работает, но по какой-то причине возвращает false . <xsl:when test="/files/file[starts-with(@type, 'main')]">

5. О .. это была моя ошибка.. Я использовал fn: starts-with против starts-with .. не думал, что это что-то изменит. Спасибо 🙂

Ответ №3:

Не знаете своей реальной цели, но этот пример может вам помочь:

  <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/files">
        <xsl:if test="file[contains(@type,'main')]">
            There is at least one file element with 'main' in @type
        </xsl:if>
  </xsl:template>


</xsl:stylesheet>
  

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

1. В конце концов, я просто хочу, чтобы код в if выполнялся один раз. Вот почему я хочу избежать a для каждого. Потому что он будет выполняться 3 раза. Вроде как, если есть хотя бы один основной файл. Сделайте это один раз, в противном случае сделайте это один раз.