Альтернативы XSLT-преобразованиям в Delphi XE8

Я пытаюсь выполнить преобразование XSLT с помощью Delphi XE8 и сталкиваюсь с проблемами. Мой XSL-файл ссылается на внешний XSL-файл с помощью оператора импорта, атрибут href которого имеет относительный путь. Преобразование завершается с ошибкой "Именованный шаблон "skrivUtDate" не отображается в таблице стилей". Определение 'skrivUtDate' находится во внешнем файле XSL. Определение выглядит следующим образом:

<xsl:template name="skrivUtDate">
    <xsl:param name="oppgittTid"/>
    <xsl:if test="string-length($oppgittTid)!=0">
        <xsl:value-of select="substring($oppgittTid,9,2)"/>.<xsl:value-of select="substring($oppgittTid,6,2)"/>.<xsl:value-of select="substring($oppgittTid,3,2)"/>
    </xsl:if>
</xsl:template>

Я поместил внешний XSL-файл в соответствующий каталог (относительно исходного XSL-файла), но получил ту же ошибку (я также перепробовал все возможные каталоги для этого внешнего файла, но ни один из них не сработал). Однако я могу выполнить преобразование с помощью редактора EditX XML, поэтому я не думаю, что XSL недействителен (обратите внимание, что этот файл XSL был предоставлен третьей стороной, и, по-видимому, он успешно используется некоторыми людьми, использующими платформы разработки, отличные от Дельфы).

Вот начальный сегмент файла XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:ref="http://www.kith.no/xmlstds/henvisning/2012-02-15" 
  xmlns:xhtml="http://www.w3.org/1999/xhtml" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:po="http://www.kith.no/xmlstds/po/poKomponent/2009-06-30" 
  xmlns:fk1="http://www.kith.no/xmlstds/felleskomponent1" 
  exclude-result-prefixes="ref xhtml po fk1">
    <xsl:import href="../../Felleskomponenter/funksjoner.xsl"/>

И да, файл funksjoner.xsl находится в каталоге Felleskomponenter.

В моем очень простом тесте используется что-то похожее на следующий псевдокод:

var
  XML : IXMLDocument;
  XSL : IXMLDocument;
  s: WideString;
begin
  XML := TXMLDocument.Create(self);
  XML.FileName := 'C:\somepath\some.xml';
  XML.Active := True;
  XSL := TXMLDocument.Create(Self);
  XSL.FileName := 'C:\someotherpath\somefile.xsl';
  XSL.Active := True;
  XML.DocumentElement.TransformNode(XSL.DocumentElement, s);

Я знаю, что Delphi XE7 начал поставляться с Omni XML DOM, а также с ADOM, но, по-видимому, они отсутствуют в Delphi XE8. Я надеялся, что использование другой объектной модели документа может решить проблему.

XML довольно сложен, как и XSL.

Есть ли у кого-нибудь предложения по альтернативным способам выполнения XSLT-преобразований с помощью Delphi XE8?


person Cary Jensen    schedule 21.09.2015    source источник
comment
MSXML, по-видимому, не может обрабатывать несколько слоев элементов ‹xsl:import› с относительными путями к файлам импорта (существует 3 уровня, с 2 импортами на третьем уровне, хотя эти файлы находятся в том же каталоге, что и файл из которые они импортируют). DIXML смог правильно проанализировать файлы XSL, и его было легко использовать, но преобразование вернуло AnsiString, что привело к искажению некоторых символов Unicode. Я разместил новый вопрос о DIXML здесь: stackoverflow.com/questions/32760579/   -  person Cary Jensen    schedule 24.09.2015


Ответы (3)


Для правильной работы XSLT в Delphi необходимо использовать MSXML для загрузки файлов XML и XSL. В этом сообщении приводится n пример использования MSXML с Delphi. TransformNode использует MSXML под капотом.

Что-то из следующего должно работать (взято отсюда, неполный фрагмент):

var
  xmlEmployees, xslStyle : IXMLDOMDocument;
begin
  xmlEmployees := CoDOMDocument.Create;
  xslStyle     := CoDOMDocument.Create;
  xmlEmployees.load('employees.xml');
  xslStyle.load('empuksna.xsl');
  result := xmlEmployees.transformNode(xslStyle);
end; 

Аналогичным образом, если вы загрузите XML и XSL через строку, исходное местоположение будет потеряно. Большинство процессоров поддерживают установку базового uri, но он выглядит так: IXSLProcessor не имеет такой опции.


Вы также просите альтернативу. DIXML поддерживает libxslt, который в некоторых отношениях превосходит MSXML (но не XSLT .NET, который является еще одной альтернативой, если вам нравится взаимодействие с .NET). Пакет DIXML поставляется с кучей демонстраций и примеров в папка демо.

Если вы можете переключиться на .NET, в этой (довольно старой) статье DrDobb показано, как выполнять XSLT с .NET. и Delphi, а также показывает еще один вариант преобразования (хотя предполагается, что это Delphi 7, но не уверен, что он все еще применим).

