2016-10-05 6 views
2

以下の質問には解決策がありますが、XSLTを使用して1つの「テンプレート」XMLともう1つの「引数」XMLからテキストを生成する一般的な方法XML

質問:

我々は<verbatim>要素及び又は<part id='part001'>要素にネストしてもしなくてもよいどちらも<argument id='foo'/>元素の混合物から構成されている「template.xml」を有します。 (したがって、verbatimsと引数はルート要素に含めることも、<part> ... </part>要素に含めることもできます)。

例 "template.xml":

<template_root> 
    <verbatim>Title</verbatim> 
    <part id='part001'> 
    <verbatim>Nested in part 1.</verbatim> 
    <argument id='keywords'>ARGKEY1, ARGKEY2, ARGKEY3</argument> 
    <verbatim>End of part 1.</verbatim> 
    </part> 
    <part id='DoNotUse'> 
    <verbatim>This should not be in the output</verbatim> 
    </part> 
    <verbatim>End of article</verbatim> 
</template_root> 

は、我々は別のファイルを持っている、 "<引数ID = 'someid' />" エレメントから構成されている "のinstance.xml" は、(<引数を参照/> sをtemplate.xmlに入れます)。これは、上記のように同じ "< part id = 'partid'>"要素に入れ子にされている場合と入れ子されていない場合があります。

例 "のinstance.xml":

<instance_root template='template.xml'> 
    <part id='part001'> 
    <argument id="keywords" enabled='true'/> 
    </part> 
</instance_root> 

私たちは、 "のinstance.xml" から次の情報を読み込み、テンプレートファイル名に

  1. 読むを生成XSLTをしたい(例: "template.xml")および "template.xml" のすべての要素について、次に
    1. 全ての
    2. コピー値をtemplate.xmlの<template_root>にあるがそのままです。それはまた、同じ@id属性@enabled='true'で「のinstance.xml」の<instance_root>にリストされている場合にのみ、template.xmlの<template_root>内のすべての<argument>
    3. コピー値。
    4. "template.xml"にある<part>のすべての子どもに対して上記(21)および(22)と同じ処理を行い、同じ@id<part>も「instance.xml」にあり、他のすべてを無視する場合のみ"template.xml"の<part>

だから私たちはコピーされませんものです。 1「のinstance.xml」で対応する<argument>を持っていない「template.xml」のすべての<argument>。 2. "template.xml"の<part>には、 "instance.xml"に対応する<part>がありません。

例のテキスト出力:

Title 
Nested in part 1. 
ARGKEY1, ARGKEY2, ARGKEY3 
End of part 1. 
End of article 

私はxsltprocのを使用していますが、一般的な方法(または、あなたが考えることができる最善の方法は)これを行うには何か知りたいの? 「汎用」とは、複雑なXPathをハードコードしたり、個々の要素を参照したりしたくないということです([1]、[2]などを使用します)。

+0

あなたのルールは完全にはっきりしていません。コピーしない要素は** **正確に説明してください。あなたは「逐語的」をコピーしますが、何らかの条件に合わない「部分」の子はしませんが、「逐語的」も一部の子です。意味が明確でない場合は、 'instance.xml'の内部階層がここで再生されます。なぜ要素をコピーすることになっているのですか? –

+0

これらのコメントを削除し、質問を編集してください。 –

+0

完了。それはもっと明確ですか? – RMZ

答えて

0

@ uL1の応答と少し微調整のおかげで、以下は非常に良い解決策です。

