2016-08-17 9 views
1

私はXSLTを初めて使用していて、いくつかのボイラープレートの名前空間処理に戸惑うことがあります。 同じURIの既定の名前または別のプレフィックス付き名前空間を持つXSLT 2.0フレキシブル

私は目標は、単に一つの要素名前を変更することで、次のXSLTいます

<ACORD xmlns="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/"> 
    <InsuranceSvcRq> 
    <BOPPolicyQuoteInqRq> 
     <RqUID>E2BA6308-62D5-43AC-B8C1-7616FDFE9C98</RqUID>  
    </BOPPolicyQuoteInqRq> 
    </InsuranceSvcRq> 
</ACORD> 

しかし、この意味的に同等のXMLは失敗します:予想通り、次のXMLの変換

<?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> 

ワークス

<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 

は、1つの接頭辞を宣言し、他方が(私も言ってベンチャーうしないので、遠くのXML仕様に関するされるように、XSLTトランスフォーマがハングアップしつつあるように、これらXMLSは意味的に等価であっても表示されます「foo」という接頭辞が付いていて、「bar」が付いているものがある場合は、ハングアップします)。

私は、特定の接頭辞または名前空間を特定の方法で宣言するように私にXMLを渡すクライアントを強制できない位置にいます。私は明日別のプレフィックスエイリアスを使用することを決断しないことも保証できません。

xpath-default-namespace属性を宣言したことは、既定のプレフィックスとして宣言されるかどうかにかかわらず、xsltトランスフォーマーに、ドキュメント全体がどのような名前空間URIに関連付けられるか、接頭辞にも「rainbowunicorns」という別名が付いています。

正確には属性xpath-default-namespaceは何を行いますか、クライアントが決定する名前空間宣言のフレーバに関係なく、意味的に同等の名前空間を適切に処理できる柔軟なXSLTをどのように記述できますか?

スペック該当する場合: 両方XMLS(マーティンHonnenの礼儀)で動作する変換更新キャメル2.16.2 サクソン-HE 9.5.1-8

<?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> 

答えて

2

を交換してください

<xsl:template match="@* | node()"> 
    <xsl:copy> 
    <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
</xsl:template> 
によって
<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> 

その後、あなたにも範囲内の任意の名前空間をコピーしてその方法として

と全体のスタイルシートは、診断上の最初の単語

<xsl:transform 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" 
    xpath-default-namespace="http://www.ACORD.org/standards/PC_Surety/ACORD1/xml/" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="BOPPolicyQuoteInqRq/RqUID"> 
     <xsl:variable name="new-local-name" as="xs:string" select="'RqUUID'"/> 
     <xsl:variable name="prefix" select="prefix-from-QName(node-name(.))"/> 
     <xsl:variable name="new-name" as="xs:string" select="if ($prefix) then concat($prefix,':', $new-local-name) else $new-local-name"/> 
     <xsl:element name="{QName(namespace-uri(), $new-name)}" namespace="{namespace-uri()}"> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:element> 
    </xsl:template> 

</xsl:transform> 
+0

<xsl:element name="{name()}" namespace="{namespace-uri()}">、あなたが好む場合にしたい場合は、あなたが提案された変更のそれぞれが終了した理由として説明を提供することをいとわないだろう仕事は? Sidenote:私はまた、|私の "他の"ルールのtext()部分がこれらの変更と組み合わされると、あいまいなルールセットが作成されました(xsltトランスフォーマーは本当にエラーを出してくれました。 _why_ – Russ

+0

を学びたいだけです。もう一度考えてみましょう。上記の提案は入力のデフォルトの名前空間で失敗することは明らかです。その場合、構築された名前は ':RqUUID'となります。私は両方のタイプの入力で動作するコードを書く方法を試してみる必要があります。 –

+0

基本的には、ノードをそのままコピーしたいのであれば、私が最初に提案したテンプレートで始めるのが一般的な方法です(それぞれ3つは見落としていました) 'xsl:copy'はスコープ内の名前空間をコピーしますが、' xsl:element'を使ってそれをしないとコピーします。 –

1

なり読み取り可能なコードを維持するためにいくつかの変数で

<xsl:template match="BOPPolicyQuoteInqRq/RqUID" > 
    <xsl:element name="{QName(namespace-uri(), if (prefix-from-QName(node-name(.))) then concat(prefix-from-QName(node-name(.)),':', 'RqUUID') else 'RqUUID')}" namespace="{namespace-uri()}"> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:element> 
</xsl:template> 

を使用します。それスタイルシートで動的エラーが発生したときにJavaスタックトレースを出力することはあまり意味がありません。 Saxonは登録されたErrorListenerにエラーを報告し、標準のErrorListenerはスタイルシートの作成者にとって便利なように設計された診断を生成し、XSLTのどこでエラーが発生したのか、そしてそのコードがどこから呼び出されたのかを示すXSLTレベルのスタックトレース。これらの診断が表示されない場合は、何か問題があります。

第2に、なぜ失敗したのですか?あなたはやっている

<xsl:element name="{name()}"> 

と値はbloat:RqUIDのようなものです。 XSLに関する規則:要素は言う:

[ERR XTDE0830] XSLの場合:name属性の 実効値場合ノー 名前空間属性を持つ要素の命令は、回復不能動的誤差でありますは、接頭辞がxsl:element 命令のスコープ内の名前空間宣言で宣言された でないQNameです。

あなたは、そのまま名前をコピー<xsl:copy>を使用するか、またはこのコードは間違いなく動作します

+0

私は二度買った本の著者から答えを得ることは決してなかった(犬は文字通り私の最初のカバーを食べた)。診断:xsltで失敗した行や列、認識されない文字などを含むスタックトレースに関する詳細情報が表示されます。しかし、これは実行時エラーと実行時エラーの傾向があります。私は何か間違っているように思えます。あなたが次回より優れたランタイム診断を得るために私に向けて指し示すことができるどんな提案も高く評価されます。私たちがラクダを活用しているので、これは有用な統合フレームワークであるため、これはラクダのことかもしれません。 – Russ

+0

私のアイデンティティルールのエラーの説明にも感謝します。元の名前空間接頭辞(もしあれば)を保持しておくことが望ましいので、xsl:elementを利用することはxsl:copyと比較して悪い選択でした。私は、プロジェクトのタイムラインのプレッシャーのために前から後ろに読んでいるのではなく(私の好み)、この本の中で狩りとペックを余儀なくされている。タイムラインを提供するのではなく、私が座って理解のために読む時間を得るとき、私はそのようなノービスの質問をしません:) – Russ

関連する問題