0

さまざまな構造とタグを持つ多数の XML ファイルに XSL スタイルシートを適用しています。すべてのファイルに 1 つの XSL スタイルシートを使用したいと考えています。新しいコンテンツ構造を持つ XML ファイルが追加された場合に、新しい xpath を簡単に追加できます。

(これは Apache の Solr で使用するためのものであり、出力ドキュメントは特定の方法で表示される必要があると付け加えるかもしれません。)

これまでのところ、さまざまなフィールドをコピーするコードを次のように書くことができました。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt" xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" xalan:indent-amount="4" omit-xml-declaration="yes"/>
<xsl:template match="/">
    <xsl:param name="fileName" />
    <xsl:param name="fileURI" />
    <xsl:param name="timeCreatedLong" />
<add>
    <doc>
        <!-- REQUIRED FIELDS. DO NOT CHANGE -->
            <field name="fileName"><xsl:value-of select="$fileName" /></field>
            <field name="fileURI"><xsl:value-of select="$fileURI" /></field>
            <field name="timeCreatedLong"><xsl:value-of select="$timeCreatedLong" /></field>
        <!-- //END OF REQUIRED FIELDS -->

        <!-- DSV INTERNAL XML -->
            <!-- Consignment Identifiers -->
            <field name="consignmentIdentifiers"><xsl:value-of select="//consignmentlist/consignment/consignmentId" /></field>
            <field name="consignmentIdentifiers"><xsl:value-of select="//consignmentlist/consignment/references/reference[@type = 'consignment_number']/value" /></field>
            <!-- //Consignment Identifiers -->

            <!-- Transport company information -->
            <field name="carrier"><xsl:value-of select="//transport/transportservice/carriername" /></field>
            <field name="carrierService"><xsl:value-of select="//transport/transportservice/carrierservicename" /></field>
            <field name="transportMode"><xsl:value-of select="//transport/transportservice/transportmode" /></field>
            <!-- //Transport company information -->
        <!-- //DSV INTERNAL XML -->
        

        
        <!-- POSTEN NORDIC LOGISTICS ORDER.XML -->
            <!-- Consignment Identifiers -->
            <field name="consignmentIdentifiers"><xsl:value-of select="//TransportJob/Consignment/@consignmentId" /></field>
            <!-- //Consignment Identifiers -->

            <!-- Transport company information -->
            <field name="definedBy"><xsl:value-of select="//TransportJob/@definedBy" /></field>
            <field name="carrier"><xsl:value-of select="//TransportJob/@profile" /></field>
            <!-- //Transport company information -->
        <!-- //POSTEN NORDIC LOGISTICS ORDER.XML -->
    </doc>
</add>
</xsl:template>

</xsl:stylesheet>

処理されたファイル構造に応じて、出力は次のようになります。

<add>
<doc>
    <field name="fileName">00373323993931432015_BOOKING.INTERNALXML</field>
    <field name="fileURI">/usr/dropbox/Dropbox/shared/file-search/00373323993931432015_BOOKING.INTERNALXML</field>
    <field name="timeCreatedLong">1377507872000</field>
    <field name="consignmentIdentifiers"/>
    <field name="consignmentIdentifiers">00373323993931432015</field>
    <field name="carrier">DSV</field>
    <field name="carrierService">DSV Mypack</field>
    <field name="transportMode">ROAD</field>
    <field name="consignmentIdentifiers"/>
    <field name="definedBy"/>
    <field name="carrier"/>
</doc>
</add>

ご覧のとおり、Solr サーバーに送信する前に削除したい空/自己終了要素がいくつかあります。

本当の問題は、この XSL を適用した後に、生成された空のタグを削除する方法があるかどうかです。前述のように、これを同じ XSL ファイルで実行したいと考えています。

4

3 に答える 3

1

要素または属性に一致するいくつかの一般的なテンプレートを使用することを改善するための 1 つの提案ですが、出力するフィールドの「名前」に設定できるパラメーターを取ります。

最初のテンプレートは実際にfield要素を出力し、それに応じて name 属性を設定します

<xsl:template match="*|@*">
    <xsl:param name="fieldName" />
    <field name="{$fieldName}">
       <xsl:value-of select="." />
    </field>
</xsl:template>