唯一の欠けている機能(私は本当に私の元の質問で尋ねなかったが、私は本当に追加したい)は、任意の数のネストされた<part>要素を処理できるようにすることです。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="text" encoding="UTF-8" indent="yes"/> 
    <xsl:variable name="template" select="document(//@template)"/> 
    <xsl:variable name="instance" select="/"/> 

    <xsl:template match="text()" priority="1.1"> 
    <xsl:value-of select="concat(., '&#10;')"/> 
    </xsl:template> 

    <xsl:template match="/"> <!-- Using match="instance_root" would work just as well. --> 
    <xsl:apply-templates select="$template/*"/> 
    </xsl:template> 

    <xsl:template match="template_root"> 
    <xsl:copy> 
     <xsl:apply-templates select=" 
      verbatim 
      | argument[@id = $instance//argument[@enabled = 'true']/@id] 
      | part[@id = $instance//part/@id]"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="part"> 
    <xsl:copy> 
     <xsl:apply-templates select=" 
      verbatim 
      | argument[@id = $instance//part[@id = current()/@id]/argument[@enabled = 'true']/@id]"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
0

私はこのソリューションが既に十分に一般的であることを願っています。以下の行を見てください:

拡張テンプレート。XML:

<instance_root template='template.xml'> 
    <part id='part001'> 
     <argument id="keywords" enabled='true'/> 
    </part> 
    <part id="part002"> 
     <argument id="keywords" enabled="false"/> 
    </part> 
    <part id="part003"> 
     <argument id="keywords" enabled="true"/> 
    </part> 
    <argument id="key" enabled='false'/> 
    <argument id="word" enabled='true'/> 
</instance_root> 

スタイルシート:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 
    <xsl:variable name="instance" select="document('instance.xml')/*"/> 

    <xsl:template match="template_root"> 
     <xsl:copy> 
      <xsl:apply-templates select=" 
       verbatim 
       | argument[@id = $instance/argument[@enabled = 'true']/@id] 
       | part[@id = $instance/part/@id]"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="part"> 
     <xsl:copy> 
      <xsl:apply-templates select=" 
       verbatim 
       | argument[@id = $instance/part[@id = current()/@id]/argument[@enabled = 'true']/@id] 
       "/> 
     </xsl:copy> 
    </xsl:template> 

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

[ヒント:テンプレートマッチ、原因と連携することができません

<template_root> 
    <verbatim>Title</verbatim> 
    <argument id="key">ARGKEY0</argument> 
    <part id="part001"> 
     <verbatim>Nested in part 1.</verbatim> 
     <argument id="keywords">ARGKEY1, ARGKEY2, ARGKEY3</argument> 
     <verbatim>End of part 1.</verbatim> 
    </part> 
    <part id="part002"> 
     <verbatim>Nested in part 2.</verbatim> 
     <argument id="keywords">ARGKEY4, ARGKEY5, ARGKEY6</argument> 
     <verbatim>End of part 2.</verbatim> 
    </part> 
    <part id="part003"> 
     <verbatim>Nested in part 3.</verbatim> 
     <argument id="keywords">ARGKEY7, ARGKEY8, ARGKEY9</argument> 
     <verbatim>End of part 3.</verbatim> 
    </part> 
    <part id="DoNotUse"> 
     <verbatim>This should not be in the output</verbatim> 
    </part> 
    <argument id="word">ARGKEY10</argument> 
    <verbatim>End of article</verbatim> 
</template_root> 

のinstance.xmlを拡大使用することは不可能ですテンプレートの試合で変数] XMLとして

結果:テキストとして

<?xml version="1.0" encoding="UTF-8"?> 
<template_root> 
    <verbatim>Title</verbatim> 
    <part> 
    <verbatim>Nested in part 1.</verbatim> 
    <argument id="keywords">ARGKEY1, ARGKEY2, ARGKEY3</argument> 
    <verbatim>End of part 1.</verbatim> 
    </part> 
    <part> 
    <verbatim>Nested in part 2.</verbatim> 
    <verbatim>End of part 2.</verbatim> 
    </part> 
    <part> 
    <verbatim>Nested in part 3.</verbatim> 
    <argument id="keywords">ARGKEY7, ARGKEY8, ARGKEY9</argument> 
    <verbatim>End of part 3.</verbatim> 
    </part> 
    <argument id="word">ARGKEY10</argument> 
    <verbatim>End of article</verbatim> 
</template_root> 

結果

Title 
Nested in part 1. 
ARGKEY1, ARGKEY2, ARGKEY3 
End of part 1. 
Nested in part 2. 
End of part 2. 
Nested in part 3. 
ARGKEY7, ARGKEY8, ARGKEY9 
End of part 3. 
ARGKEY10 
End of article 

あなたはあなたの正確な出力を達成するために、いくつかの小さなものを変更する必要があります!変更/次の行を追加します。

<xsl:output method="text" encoding="UTF-8"/> 

<xsl:template match="text()" priority="1.1"> 
    <xsl:value-of select="concat(., '&#10;')"/> 
</xsl:template> 

最も重要なのと、多分欠点:これは//part/partでは動作しません! [@idと一致する場合はancestor::partを確認できません]

+0

こんにちはuL1。これは素晴らしく、多くのものを明確にします。答える時間をとってくれてありがとう。私が持っている唯一の問題は、 "instance.xml"は、他の方法で使用するテンプレートを参照する必要があるということです。 "template.xml"はすべてのインスタンスファイルを参照する必要はありません。あなたはまたあなたのヒントをもう少し説明できますか? 「テンプレートマッチで作業できません」とはどういう意味ですか、なぜそれが必要だと思いますか?また、 "すべてが正しい@ idと一致する場合、ancestor :: partをチェックできません"ということはどういう意味ですか? – RMZ

+0

質問を説明する他の方法があります。私は簡単な方法で質問を説明することができます:私たちは "instance.xml"を持っており、どのテンプレートを選択するか教えてくれます。 "instance.xml"を読み込んで、このインスタンスが参照するテンプレートから "有効にする"要素の値を、表示されている順にコピーする必要があります。これらの要素はネストすることができますが、インスタンス内の要素パスはテンプレート内の同じパスに対応するものです。 – RMZ

0

は、よく知られているXSLTのデザインパターンである空白を埋めます。

詳細な説明と実際のコードについては、this answerを参照してください。

関連する問題