Как сортировать элементы и сохранять их в переменной, XSLT

Мне было интересно, можно ли сначала отсортировать некоторые элементы и сохранить их (уже отсортированные) в переменной. Мне нужно было бы ссылаться на них, как на XSLT, поэтому я хотел бы сохранить их в переменной.

Я пытался сделать следующее, но это, похоже, не работает

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

<xsl:variable name="deposits">
  <xsl:for-each select="/BookingCostings/MultiDeposits">
    <xsl:sort select="substring(@DepositDate, 1, 4)" />
    <xsl:sort select="substring(@DepositDate, 6, 2)" />
    <xsl:sort select="substring(@DepositDate, 9, 2)" />
 </xsl:for-each>
</xsl:variable>

Я пытался отсортировать элементы по @DepositDate в формате «гггг-мм-дд» и сохранить их все в переменной $deposits. Чтобы потом я мог получить к ним доступ с помощью $deposits[1].

Буду признателен за любую помощь и советы!

Большое спасибо!


person DashaLuna    schedule 16.02.2010    source источник
comment
Ваш вопрос указывает на то, что вы, вероятно, пытаетесь решить проблему неправильным путем в более широком масштабе. Почему вы хотите хранить отсортированный набор узлов в переменной? Что именно ты пытаешься сделать? (Я хочу получить к ним доступ, поскольку $deposits[1] — это не тот ответ, который мне нужен.)   -  person Tomalak    schedule 16.02.2010
comment
Томалак, к сожалению, я работаю с плохо структурированным XML. Есть депозиты, которые должны быть перечислены по порядку, а также они требуются в разных частях итогового документа. Атрибута для определения последовательности депозитов нет, и я решил не полагаться на позицию. Вот почему я решил отсортировать их и сохранить, чтобы я мог легко обращаться ко всем из них, когда мне это нужно. Надеюсь, это имеет смысл?   -  person DashaLuna    schedule 17.02.2010
comment
Да, это так. Иногда это просто так. Думали о промежуточном преобразовании, которое разумно реструктурирует неверный ввод, а затем строит на нем ваше окончательное преобразование? Может оказаться полезным в долгосрочной перспективе.   -  person Tomalak    schedule 17.02.2010


Ответы (3)


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

<xsl:variable name="deposits"> 
  <xsl:for-each select="/BookingCostings/MultiDeposits"> 
    <xsl:sort select="substring(@DepositDate, 1, 4)" /> 
    <xsl:sort select="substring(@DepositDate, 6, 2)" /> 
    <xsl:sort select="substring(@DepositDate, 9, 2)" /> 
    <xsl:copy-of select=".|@*" />
 </xsl:for-each> 
</xsl:variable> 

Это создает «набор узлов», но для доступа к нему вам потребуется использовать функцию расширения в XSLT. Какой из них вы используете, зависит от процессора XSLT, который вы используете. В примере, который я собираюсь привести, я использую Microsoft.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt" version="1.0"> 

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

<xsl:value-of select="ms:node-set($deposits)/MultiDeposits[1]/@DepositDate" />

Вот хорошая статья, чтобы прочитать о наборах узлов

статья Xml.com о наборах узлов

person Tim C    schedule 16.02.2010
comment
Тим прав, что внутри вашего for-each вам нужно что-то вывести, если вы хотите заполнить переменную, поэтому используйте это ‹xsl:copy-of select=./› внутри for-each. Однако тип переменной не является набором узлов, а скорее фрагментом результирующего дерева. Только путем вызова функции расширения для переменной фрагмент результирующего дерева преобразуется в набор узлов, к которому можно применить XPath. - person Martin Honnen; 16.02.2010
comment
Спасибо вам, ребята! Да, мне определенно нужен ‹xsl:copy-of select=./›. Тим, спасибо за статью, она была полезной. Мартин, вы случайно не знаете, как хорошо читать фрагменты дерева и как разные функции работают с документом? Или, если на то пошло, какую-либо информацию о XSLT в целом? Я был бы очень признателен. Просто пытаюсь понять все это лучше :) - person DashaLuna; 17.02.2010

  1. Используя XSLT version 2.0, вы можете использовать perform-sort и сказать, что ваша переменная имеет тип последовательности MultiDeposits, используя as keyword (as="element(MultiDeposits)+")
  2. Поскольку ваши данные уже имеют формат гггг-мм-дд, вы можете не использовать подстроку для получения каждой части даты и использовать сортировку непосредственно в поле.

с этим образцом XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<BookingCostings>
  <MultiDeposits depositDate="2001-10-09">1</MultiDeposits>
  <MultiDeposits depositDate="1999-10-09">2</MultiDeposits>
  <MultiDeposits depositDate="2010-08-09">3</MultiDeposits>
  <MultiDeposits depositDate="2010-07-09">4</MultiDeposits>
  <MultiDeposits depositDate="1998-01-01">5</MultiDeposits>
</BookingCostings>

и используя лист XSLT версии 2.0:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="/">
 <html>
  <body>

  <xsl:variable name="deposits" as="element(MultiDeposits)+">
   <xsl:perform-sort select="BookingCostings/MultiDeposits">
    <xsl:sort select="@depositDate"/>
   </xsl:perform-sort>
  </xsl:variable>

  first date:<xsl:value-of select="$deposits[1]/@depositDate"/>,
  last date:<xsl:value-of select="$deposits[last()]/@depositDate"/>

  </body>
 </html>
 </xsl:template>

</xsl:stylesheet>

вывод будет таким:

first date:1998-01-01, last date:2010-08-09
person Patrick    schedule 16.02.2010
comment
Спасибо, Патрик. Я предполагаю, что as=element(MultiDeposits)+ невозможно в XSLT 1.0? К сожалению, у меня нет даты в формате гггг-мм-дд. Я использую функцию в каждом операторе сортировки перед функцией подстроки. Я не упомянул об этом, чтобы немного упростить код. Я пытался использовать локальную переменную перед оператором сортировки со всей датой, преобразованной в гггг-мм-дд, но, по-видимому, инструкция сортировки должна быть первой. Так да. Спасибо за ответ :) - person DashaLuna; 17.02.2010
comment
К сожалению нет, это только 2.0. - person Patrick; 17.02.2010
comment
@ Патрик, а что, если у него есть пространство имен. Я получаю Required item type of value of variable $xx is element(Q{}yy); supplied value has item type element(Q{http://www.w3.org/1999/xhtml}yy). - person rdonuk; 01.08.2019

Угадайте (нет dev env под рукой):

Добавить <xsl:value-of select="." />

Перед закрытием </xsl:for-each>

person Murph    schedule 16.02.2010