もう 1 つは、値のない要素や属性を無視するために使用されます。

<xsl:template match="*[normalize-space()='']|@*[normalize-space()='']" />

(ここでは、より具体的なテンプレート (空の文字列をチェックする Xpath 式を持つテンプレート) が、非具体的なテンプレートよりも優先されることに注意してください。)

次に、これを書く代わりに:

<field name="consignmentIdentifiers">
    <xsl:value-of select="//consignmentlist/consignment/consignmentId" />
</field>

あなたはこれを書くでしょう

<xsl:apply-templates select="//consignmentlist/consignment/consignmentId">
    <xsl:with-param name="fieldName" select="'consignmentIdentifiers'" />
</xsl:apply-templates>

出力したい他のすべてのフィールドについても同様です。したがって、各ステートメントの前後にxsl:ifステートメントを記述することについて心配する必要はありません。それは、あなたが現在行っていることに対するほんのわずかな変化です。

編集: XSLT を独自の出力に適用したい場合は...

次に、これを行う方法は、「2 パス変換」を使用することです。ここで 2 つの XSLT を使用するのが理想的ですが、単純に新しい要素を出力するのではなく、「最初のパス」として 1 つを実行したい場合は、既存のコードを変数でラップします。

<xsl:variable name="HereBeDragons">
   <add>
      <doc>
          <field ...
      </doc>
   </add>
</xsl:variable>

これで、現在の出力を含む変数が作成され、空のタグが追加されました。XSLT 2.0 を使用していた場合は、これを行うだけで、変数内の要素に一致するテンプレートを探し始めることができます。

<xsl:apply-templates select="$HereBeDragons/*"/>

しかし、XSLT 1.0 では、ノード セットではないというメッセージが表示される可能性があります。XSLT 1.0 では、変数は実際には「結果ツリー フラグメント」を格納しており、テンプレートを使用できるようにノード セットに変換する必要があります。ここで EXSLT を使用しているように見えるので、これを実行できるはずです。

<xsl:apply-templates select="exslt:node-set($HereBeDragons)/*" />

変数にテンプレートを適用し始めたので、必要に応じてデータを処理するためのテンプレートを追加するだけです。インデンティ テンプレート用のテンプレートが 1 つあります。

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

もう1つは、空のフィールドを無視することです

<xsl:template match="field[normalize-space()='']" />

ただし、これらのテンプレートは 1 回目のパスと 2 回目のパスの両方に適用されることに注意してください。2 番目のパスで異なる動作をする特定の要素に一致するテンプレートが必要な場合は、テンプレートのモードプロパティを使用してそれらを区別する必要がある場合があります。

もちろん、この方法で 2 パス変換を行うことは、メモリと速度の両方の点で効率的ではありません。そのため、最初から空のタグを出力しないように元の XSLT にロジックを追加することが提案されています。

于 2013-08-27T13:11:18.597 に答える
0

ソースが空でない場合にのみ要素を作成する XSLT にチェックを追加できます。たとえば、フィールドのcarrier場合は次のことができます。

<xsl:if test="not(//transport/transportservice/carriername='')">
 <field name="carrier">
   <xsl:value-of select="//transport/transportservice/carriername" />
 </field>   
</xsl:if>

これを行うと、出力に空のフィールドが表示されなくなります。

編集:出力を確認したい場合は、identity-rule を使用して非常に効率的な方法があります。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output method="xml" indent="yes"/>

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

<xsl:template match="field[normalize-space()='']"/>

</xsl:stylesheet>
于 2013-08-27T08:41:55.053 に答える
0

XSLT 2.0 を仮定すると (あなたはまだ言っていません)、私は次のようにします:

<xsl:sequence select="
   f:field('carrier', //transport/transportservice/carriername),
   f:field('carrierService', //transport/transportservice/carrierservicename),
   f:field('transportMode', //transport/transportservice/transportmode),
   ..."/>

f:field が次のように定義されている場合

<xsl:function name="f:field" as="element(field)?">
  <xsl:param name="name" as="xs:string"/>
  <xsl:param name="value" as="xs:string?"/>
  <xsl:if test="$value">
    <field name="{$name}">
      <xsl:value-of select="$value"/>
    </field>
  </xsl:if>
</xsl:function>
于 2013-08-27T09:29:21.197 に答える