Я использую Schematron для проверки экземпляров XML-документов в XML-редакторе, поддерживающем настраиваемые схемы (обратите внимание, что проверка Schematron - это просто преобразование XSLT). Экземпляр может содержать элементы, в значении которых указан путь (упрощенное выражение XPath). Примером такого пути может быть:
/p:root/p:level-one/r:level-two/r:level-two-leaf
где оба префикса (p и r) привязаны к пространству имен, определенному в документе экземпляра. My Schematron проверяет такие пути, гарантируя, что элемент, на который указывает путь, действительно существует в документе экземпляра. Для этого он полагается на EXSLT (я вынужден использовать XSLT1.0), точнее на dyn:evaluate()
, чтобы оценить текстовое значение элемента, которое, как вы можете видеть по сути является выражением XPath. Работает как часы.
Но есть одна проблема, на самом деле огромная. Вызов dyn:evaluate()
выполняется из Schematron XSLT, который оценивает выражение XPath в своем собственном контексте пространства имен. Это означает, что для правильной работы как экземплярный документ, так и XSLT Schematron должны использовать одну и ту же привязку prefix → namespace. Я не могу заставить пользователя использовать одни и те же префиксы для тех же пространств имен, которые указаны в моей схеме ... это было бы глупым требованием (однако гарантируется, что по крайней мере те же самые пространства имен будут использоваться в обоих). Schematron всегда генерируется перед проверкой экземпляра, но это делается только один раз из соображений производительности. Единственный вариант, который у меня есть, - это каким-то образом предварительно обработать пути из экземпляра и выполнить своего рода перевод из «путей экземпляра» в «пути XSLT». Я новичок в XSLT и понятия не имею, как я могу этого добиться.
Как мне преобразовать такие текстовые значения в то, что требуется контексту пространства имен XSLT? Это вообще возможно? В настоящее время я думаю об исправлениях памяти XSLT (все это делается в Java) перед каждым вызовом проверки - переименованием префиксов так, чтобы они соответствовали привязке экземпляров или введению новых атрибутов пространства имен - но это может привести к конфликтам имен префиксов, и я Я не уверен, как это повлияет на производительность проверки. Я открыт для любых предложений, так как предполагаю, что это то, с чем, должно быть, сталкивались и другие люди (при использовании Schematron или dyn:evaluate()
).
Изменить: отсюда следует пояснение того, что я пытаюсь сделать.
У меня есть файл экземпляра XML, который редактирует пользователь в редакторе. Примером такого файла может быть:
<?xml version="1.0" encoding="utf-8"?>
<config xmlns="http://example.com/ns/config"
xmlns:cfg="http://example.com/ns/config"
xmlns:ns1="http://example.com/ns/custom-01"
xmlns:ns2="http://example.com/ns/custom-02">
<ns1:some-element>/cfg:config/ns1:other-element/ns2:nested-element</ns1:some-element>
<ns1:other-element>
<ns2:nested-element>some value</ns2:nested-element>
</ns1:other-element>
</config>
Такой документ затем проходит проверку схемы, которая, по сути, является преобразованием XSLT. Он будет объявлен действительным только в том случае, если путь в ns1:some-element
относится к существующему элементу в том же документе (поэтому приведенный выше пример действителен).
Схема XSLT выглядит примерно так (обратите внимание, что она была значительно упрощена):
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--This XSLT was automatically generated from a Schematron schema.-->
<xsl:stylesheet xmlns:iso="http://purl.oclc.org/dsdl/schematron"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:exsl="http://exslt.org/common"
xmlns:sch="http://www.ascc.net/xml/schematron"
xmlns:cfg="http://example.com/ns/config"
xmlns:cust1="http://example.com/ns/custom-01"
xmlns:cust2="http://example.com/ns/custom-02"
extension-element-prefixes="dyn exsl"
version="1.0">
<!-- other templates -->
<xsl:template match="/cfg:config/cust1:some-element">
<xsl:choose>
<xsl:when test="dyn:evaluate(.)">
<!-- do stuff -->
<xsl:when>
</xsl:choose>
</xsl:template>
<!-- other templates -->
</xsl:stylesheet>
Я уверен, что это объясняет проблему. Вызов dyn:evaluate(.)
будет пытаться оценить выражение /cfg:config/ns1:other-element/ns2:nested-element
XPath, которое использует несвязанные префиксы из префикса преобразования (и поэтому всегда имеет значение false).
Вопрос был и остается: как я могу перевести эти выражения XPath, чтобы они действительно имели смысл в преобразовании?