Я новичок в XSLT и споткнулся об обработке пространства имен котлов.XSLT 2.0 гибкий со стандартным или различным префиксным пространством имен того же URI
Я следующий XSLT, где целью является просто переименовать один элемент:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/" >
<xsl:strip-space elements="*" />
<!-- element template that copies over elements -->
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<!-- attribute template to copy attributes over -->
<xsl:template match="@*">
<xsl:copy>
<xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
</xsl:copy>
</xsl:template>
<!-- "other" template to copy the rest of the nodes -->
<xsl:template match="comment() | text() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<!-- Rename an element -->
<xsl:template match="BOPPolicyQuoteInqRq/RqUID" >
<xsl:element name="RqUUID">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Преобразуя следующий XML работает, как ожидалось:
<ACORD xmlns="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/">
<InsuranceSvcRq>
<BOPPolicyQuoteInqRq>
<RqUID>E2BA6308-62D5-43AC-B8C1-7616FDFE9C98</RqUID>
</BOPPolicyQuoteInqRq>
</InsuranceSvcRq>
</ACORD>
Однако это семантически эквивалентно XML терпит неудачу:
<bloat:ACORD xmlns:bloat="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/">
<bloat:InsuranceSvcRq>
<bloat:BOPPolicyQuoteInqRq>
<bloat:RqUID>E2BA6308-62D5-43AC-B8C1-7616FDFE9C98</bloat:RqUID>
</bloat:BOPPolicyQuoteInqRq>
</bloat:InsuranceSvcRq>
</bloat:ACORD>
Ошибка, которую я получаю:
Caused by: net.sf.saxon.trans.XPathException: Undeclared prefix in element name: bloat
at net.sf.saxon.expr.instruct.ComputedElement.getElementName(ComputedElement.java:429)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:388)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:371)
at net.sf.saxon.expr.instruct.Template.applyLeavingTail(Template.java:239)
at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:1056)
at net.sf.saxon.trans.TextOnlyCopyRuleSet.process(TextOnlyCopyRuleSet.java:65)
at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:1044)
at net.sf.saxon.Controller.transformDocument(Controller.java:2088)
at net.sf.saxon.Controller.transform(Controller.java:1911)
at org.apache.camel.builder.xml.XsltBuilder.process(XsltBuilder.java:141)
at org.apache.camel.impl.ProcessorEndpoint.onExchange(ProcessorEndpoint.java:103)
at org.apache.camel.component.xslt.XsltEndpoint.onExchange(XsltEndpoint.java:121)
at org.apache.camel.impl.ProcessorEndpoint$1.process(ProcessorEndpoint.java:71)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:141)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:460)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:62)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:109)
at org.apache.camel.processor.UnitOfWorkProducer.process(UnitOfWorkProducer.java:68)
at org.apache.camel.impl.ProducerCache$2.doInProducer(ProducerCache.java:412)
at org.apache.camel.impl.ProducerCache$2.doInProducer(ProducerCache.java:380)
at org.apache.camel.impl.ProducerCache.doInProducer(ProducerCache.java:270)
at org.apache.camel.impl.ProducerCache.sendExchange(ProducerCache.java:380)
at org.apache.camel.impl.ProducerCache.send(ProducerCache.java:221)
at org.apache.camel.impl.DefaultProducerTemplate.send(DefaultProducerTemplate.java:124)
at org.apache.camel.impl.DefaultProducerTemplate.sendBody(DefaultProducerTemplate.java:137)
... 32 more
Оказывается, даже если эти XMLs семантически эквивалентны насколько XML-спецификации будут иметь дело, то XSLT трансформатор становится повесил трубку, потому что один говорит префикс, а другой не (я бы тоже рискнул сказать, он будет зависеть, если в нем будет префикс «foo», а один - «bar»).
Я в состоянии, когда я не могу заставить клиента, передающего мне xml, объявить определенный префикс или пространство имен определенным образом. Я также не могу гарантировать, что они не решат использовать другой псевдоним префикса завтра.
Мое понимание объявления атрибута xpath-default-namespace
состояло в том, что он передал трансформатору xslt, какой URI пространства имен будет связан с всем документом, независимо от того, будет ли он объявлен как префикс по умолчанию, префикс с псевдонимом «bloat» или даже префикс с псевдонимом «rainbowunicorns».
Что именно делает атрибут xpath-default-namespace
и как я могу написать гибкий XSLT, который может изящно обрабатывать любое количество семантически эквивалентных пространств имен независимо от того, какой вкус объявления пространства имен принимает клиент?
функции при необходимости: Camel 2.16.2 Saxon-HE 9.5.1-8
Обновлено преобразование, которое работает как с XMLs (любезно Мартина Honnen):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/" >
<xsl:strip-space elements="*" />
<!-- element template that copies over elements -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<!-- "other" template to copy the rest of the nodes -->
<xsl:template match="comment() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<!-- Rename an element -->
<xsl:template match="BOPPolicyQuoteInqRq/RqUID" >
<xsl:element name="RqUUID" namespace="{namespace-uri()}">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Этот код определенно работает, вы были бы готовы предоставить объяснение, почему каждый из изменений, которые вы предложили закончились работа? Sidenote: Мне также пришлось удалить | text() моего «другого» правила, в сочетании с этими изменениями, он сделал неоднозначный набор правил (трансформатор xslt дал действительно ошибку, которая помогла мне исправить ее самостоятельно). Просто хочу узнать _why_ – Russ
Думая о нем снова, предложение выше, очевидно, потерпит неудачу с пространством имен по умолчанию на входе, так как построенное имя будет ': RqUUID'. Мне нужно попробовать и проверить, как писать код, который работает с обоими типами ввода. –
Что касается объяснения, в основном, если вы хотите скопировать узлы без изменений, то обычно рекомендуется начинать с шаблона, который я предложил сначала вместо двух (соответственно три, я пропустил третий), которые вы пробовали, это более компактный способ и 'xsl: copy' скопирует любое пространство имен в пространстве, в то время как ваши попытки с помощью' xsl: element' этого не делают. –