person Abel    schedule 21.09.2015
comment
Спасибо за ваш щедрый вклад. У меня это еще не работает - я все еще получаю ошибки в Delphi, хотя редактор EditX XML может выполнять преобразование. Я сообщу о своем прогрессе. - person Cary Jensen; 22.09.2015
comment
@CaryJensen, если вы работаете на современном компьютере с Windows, возможно, установленная версия MSXML не соответствует той версии, которую вы пытаетесь загрузить. В случае сбоя операций COM попробуйте загрузить MSXML. (обычно либо версия 3.0, либо 6.0, либо обе, другие версии проблематичны) - person Abel; 22.09.2015
comment
@CaryJensen, вы можете проверить установленные версии, используя XmlVersion.exe или Versions.exe. - person Abel; 22.09.2015
comment
По-прежнему никакой радости. К вашему сведению: я вызываю метод LoadXML для экземпляров IXMLDOMDocument, чтобы загрузить XML. Я получаю сообщение об ошибке: Таблица стилей не содержит элемент документа. Таблица стилей может быть пустой или может быть неправильно сформированным XML-документом. Есть элемент документа, и он выглядит правильно. Кстати, если я вызываю только метод Load, я получаю сообщение об ошибке, в котором говорится, что система не может найти указанный путь. - person Cary Jensen; 22.09.2015
comment
@cary, я полагаю, вы проверили таблицу стилей с помощью внешнего процессора командной строки и нашли ее правильной? Можете ли вы опубликовать точный минимальный код, который вы пытаетесь использовать в своем вопросе? - person Abel; 22.09.2015
comment
Я использую Windows 10 на виртуальной машине. XmlVersion не работает. Я вижу, что Delphi загружает MSXML3.dll. Я установил MSXML6, но из-за параллельной установки MSXML3 все еще используется модулем Delphi MSXML. Я запустил Version.exe, и, если я правильно понимаю, установлены все версии (от MSXML до MSXML6). Я не могу найти внешний валидатор таблицы стилей, который может обрабатывать эту таблицу стилей, потому что таблица стилей использует операторы импорта и ссылки на удаленное пространство имен для некоторых своих функций. К вашему сведению: DIXML также не может проанализировать таблицу стилей. Это довольно сложно. Поделюсь тем, что найду. - person Cary Jensen; 23.09.2015
comment
@CaryJensen, если DIXML не может проанализировать его как XML, возможно, он недействителен или вы нажали эта ошибка. URI пространства имен не разыменовываются, так что это не имеет значения. Ваша таблица стилей version="2.0"? XSLT 2.0 не поддерживается Microsoft. На информационной странице XSLT я перечислил множество процессоров командной строки, которые вы можете использовать (включая msxml.exe). Если вы не можете запустить свою таблицу стилей из командной строки, она точно не будет работать через код. - person Abel; 23.09.2015
comment
Абель: Я подозревал то же самое, что что-то в XSL-документе забавно, поскольку он не может обработать весь импорт (таблица стилей импортирует другую таблицу стилей, которая, в свою очередь, импортирует другую таблицу стилей). Я разговаривал с другим разработчиком, использующим те же таблицы стилей, и оказалось, что им пришлось внести некоторые незначительные изменения. Если эти изменения сработают, я отмечу ваш ответ как ответ, так как в том, что вы опубликовали, содержится много полезной информации. Спасибо! - person Cary Jensen; 23.09.2015
comment
Проблема заключалась в том, что таблицы стилей импортировали другие таблицы стилей из каталогов с использованием относительных путей, а эти относительные каталоги отсутствовали. Как только различные каталоги были размещены в нужных местах, DIXXML смог проанализировать таблицы стилей и преобразовать XML-файлы. MSXML не смог проанализировать таблицы стилей даже после исправления структуры каталогов. В итоге собираемся купить лицензию DIXML и пользоваться ею. - person Cary Jensen; 24.09.2015
comment
@cary, хотя это должно быть возможно, msxml очень старый, Microsoft предлагает использовать возможную версию .net. Купить лицензию, наверное, проще. - person Abel; 24.09.2015
comment
Я уже некоторое время работаю с DIXML, и хотя DIXML поддерживает Unicode, XSLT возвращает AnsiString, а результат преобразования содержит несколько неверных символов. Я пробовал несколько обходных путей с DIXML, но не понял, как вернуть строку Unicode. - person Cary Jensen; 24.09.2015
comment
@cary, давайте постараемся не допустить, чтобы эта ветка стала слишком длинной, в stackoverflow идея состоит в том, чтобы по одному вопросу на ветку, иначе более поздние посетители не смогут найти нужную информацию. Кроме того, это может привлечь других людей, которые больше разбираются в этом вопросе;) - person Abel; 24.09.2015

Вероятно, сейчас это излишне, но я обнаружил, что самый простой способ решить проблемы с импортом и включением пути — это использовать абсолютные пути.

Если используется относительный путь, он относится к каталогу установки msxml.exe, а не к вашему exe или корневому xsl. Это проблематично при переключении между разными серверами.

person Bryn Lewis    schedule 17.07.2020

Если вам нужно собственное кроссплатформенное решение: OXml предлагает механизм XSLT, полностью написанный на Delphi. / Паскаль. Однако это коммерческий продукт. (Я автор OXml.)

person oxo    schedule 27.07.2020