Не удается получить доступ к обновленному объекту Java из процессора Saxon XSLT

Я работаю с версией процессора Saxon XSLT с открытым исходным кодом «Saxon 9.0.0.2J от Saxonica» и впервые пытаюсь использовать расширяемость Java. Я столкнулся с проблемой, которая, как я подозреваю, может быть ограничением версии с открытым исходным кодом, но я хотел сначала проверить, может ли быть что-то, что я просто упускаю здесь.

Из фрагмента ниже мой вывод состоит в том, что окончательное значение $c1 не изменяется в результате вызова greg:setTime() - т. е. переменная $c1 в Saxon кажется отсоединенной от базового объекта Java, и существует нет очевидного способа получить доступ к объекту, обновленному вызовом setTime().

ОБРАТИТЕ ВНИМАНИЕ, что весь код во фрагменте проверен и работает иначе, т. е. экземпляр $c1 правильно создается вызовом getInstance(), $startdate имеет правильный формат, а экземпляр $d1 создается правильно.

Мысли?

<xsl:transform
       .....
       xmlns:sql="java:java.sql.Date"
       xmlns:greg="java:java.util.GregorianCalendar"
       .....
>
....
<xsl:element name="JobExpireDate">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf($startdate)" />
      <xsl:variable name="void" select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="$c1" />
</xsl:element>

person Chip Kaye    schedule 13.04.2010    source источник
comment
Можете ли вы привести краткий самодостаточный пример файла ввода XML и файла преобразования XSL?   -  person Christian Semrau    schedule 14.04.2010
comment
Сам нашел пример. Смотрите мой ответ.   -  person Christian Semrau    schedule 14.04.2010


Ответы (2)


Я только что попробовал с saxonb9-0-0-8j.

Вызовы функций void иногда игнорируются, как показано ниже.

Входной файл:

<root>
<date1>2009-01-02</date1>
<date2>2009-01-02</date2>
</root>

Преобразование:

 <xsl:transform
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:sql="java:java.sql.Date"
       xmlns:greg="java:java.util.GregorianCalendar"
 version="2.0">

<xsl:template match="*">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="root/date1/text()">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf(.)" />
      <xsl:variable name="void" select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="greg:getTime($c1)" />
</xsl:template>

<xsl:template match="root/date2/text()">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf(.)" />
      <xsl:value-of select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="greg:getTime($c1)" />
</xsl:template>

</xsl:transform>

Результат:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<date1>2010-04-14T08:23:25.341Z</date1>
<date2>2009-01-01T23:00:00Z</date2>
</root>

Так что похоже, что setTime() вызывается не для даты1, а для даты2.

У Saxon есть хорошая функция explain, которая отображает проанализированное преобразование в удобочитаемом формате:

...
<templateRule match="root/date2/text()" precedence="0" priority="0.5" line="21"
              module="file:/C:/devtools/saxonb9-0-0-8j/template.xsl">
  <let variable="c1" as="java:java.util.Calendar?">
    <be>
      <functionCall name="greg:getInstance"/>
    </be>
    <return>
      <sequence>
        <valueOf>
          <simpleContentConstructor>
            <functionCall name="greg:setTime">
              <variableReference name="c1"/>
              <functionCall name="sql:valueOf">
                <dot/>
              </functionCall>
            </functionCall>
            <literal value=" " type="xs:string"/>
          </simpleContentConstructor>
        </valueOf>
        <valueOf>
          <simpleContentConstructor>
            <functionCall name="greg:getTime">
              <variableReference name="c1"/>
            </functionCall>
            <literal value=" " type="xs:string"/>
          </simpleContentConstructor>
        </valueOf>
      </sequence>
    </return>
  </let>
</templateRule>
<templateRule match="root/date1/text()" precedence="0" priority="0.5" line="14"
              module="file:/C:/devtools/saxonb9-0-0-8j/template.xsl">
  <valueOf>
    <simpleContentConstructor>
      <functionCall name="greg:getTime">
        <functionCall name="greg:getInstance"/>
      </functionCall>
      <literal value=" " type="xs:string"/>
    </simpleContentConstructor>
  </valueOf>
</templateRule>
...

Как видите, для даты1 вызов setTime() игнорируется, но есть для даты2.

person Christian Semrau    schedule 14.04.2010
comment
О боже, Кристиан, тебе это понравится. Я некоторое время ломал голову над этим, прежде чем понял, что вы нашли решение с помощью вырезания и вставки. Обратите внимание, что ваш шаблон для date2 вызывает setTime через ‹xsl:value-of›, а шаблон для date1 вызывает через ‹xsl:variable›, как в моем исходном фрагменте. Ваш измененный шаблон date2 приводит к успешному вызову. Я перенес эту логику в свое преобразование, и теперь все работает. Большое спасибо за вашу вторую пару глаз и вашу ошибку вырезания и вставки! - person Chip Kaye; 14.04.2010
comment
Извините, что не объяснил разницу. :-) Я поигрался с разными способами вызова функции Java, и вариант date2 сработал. Но я не знаю почему. - person Christian Semrau; 15.04.2010

Вы вызываете setTime в GregorianCalendar с аргументом java.sql.Date? Разве это не должно потерпеть неудачу? Или происходит какое-то скрытое преобразование?

Если это не удается, может быть, Saxon молча игнорирует ошибку?

Я заметил, что в некоторых версиях Xalan вызовы функций void игнорируются компилятором XSLT. Саксон может вести себя аналогично.

person Christian Semrau    schedule 13.04.2010
comment
Спасибо, Кристиан. Я не верю, что это должно потерпеть неудачу - java.sql.Date является прямым подклассом java.util.Date. Кроме того, любой вызов установки отдельного поля в объекте календаря дает тот же необновленный результат для $c1, поэтому я думаю, что мы имеем дело с проблемой более высокого уровня, связанной с тем, как экземпляры объекта/переменной связаны между Java и Saxon. - person Chip Kaye; 13.04.2010
comment
Я никогда не использовал java.sql.Date напрямую, поэтому никогда не замечал, что это подкласс. :-) Тогда вы правы: тип аргумента не является причиной. - person Christian Semrau; 14.04.2010