Я работал с продуктом, который сразу же выводит «необработанный» системный журнал XML в собственный (но простой) формат XML, и нам нужно преобразовать часть информации в некоторых сообщениях.
Этот продукт поддерживает возможность настройки преобразования «необработанного» XML в форматы, адаптированные для продуктов SIEM, таких как Splunk и ArcSight, с использованием одного XSLT:
Продукт ==> «необработанный» вывод системного журнала XML ==> XSLT, специфичный для SIEM ==> SIEM (например, ArcSight, Splunk и т. д.)
Теперь у нас есть требование изменить ОДИН из элементов XML в некоторых необработанных сообщениях системного журнала, прежде чем сообщения будут преобразованы XSLT, «специфичным для SIEM». Итак, мы хотим иметь такой поток:
Продукт ==> «необработанный» вывод системного журнала XML ==> преобразованный «нашим XSLT» ==> преобразованный «XSLT, специфичным для SIEM, предоставленным поставщиком продукта» ==> SIEM (например, ArcSight, Splunk и т. д.)
Я работал над XSLT «нашего XSLT» (чтобы просто преобразовать этот один элемент, который затем будет передан в XSLT, специфичный для SIEM), и публиковал сообщения в одном из списков рассылки XSLT, и в одном из ответов я понял, кто-то упомянул о возможном использовании/использовании XProc для обеспечения «цепочки XSLT», поэтому я кое-что прочитал, но у меня все еще есть некоторые вопросы по поводу XProc...
а) Поскольку мы имеем дело с существующим продуктом в качестве источника XML системного журнала и поскольку нам необходимо использовать процессор XSLT, встроенный в продукт, который, по-видимому, использует XALAN-C v1, мы, к сожалению, ограничены используя XSLT 1.0.
Помешает ли это нам использовать XPoc?
б) Кроме того, я занимался разработкой XSLT в системе CENTOS и тестировал свой XSLT с помощью xsltproc, а затем, после того как я наладил работу с xsltproc, я тестировал XSLT с самим продуктом.
В рамках процесса разработки XSLT и обсуждений в списке рассылки XSLT я подтвердил, что механизм XSLT, используемый в продукте, — это XALAN-C, а также, что функция exslt:set-node() доступна и работает в как в xsltproc, так и в самом продукте.
Мое первоначальное намерение состояло в том, чтобы попытаться реализовать цепочку XSLT в нашем коде XSLT, но после некоторых исследований того, что будет задействовано, оказалось, что нам, по сути, придется как бы воспроизвести некоторые функции, которые уже предоставляются XProc, поэтому Я хочу попытаться использовать XProc для нашей работы, и я хочу попытаться заставить цепочку XSLT работать с XProc вместе с нашим XSLT и XSLT, предоставленным поставщиком продукта для SIEM.
Я публикую приведенную выше информацию, но я также хотел проверить, учитывая имеющиеся у нас ограничения (например, ограничение XSLT 1.0), есть ли какие-либо ошибки при использовании XProc для выполнения того, что я описал, в нашем случае?
в) Кроме того, я видел некоторые упоминания о Java... Если предположить, что продукт, с которым мы работаем, поддерживает XSLT 1.0, включая set-node(), понадобится ли Java для использования XProc в этом продукте?
Буду рад любым отзывам и заранее спасибо!
РЕДАКТИРОВАТЬ 1: Я как бы напутал в своем исходном посте в строке, где пытался показать «поток» XSLT... Пользовательский интерфейс SO заставлял часть текста исчезать. Сейчас я исправил эту строчку...
Обновлено еще раз: Я думаю, что мы близки к тому, что может работать с XSLT, опубликованным Коналом, но, судя по моим комментариям в ответ Коналу, я получаю эту ошибку:
It is an error to call 'apply-imports' when there's no current template rule.
error: file EmptyDetailsauditrecord.xml
xsltRunStylesheet : run failed
и я не понимаю, что вызывает эту ошибку... но у меня есть вопрос... с подходом, который предлагает Конал, требуется ли, чтобы XSLT " Third-party-stylesheet.xsl" был МОДИФИЦИРОВАН для добавления "режим" для всех шаблонов xsl:... ВНУТРИ "стороннего файла stylesheet.xsl"??? Кажется, ошибка говорит о том, что в импортированном XSLT нет совпадающих шаблонов, поэтому мне интересно, может быть, причина отсутствия совпадений заключается в том, что ни один из шаблонов xsl:template внутри «стороннего файла» stylesheet.xsl» имеет mode="pre-process" ???
РЕДАКТИРОВАТЬ 3:
Ниже приведен текущий файл конвейера.xsl после того, как я добавил код из своего XSLT в файл конвейера.xsl, а также добавил дополнительный режим="pre-process". Pipeline.xsl теперь запускается без ошибок, но по сути он принимает входной XML и преобразует его с помощью стороннего файла stylesheet.xsl вместо того, чтобы сначала выполнить преобразование, которое находится в самом конвейере.xsl, а затем выполнение стороннего файла stylesheet.xsl.
<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:exslt = "http://exslt.org/common"
exclude-result-prefixes = "exslt"
version = "1.0">
<xsl:import href = "./third-party-stylesheet.xsl"/>
<xsl:template mode = "pre-process" match = "/">
<xsl:variable name = "pre-processed-xml">
<xsl:apply-templates mode = "pre-process" select = "/" />
</xsl:variable>
<xsl:message><xsl:value-of select = "$pre-processed-xml"/></xsl:message>
<xsl:for-each select = "exslt:node-set($pre-processed-xml)">
<!-- apply the imported templates to the pre-processed-xml -->
<xsl:apply-imports/>
</xsl:for-each>
</xsl:template>
<!-- pre-processor generally copies the input -->
<xsl:template match = "@*|node()" mode = "pre-process">
<xsl:copy>
<xsl:apply-templates mode = "pre-process" select = "@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- THE CODE BELOW IS WHAT WAS ORIGINALLY IN "my XSLT" -->
<!-- Handle processing of <ExtraDetails>... -->
<xsl:template match = "/syslog/audit_record/ExtraDetails">
<!-- SET GLOBAL VARIABLE $incomingMessageID... -->
<xsl:variable name = "incomingMessageID" select = "/syslog/audit_record/MessageID"/>
<!-- SET GLOBAL VARIABLE $incomingExtraDetails... -->
<xsl:variable name = "incomingExtraDetails" select = "/syslog/audit_record/ExtraDetails"/>
<xsl:message>+++++++++ UPON ENTERING template match - incomingExtraDetails: [<xsl:value-of select = "$incomingExtraDetails"/>]</xsl:message>
<ExtraDetails>
.
.
.
.
</ExtraDetails>
</xsl:template>
</xsl:stylesheet>
РЕДАКТИРОВАТЬ 4A: Первый запуск XSLT (initialparsetestSMALL.xsl):
<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:exslt = "http://exslt.org/common"
exclude-result-prefixes = "exslt"
version = "1.0">
<!-- SET GLOBAL VARIABLE $incomingMessageID... -->
<xsl:variable name = "incomingMessageID" select = "/syslog/audit_record/MessageID"/>
<!-- SET GLOBAL VARIABLE $incomingExtraDetails... -->
<xsl:variable name = "incomingExtraDetails" select = "/syslog/audit_record/ExtraDetails"/>
<!-- Identity Transform -->
<xsl:template match = "@*|node()">
<xsl:copy>
<xsl:apply-templates select = "@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Handle processing of <ExtraDetails>... -->
<xsl:template match = "/syslog/audit_record/ExtraDetails">
<ExtraDetails>
<xsl:choose>
<xsl:when test = "$incomingMessageID = '412'">
<xsl:variable name = "before-tab" select = " substring-before( substring-after($incomingExtraDetails, '='), '[Tab]' ) "/>
<xsl:variable name = "after-tab" select = " substring-before( substring-after($incomingExtraDetails, '[Tab]'), ';') "/>
<xsl:variable name = "front" select = " substring-before($incomingExtraDetails, '=')"/>
<xsl:variable name = "frontEqual" select = "concat($front, '=')"/>
<xsl:variable name = "back" select = " substring-after($incomingExtraDetails, ';')"/>
<xsl:variable name = "redacted" select = "'************;'"/>
<xsl:variable name = "newExtraDetails" select = "concat($frontEqual,$redacted)"/>
<xsl:variable name = "newExtraDetailsAll" select = "concat($newExtraDetails,$back)"/>
<xsl:value-of select = "$newExtraDetailsAll"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test = "$incomingExtraDetails = ''">
<xsl:message>+++++++++++++++++++++++++++++ incomingExtraDetails is null</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:message>+++++++++++++++++++++++++++++++++++++ NOT 412</xsl:message>
<xsl:value-of select = "$incomingExtraDetails"/>
<xsl:message>+++++++++++++++++++++++++++++++++++++ DONE NOT 412</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</ExtraDetails>
</xsl:template>
</xsl:stylesheet>
РЕДАКТИРОВАТЬ 4B: второй/последний XSLT для запуска (сторонний-stylesheet.xsl) - обратите внимание, что этот XSLT производит текстовый вывод:
<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:import href='./RFC5424Changes.xsl'/>
<xsl:output method='text' version='1.0' encoding='UTF-8'/>
<xsl:key name = "CAProperty_Name" match = "CAProperty" use = "@Name"/>
<xsl:template match = "/">
<xsl:apply-imports/>
<xsl:for-each select = "syslog/audit_record"><xsl:if test = "not(key('CAProperty_Name','KeyDescription')) and not(key('CAProperty_Name','ApplicationObjectID')) and (Action = 'Retrieve password' or Action = 'Use Password' or Action = 'Retrieve SSH Key' or Action = 'CPM Change Password' or Action = 'CPM Reconcile Password')">|<xsl:value-of select = "Issuer"/>|<xsl:value-of select = "IsoTimestamp"/>|<xsl:value-of select = "Action"/>|<xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'UserName'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'Address'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'PolicyID'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'DeviceType'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'Database'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'AWSAccountID'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'AWSAccessKeyID'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'ActiveDirectoryID'" /></xsl:call-template>
</xsl:if>
</xsl:for-each>
<xsl:for-each select = "syslog/audit_record"><xsl:if test = "Action = 'Logon' or Action = 'User Authentication'">|<xsl:value-of select = "Issuer"/>|<xsl:value-of select = "IsoTimestamp"/>|<xsl:value-of select = "Action"/>|<xsl:value-of select = "Station"/>|</xsl:if>
</xsl:for-each>
<xsl:for-each select = "syslog/audit_record"><xsl:if test = "Action = 'Store password' or Action = 'Store SSH Key'">|<xsl:value-of select = "IsoTimestamp"/>|<xsl:value-of select = "Action"/>|<xsl:value-of select = "Safe"/>|<xsl:value-of select = "File"/>|</xsl:if>
</xsl:for-each>
<!-- MessageID = '361' is Command Audit -->
<!-- MessageID = '359' is Command Audit -->
<!-- MessageID = '302' is Disconnect Audit -->
<xsl:for-each select = "syslog/audit_record"><xsl:if test = "MessageID = '361' or MessageID = '359' or MessageID = '411' or MessageID = '412' or MessageID = '436' or MessageID = '300' or MessageID = '302'">|<xsl:value-of select = "Issuer"/>|<xsl:value-of select = "IsoTimestamp"/>|<xsl:value-of select = "MessageID"/>|<xsl:value-of select = "Action"/>|<xsl:value-of select = "Station"/>|<xsl:value-of select = "File"/>|<xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'PolicyID'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'Address'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'DeviceType'" /></xsl:call-template><xsl:call-template name = "print-file-category"><xsl:with-param name = "category-name" select = "'Database'" /></xsl:call-template><xsl:value-of select = "ExtraDetails"/>|</xsl:if>
</xsl:for-each>
<!-- MessageID = '471' is Access Succeeded Syslog -->
<xsl:for-each select = "syslog/audit_record"><xsl:if test = "MessageID = '471'">|<xsl:value-of select = "IsoTimestamp"/>|<xsl:value-of select = "MessageID"/>|<xsl:value-of select = "Issuer"/>|<xsl:value-of select = "Action"/>|<xsl:value-of select = "Station"/>|<xsl:value-of select = "ExtraDetails"/>|</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- replace all occurences of the character(s) `from'
by the string `to' in the string `string'.-->
<xsl:template name = "string-replace" >
<xsl:param name = "string"/>
<xsl:param name = "from"/>
<xsl:param name = "to"/>
<xsl:choose>
<xsl:when test = "contains($string,$from)">
<xsl:value-of select = "substring-before($string,$from)"/>
<xsl:value-of select = "$to"/>
<xsl:call-template name = "string-replace">
<xsl:with-param name = "string" select = "substring-after($string,$from)"/>
<xsl:with-param name = "from" select = "$from"/>
<xsl:with-param name = "to" select = "$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select = "$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name = "print-file-category">
<xsl:param name = "category-name"/>
<xsl:param name = "print-pipe-if-empty" select = "true()"/>
<xsl:variable name = "out">
<xsl:for-each select = "CAProperties/CAProperty">
<xsl:choose>
<xsl:when test = "@Name=$category-name">
<xsl:value-of select = "@Value" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select = "$out" />
<xsl:choose>
<xsl:when test = "$print-pipe-if-empty and $out=''">|</xsl:when>
<xsl:when test = "$out!=''">|</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
РЕДАКТИРОВАТЬ 4C: Пример ввода XML (sample-syslog-message.xml):
<?xml version = "1.0" encoding = "UTF-8"?>
<syslog>
<audit_record>
<Rfc>yes</Rfc>
<Timestamp>Jul 21 01:10:30</Timestamp>
<IsoTimestamp>2024-07-21T01:10:30Z</IsoTimestamp>
<Hostname>VAU01</Hostname>
<Vendor>Test</Vendor>
<Product>Vau</Product>
<Version>14.0.0000</Version>
<MessageID>412</MessageID>
<Desc>logging</Desc>
<Severity>Info</Severity>
<Issuer>xxxxx</Issuer>
<Action>logging</Action>
<SourceUser/>
<TargetUser/>
<File>Root\Operating</File>
<Station>xx.yy.4.8</Station>
<Location/>
<Category/>
<RequestId/>
<Reason/>
<ExtraDetails>Command=11111[Tab]11111;ConnectionComponentId=Users;9T;</ExtraDetails>
<GatewayStation/>
<CAProperties>
<CAProperty Name = "PolicyID" Value = "Windows"/>
<CAProperty Name = "UserName" Value = "xxxxx"/>
<CAProperty Name = "Address" Value = "my.solutions"/>
<CAProperty Name = "DeviceType" Value = "Operating System"/>
<CAProperty Name = "Disabled" Value = "No Reason"/>
<CAProperty Name = "Logon" Value = "my"/>
<CAProperty Name = "CreationMethod" Value = "VWA"/>
</CAProperties>
</audit_record>
</syslog>
РЕДАКТИРОВАТЬ 4D: небольшой сценарий оболочки для последовательного запуска XSLT (Linux):
#!/bin/bash
xsltproc -o outfromstep1 initialparsetestSMALL.xsl sample-syslog-message.xml && cat outfromstep1
xsltproc -o outfromstep2 third-party-stylesheet.xsl outfromstep1 && cat outfromstep2
РЕДАКТИРОВАТЬ 4E: Пример вывода запуска (из стороннего файла stylesheet.xsl):
[root@nodejs stackoverflowexample]# ./runXslt.sh
<?xml version = "1.0"?>
<syslog>
<audit_record>
<Rfc>yes</Rfc>
<Timestamp>Jul 21 01:10:30</Timestamp>
<IsoTimestamp>2024-07-21T01:10:30Z</IsoTimestamp>
<Hostname>VAU01</Hostname>
<Vendor>Test</Vendor>
<Product>Vau</Product>
<Version>14.0.0000</Version>
<MessageID>412</MessageID>
<Desc>logging</Desc>
<Severity>Info</Severity>
<Issuer>xxxxx</Issuer>
<Action>logging</Action>
<SourceUser/>
<TargetUser/>
<File>Root\Operating</File>
<Station>xx.yy.4.8</Station>
<Location/>
<Category/>
<RequestId/>
<Reason/>
<ExtraDetails>Command=************;ConnectionComponentId=Users;9T;</ExtraDetails>
<GatewayStation/>
<CAProperties>
<CAProperty Name = "PolicyID" Value = "Windows"/>
<CAProperty Name = "UserName" Value = "xxxxx"/>
<CAProperty Name = "Address" Value = "my.solutions"/>
<CAProperty Name = "DeviceType" Value = "Operating System"/>
<CAProperty Name = "Disabled" Value = "No Reason"/>
<CAProperty Name = "Logon" Value = "my"/>
<CAProperty Name = "CreationMethod" Value = "VWA"/>
</CAProperties>
</audit_record>
</syslog>
|xxxxx|2024-07-21T01:10:30Z|412|logging|xx.yy.4.8|Root\Operating|Windows|my.solutions|Operating System||Command=************;ConnectionComponentId=Users;9T;|
Напоминание: моя цель — реализовать XSLT (который будет принимать входные данные XML для каждого образца и вызывать первое преобразование для этого входящего XML, а затем выполнять второе преобразование для выходных данных первого преобразования.
Как обсуждалось, в идеале мы не можем изменить второй XSLT (сторонний файл stylesheet.xsl, поскольку это не «наше программное обеспечение»).
РЕДАКТИРОВАТЬ 5:
Изначально я не включил файл «pipeline2.xsl», в котором есть код, опубликованный Коналом, а также код XSLT для выполнения «предварительной обработки», но у меня возникла проблема, потому что когда я тестирую этот «pipeline2. xsl», он ВСЕ ЕЩЕ по сути пропускает обработку XSLT предварительной обработки, встроенного в «pipeline2.xsl», поэтому я публикую фрагмент Pipeline2.xsl в надежде, что кто-нибудь сможет сказать мне, почему это происходит?
Вот фрагмент:
<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:exslt = "http://exslt.org/common"
exclude-result-prefixes = "exslt"
version = "1.0">
<xsl:import href = "./third-party-stylesheet.xsl"/>
<xsl:template mode = "pre-process" match = "/">
<xsl:variable name = "pre-processed-xml">
<xsl:apply-templates mode = "pre-process" select = "/" />
</xsl:variable>
<xsl:message><xsl:value-of select = "$pre-processed-xml"/></xsl:message>
<xsl:for-each select = "exslt:node-set($pre-processed-xml)">
<!-- apply the imported templates to the pre-processed-xml -->
<xsl:apply-imports/>
</xsl:for-each>
</xsl:template>
<!-- pre-processor generally copies the input -->
<xsl:template match = "@*|node()" mode = "pre-process">
<xsl:copy>
<xsl:apply-templates select = "@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- pre-processor should e.g. remove a particular element -->
<!-- <xsl:template match = "unwanted-element" mode = "pre-process"/> -->
<!-- From Conal's posts, I interpreted that he intended that, by the 2 lines above here, that I should basically add the code from my initialparsetest.xsl below here, i.e., the initial transformation of the <ExtraDetails>
element is performed in this pipeline XSLT and then after that the code above would cause the transformation in the third-party-stylesheet.xsl to be performed -->
<!-- BUT when I test, the code below (the xsl:template...) does NOT SEEM to be being executed !! -->
<!-- Handle processing of <ExtraDetails>... -->
<xsl:template mode = "pre-process" match = "/syslog/audit_record/ExtraDetails">
<!-- SET GLOBAL VARIABLE $incomingMessageID... -->
<xsl:variable name = "incomingMessageID" select = "/syslog/audit_record/MessageID"/>
<!-- SET GLOBAL VARIABLE $incomingExtraDetails... -->
<xsl:variable name = "incomingExtraDetails" select = "/syslog/audit_record/ExtraDetails"/>
<xsl:message>+++++++++ UPON ENTERING template match - incomingExtraDetails: [<xsl:value-of select = "$incomingExtraDetails"/>]</xsl:message>
<ExtraDetails>
<xsl:choose>
<!-- START 'when' TO HANDLE '412' requests -->
<xsl:when test = "$incomingMessageID = '412'">
<xsl:message>+++++++++++++++++++++++++++++++++++++ Processing a request with MessageId 412</xsl:message>
<xsl:message> VARIABLE incomingExtraDetails=[<xsl:value-of select = "$incomingExtraDetails"/>] </xsl:message>
.
.
.
.
BUNCH OF CODE
.
.
.
</ExtraDetails>
</xsl:template>
</xsl:stylesheet>
Я также нашел эту тему SO:
Сопоставление шаблона XSLT с установленным атрибутом режима не работает
который, похоже, имеет схожие симптомы (XSLT с режимом, который не выполняется), поэтому мне интересно, может быть, проблема, которую я вижу в моем конвейере2.xsl, вызвана той же самой вещью (отсутствием шаблонов применения?) ?
Если да, то что мне нужно добавить в файл Pipeline2.xsl, чтобы он начал работать?
michael.hor257k - Я согласен - как я уже говорил, предлагалось попробовать XProc, но я никогда о нем не слышал, и я пытался понять XProc, чтобы оценить, будет ли он жизнеспособным, но мы, вероятно, не сможем развертывать в продукте любой код Java или C, поэтому кажется, что я возвращаюсь к подходу «использовать XSLT 1.0». Спасибо!
Я до сих пор не понимаю, почему вы не можете просто изменить существующую таблицу стилей XSLT, чтобы она обрабатывала необработанный XML в нужный результат за один проход. При необходимости опубликуйте новый вопрос, указав все 3.
michael.hor257k — причина, по которой мы не ХОТИМ делать все в одном XSLT, заключается в том, что XSLT, специфичные для SIEM, предоставляются НАМ поставщиком продукта, и поэтому мы не хотим изменять XSLT, специфичные для SIEM. . Итак, мы хотим как бы разделить изменения, которые вносит «наш XSLT» (до того, как будет обработан XSLT, специфичный для SIEM). Таким образом, ответ заключается в том, что мы не можем сделать один XSLT не по технической причине, а скорее по причине своего рода деловая причина.
Вы можете написать свою собственную таблицу стилей и включить/импортировать существующую. Но более подробный ответ невозможен без минимально воспроизводимого примера (как вы также узнаете ниже).
Пожалуйста, отредактируйте свой вопрос и покажите (1) необработанный вывод XML из вашей системы, (2) исходную таблицу стилей XSLT, предоставленную вам поставщиком, и (3) точный результат, который вы ожидаете получить.
К вашему сведению, я добавлю пример двух XSLT, которые мне нужно запустить последовательно, а также образец запроса/XML через несколько минут. Извините, потребовалось время, чтобы собрать это воедино.
ок, обновил ОП новыми файлами!
Обратите внимание: ваш код все еще не является минимальной воспроизводимой формой. В одном из файлов с самого начала немного не хватает строк, а из другого вырезан кусок строк и заменен на «КУЧКА КОДА». Суть воспроизводимого примера в том, что люди здесь действительно могут взять ваш XSLT-код и запустить его, настроить и т. д. Если это даже не правильно сформированный XML, то, откровенно говоря, вы зря тратите время людей. Мы не хотим видеть весь ваш код: вы можете сократить его до образца, но он должен быть работоспособным, и вы должны проверить, что он работает.
кроме последнего файла (pipeline2.xsl), все остальные файлы должны быть работоспособными... Когда я собрал все остальные вместе, я запустил их здесь, прежде чем добавить их в OP. Как вы думаете, какого файла «немного не хватает»??
ре. тот, что с кучей кода - мне нужно подумать об этом, чтобы увидеть, что я могу предоставить, достаточное для всех вас. Кстати, @Conal, что Pipeline2.xsl - это, по сути, второй пример кода, который вы опубликовали... Я знаю, что вы хотите большего, но можете ли вы быстро взглянуть на него? Кроме того, в конце вашего примера было две строки, и я «предполагал», что вы имели в виду, что я должен поместить ТАМ свой код предварительной обработки (который не запускается). Было ли мое предположение верным?
Неработающие — это ваши правки, помеченные 4A и 5. А в другом блоке кода сверху и снизу есть лишние не-XML-коды, но, по крайней мере, там очевидно, что не так.
Я полностью обновил свой ответ, добавив несколько рабочих примеров кода, которые, я думаю, вы сможете изменить в соответствии со своими требованиями.
Обратите внимание: теперь, когда вопрос стал немного яснее, я решил в интересах ясности удалить свой первоначальный ответ и начать с нуля.
Цель состоит в том, чтобы создать конвейер, который последовательно запускает две таблицы стилей XSLT; во-первых, pre-processor.xsl
, который мы определяем сами, чья роль заключается в внесении некоторых изменений во входные данные, прежде чем они будут обработаны third-party-stylesheet.xsl
, содержимое которого мы не хотим менять.
Итак, у нас есть три файла XSLT; два упомянутых выше, и основная таблица стилей pipeline.xsl
, задача которой — запуск двух других.
pipeline.xsl
:
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:exslt = "http://exslt.org/common"
exclude-result-prefixes = "exslt"
version = "1.0">
<xsl:import href = "third-party-stylesheet.xsl"/>
<xsl:import href = "pre-processor.xsl"/>
<xsl:output method = "text"/>
<xsl:template match = "/">
<xsl:param name = "run-preprocessor" select = " 'yes' "/>
<xsl:choose>
<xsl:when test = "$run-preprocessor = 'yes' ">
<xsl:variable name = "pre-processed-xml">
<xsl:apply-templates mode = "pre-process" select = "/"/>
</xsl:variable>
<xsl:apply-templates select = "exslt:node-set($pre-processed-xml)">
<xsl:with-param name = "run-preprocessor" select = " 'no' "/>
<!-- 👇 recurses, but effectively calls the code below -->
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- effectively called from ☝️ above -->
<xsl:apply-imports/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
pipeline.xsl
импортирует две другие таблицы стилей, чтобы применить шаблоны из обеих.
Сначала он запускает pre-processor.xsl
(который написан в режиме pre-process
, чтобы его шаблоны не конфликтовали с шаблонами third-party-stylesheet.xsl
).
Вывод pre-processor.xsl
фиксируется в переменной, которая представляет собой «фрагмент дерева результатов» (поскольку это XSLT 1.0), поэтому нам нужно использовать функцию exslt:node-set()
, чтобы преобразовать его обратно в документ, к которому мы затем можем применить шаблоны third-party-stylesheet.xsl
чтобы.
Единственная сложность здесь заключается в том, как, когда мы снова вызываем apply-templates
, мы получаем шаблон match = "/"
в third-party-stylesheet.xsl
, соответствующий нашему предварительно обработанному документу, вместо того, чтобы он соответствовал шаблону match = "/"
в pipeline.xsl
и повторял бесконечную рекурсию. Хитрость заключается в том, чтобы использовать параметр, указывающий, завершен ли этап предварительной обработки. Когда мы делаем рекурсивный вызов apply-templates
с нашим предварительно обработанным документом, мы передаем флаг соответствующему шаблону, сообщающий, что предварительная обработка завершена. Если наш шаблон получит этот флаг, он сможет использовать оператор apply-imports
для перехода к шаблону в импортированном third-party-stylesheet.xsl
.
Обратите внимание: third-party-stylesheet.xsl
использует метод вывода text
, как и наш pipeline.xsl
.
Вот другие мои файлы:
pre-processor.xsl
:
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
<!-- pre-processor generally copies the input -->
<xsl:template match = "@*|node()" mode = "pre-process">
<xsl:copy>
<xsl:apply-templates select = "@*|node()" mode = "pre-process"/>
</xsl:copy>
</xsl:template>
<!-- pre-processor should e.g. remove a particular element -->
<xsl:template match = "unwanted-element" mode = "pre-process"/>
</xsl:stylesheet>
third-party-stylesheet.xsl
:
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
<xsl:output method = "text"/>
<xsl:template match = "/">
<xsl:value-of select = "."/>
</xsl:template>
</xsl:stylesheet>
input.xml
:
<example>
<desired-text>This text should make it past the pre-processor</desired-text>
<unwanted-element>This element should be filtered out by the pre-processor</unwanted-element>
<desired-text>This should appear</desired-text>
<unwanted-element>This should not appear</unwanted-element>
</example>
Запуск xsltproc -o output.txt pipeline.xsl input.xml
производит:
output.txt
:
This text should make it past the pre-processor
This should appear
Конал Туохи. Я внес некоторые изменения в исходное сообщение, чтобы исправить некоторые проблемы, приводившие к отсутствию строк. К вашему сведению, в «желаемом потоке» нам нужно только ДВА XSLT: (а) мой XSLT, который преобразуется в элементе, после чего мы хотим передать этот измененный XML в XSLT, специфичный для SIEM. Я пытался настроить опубликованный вами XSLT, но мне кажется, что в опубликованном вами XSLT были некоторые опечатки, плюс то, что вы опубликовали, ожидало 4 XSLT (вместо 2), и у меня возникли проблемы с корректировкой опубликованного вами XSLT. Итак, после этого я опубликую отредактированную версию вашего XSLT. Не могли бы вы просмотреть и исправить то, что я публикую?
Я отредактировал ваш вопрос и удалил некоторые угловые скобки, которые исказили описание вашего конвейера. Я думаю, что понимаю, что то, что вам нужно, проще, чем я думал: на самом деле у вас в конвейере только две стадии XSLT, верно? Я представил обобщенное решение, но отредактирую свой пост, чтобы показать более простую версию.
Конал - да, это правильно - спасибо - к вашему сведению - я пытался настроить то, что вы изначально опубликовали - следует ли мне опубликовать то, что у меня есть (но все еще появляется ошибка "ошибка времени выполнения: файл конвейер.xsl, строка 27, элемент apply-imports" Вызов «apply-imports», когда нет текущего правила шаблона, является ошибкой».? Или мне просто подождать вашего обновления и попробовать обновленный конвейер XSLT?
ок, нвм, дай мне попробовать твой новый XSLT
Конал Туохи. Я не уверен, что SO удаляет его, но я думаю, что в строке 4 в новом XSLT, который вы опубликовали, отсутствует конечная косая черта. Я исправил это, но когда я запускаю ваш XSLT (я назвал «pipeline2.xsl»), я получаю ошибку: [root@nodejs stackoverflow1]# xsltproc -o foo pipeline2.xsl EmptyDetailsauditrecord.xml && cat foo runtime error: file pipeline2.xsl line 14 element apply-imports It is an error to call 'apply-imports' when there's no current template rule.
Конал Туохи: Если вы модифицировали XSLT, где он выполняет то, что вы называли «препроцессором XSLT» (то, что я назвал «нашим XSLT» в своем исходном посте)? Похоже, что ваш модифицированный XSLT не вызывает обработку XSLT «нашего XSLT» (до того, как он запустит сторонний файл stylesheet.xsl)?
Конал Туохи - Ааа - я пересматривал ваш обновленный XSLT и, кажется, не понимал, что должен делать опубликованный вами XSLT... Я думаю, что в строках в конце вашего XSLT: ` <!- - препроцессор обычно копирует ввод --> <xsl:template match = "@*|node()" mode = "pre-process"> <xsl:copy> <xsl:apply-templates select = "@*| node()"/> </xsl:copy> </xsl:template> <!-- препроцессор должен, например. удалить определенный элемент --> <xsl:template match = "unwanted-element" mode = "pre-process"/> ` вы ожидали, что этот код будет включать в себя то, что у меня было в моем «нашем XLST»?
Конал. Однако теперь, когда я это понимаю, я до сих пор не знаю, почему я получаю сообщение об ошибке «apply-imports». Вызов «apply-imports» является ошибкой, когда нет текущего правила шаблона. `
возможно, если бы вы опубликовали пример вашего исходного XML и имеющегося у вас XSLT, включая изменения, которые вы хотите, чтобы ваш препроцессор внес, можно было бы попытаться воспроизвести проблему. Без этого мой ответ, естественно, будет несколько гипотетичным и уклончивым. Всегда полезно опубликовать stackoverflow.com/help/minimal-reproducible-example
@ConalTuohy - Я думаю, вы хотите добавить mode = "pre-process"
к xsl:apply-templates
в преобразовании личности.
На самом деле, я как раз собирался опубликовать, но что-то другое, чем то, что написал Дэниел. Думаю, мне пришлось добавить "mode=pre-process" к первому <xsl:template... так что я <xsl:template mode = "pre-process" match = "/">
Это устранило ошибку, которую я получал, но у меня не было времени проверить, действительно ли выполняется предварительная обработка. еще в обработке, потому что мне нужно добавить свой код в конвейер.xsl - я опубликую немного позже, если смогу это подтвердить.
поэтому добавление mode=pre-process к первому <xsl:template... избавило от ошибки, но после того, как я добавил свой код в конвейер.xsl, когда я тестирую, он запускает не мой код предварительной обработки, а скорее в основном использует XSLT третьей части, поэтому сейчас я собираюсь попробовать предложение Дэниела Хейли...
Я попробовал, как предложил Дэниел Хейли, но, похоже, он по-прежнему выполняет только стороннее преобразование. Я могу сказать, что он использует сторонний XSLT, потому что этот XSLT приводит к тому, что выходные данные представляют собой текст, а не XML. Есть идеи, почему он даже не пытается выполнить преобразование, находящееся в самом файле Pipeline.xsl?
К вашему сведению, я добавлю пример двух XSLT, которые мне нужно запустить последовательно, а также образец запроса/XML через несколько минут. Извините, потребовалось время, чтобы собрать это воедино.
ок, обновил ОП новыми файлами!
@ConalTuohy - я только что получил файлы, которые вы просили ранее, но, поскольку вы изменили подход и файлы, которые публикуете, я думаю, что для меня имеет смысл (а) попытаться запустить ваши новые файлы как есть, чтобы проверить, что я получите те же результаты, что и вы, затем (б) я изменю то, что вы предоставили, чтобы использовать настоящую/полную предварительную обработку и сторонние XLST, а затем (в) сообщу о том, что произойдет. Это звучит нормально? К вашему сведению, я не уверен, смогу ли я сделать все это сегодня вечером (сейчас 2:15 ночи)...
@ConalTuohy - Когда я запускаю xsltproc с вашими файлами, я получаю описанный вами результат... поэтому я постараюсь приспособиться к вашему новому подходу... и дам вам знать
@ConalTuohy - я поменял местами свои настоящие файлы XSLT, а также входной XML-файл, и когда я запускаю xsltproc -o output.txt Pipeline.xsl input.xml, он не создает файл output.txt. И ошибок тоже не выдает :(...
@ConalTuohy - ИЗВИНИТЕ ЗА ПАНИКУ!!! Я понял, что мне нужно зайти в pre-processor.xsl и добавить mode = "pre-process" к командам шаблона, и я протестировал еще раз, и теперь это работает!!! Я ХОЧУ ПРОВЕСТИ БОЛЕЕ ПОДРОБНОЕ ТЕСТИРОВАНИЕ ЗАВТРА И НАПИШУ ОТВЕТ.... СПАСИБО!!
КСТАТИ, это ТАК КРУТО :) !!
Без проблем! Требование импортировать другую таблицу стилей, не прибегая к ее изменению, означало, что проблема требовала неочевидного трюка, найти решение которого было интересно. Обратите внимание, что в современной версии XSLT подобные вещи намного проще, но, к сожалению, до сих пор существует много-много программных платформ, которые поддерживают только эту уже древнюю версию языка (25 лет!). В XSLT 3 вы можете вызвать другой XSLT, используя функцию transform()
, в результате чего длина pipeline.xsl
составит всего несколько строк.
@ConalTuohy - Я согласен насчет ситуации с версией 1.0... это просто смешно. Я собираюсь попытаться протестировать XSLT на реальном продукте где-нибудь на этих выходных, и мы внутри компании обсуждаем возможность запроса на улучшение XSLT 3 от поставщика продукта, но даже если мы это сделаем, это все равно может не произойти во время наша жизнь (серьезно). Я опубликую после того, как опробую на реальном продукте.
@ConalTuohy - я только что протестировал новый конвейер.xsl и т. д. с продуктом, и он сработал, поэтому после этого я отмечу ваш ответ. Спасибо, что остаетесь со мной в этом!!
IIUC, вы спрашиваете, можете ли вы интегрировать предварительное преобразование XSL в свой продукт перед существующим. Мы ничего не знаем о вашем продукте и не можем ответить на этот вопрос. Я предполагаю, что самый простой путь — найти таблицу стилей XSLT, которую использует ваш продукт, и изменить ее для получения нужного вам результата.