3

XSD で定義されていないすべての要素と属性が出力 XML で (XSLT から) 除外されるように、XML を変換できる XSLT を作成したいと考えています。

この XSD があるとします。

<xs:element name="parent">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="keptElement1" />
            <xs:element name="keptElement2" />
        </xs:sequence>

        <xs:attribute name="keptAttribute1" />
        <xs:attribute name="keptAttribute2" />
    </complexType>
</xsd:element>

そして、この入力 XML があります。

<parent keptAttribute1="kept" 
    keptAttribute2="kept" 
    notKeptAttribute3="not kept" 
    notKeptAttribute4="not kept">

    <notKeptElement0>not kept</notKeptElement0>
    <keptElement1>kept</keptElement1>
    <keptElement2>kept</keptElement2>
    <notKeptElement3>not kept</notKeptElement3>
</parent>

次に、出力 Xml を次のようにしたいと思います。

<parent keptAttribute1="kept" 
    keptAttribute2="kept">

    <keptElement1>kept</keptElement1>
    <keptElement2>kept</keptElement2>
</parent>

要素を指定することでこれを行うことができますが、これは私の xslt スキルが到達する範囲です。一般的に、すべての要素とすべての属性に対してこれを行うのに問題があります。

4

2 に答える 2

6

ここでは 2 つの課題があります。(1) スキーマで宣言された要素名と属性のセットを識別し、ローカル宣言の適切なコンテキスト情報を使用すること、および (2) これらの名前または名前に一致する要素と属性を保持する XSLT を記述すること、および-コンテキスト。

つまり、「XSDスキーマで定義されている(または定義されていない)要素と属性」の意味を明確に指定します。説明のために、スキーマ内の要素または属性の宣言にバインドできる要素および属性を意味すると仮定します。検証エピソードでは、(a) 入力ドキュメント ツリーの任意のポイントにルートがあり、(b) で始まるトップレベルの要素宣言または属性宣言。この仮定にはいくつかの意味があります。(a)ローカル要素の宣言は、コンテキスト内のものにのみ一致します-あなたの例ではkeptElement1keptElement2それらがの子である場合にのみ保持されますparent、それ以外ではありません。(b) 入力内の要素が問題の要素宣言に実際にバインドされるという保証はありません。それらの先祖の 1 つがローカルで無効である場合、XSD 1.0 と 1.1 の両方で物事が急速に複雑になります。(c) 名前付きの型定義から検証を開始することはできません。(d) ローカルの要素または属性の宣言から検証を開始することはできません。

これらの仮定が明確になったので、問題に取り掛かることができます。

最初のタスクでは、(a) スキーマ内の最上位宣言を持つすべての要素と属性、および (b) それらから到達可能なすべての要素と属性のリストを作成する必要があります。トップレベルの宣言の場合、記録する必要があるのは、オブジェクトの種類 (要素または属性) と展開された名前だけです。ローカル オブジェクトの場合、トップレベルの要素宣言からのオブジェクトの種類とフル パスが必要です。サンプル スキーマの場合、リスト (a) は次のもので構成されます。

  • 要素{}親

(私は中括弧で名前空間名を拡張した名前を書く慣習を使用しています; ジェームズ・クラークのために、このクラーク記法と呼ぶ人もいます.)

リスト (b) の構成

  • 要素 {}parent/{}keptElement1
  • 要素 {}parent/{}keptElement2
  • 属性 {}parent/{}keptAttribute1
  • 属性 {}parent/{}keptAttribute2

より複雑なスキーマでは、このリストを生成するプロセスを経るにつれて、一定量の簿記が必要になります。

2 番目のタスクは、要素と属性をリストに保持し、残りを削除する XSLT スタイルシートを作成することです。(ここでは、要素をドロップすると、その内容もすべてドロップすると想定しています。質問は、タグではなく要素について語っています。)

リスト内の各要素に対して、リストで指定されたコンテキストを使用して、適切な恒等変換を記述します。

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

要素ごとに個別のテンプレートを作成するか、複数の要素を一致パターンに書き込むことができます。

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

リスト内の各属性について、同じことを行います。

<xsl:template match="parent/@keptAttribute1">
  <xsl:copy/>
</xsl:template>

要素と属性のデフォルト テンプレートをオーバーライドして、他のすべての要素と属性を抑制します。

<xsl:template match="*|@*"/>

[代わりに、DrMacro が提案しているように、XSLT で関数または名前付きテンプレートを記述して、タスク 1 で生成したリストを参照できます。明示的な一致パターンを使用して繰り返しテンプレートに書き出すのではありません。背景によっては、スタイルシートが何をしているかを理解するのが簡単になったり、難しくなったりすることがあります。]

于 2013-02-12T16:53:29.330 に答える
5

XSLTエンジンにはXSDの知識がないため、これは汎用XSLT処理では実行できません。

これにはいくつかのオプションがあります。

  1. XSDドキュメントをXSLTで直接処理して、実際に宣言されている要素タイプと宣言されていない要素タイプを判別し、その情報を変換で使用します。たとえば、要素がXSDスキーマによって管理されていない名前空間にある場合、その要素が定義されていないことがわかります。または、要素の名前空間がxs:any要素によって「緩い」検証で指定されている場合、それが宣言されていません。

  2. XSDの解析と検証を提供し、XSD処理によって要素に追加された追加のプロパティへのアクセスを提供するSaxonの商用バージョンを使用してください。詳細については、Saxonのドキュメントを参照してください。

Apache xercesプロジェクトにはJavaのXSDパーサーが含まれており、複雑なXSDを処理して、特定のスキーマによって管理されている、または管理されていない要素タイプや名前空間のリストを作成するなど、必要なことを実行できます。したがって、スキーマが比較的静的である場合は、スキーマを前処理して、XSLTがドキュメントを処理するときに使用できる単純なデータファイルを作成するのが最も効率的です。

XSLT 2を使用できるかどうかは言いませんでしたが、可能であれば、一般的な解決策は、特定の要素または属性が宣言されているかどうかを判断する関数を定義し、その関数を標準のID変換の一部として使用することです。XSLT 1では、名前付きテンプレートでも同じ効果を得ることができます。

例えば:

<xsl:function name="local:isGoverned" as="xs:boolean">
   <xsl:param name="context" as="node()"/>
   <xsl:variable name="isGoverned" as="xs:boolean">
   <!-- Do whatever you do to determine governedness,
        whether this is to look at your collected data
        or use Saxon-provide info or whatever.
    -->
  </xsl:variable>
  <xsl:sequence select="$isGoverned"/>
</xsl:function>

そして、あなたのアイデンティティ変換では:

<xsl:template match="*">
  <xsl:copy>
    <xsl:apply-templates 
      select="
         @*[local:isGoverned(.)], 
         (*[local:isGoverned(.)] | 
          node())"
    />
  </xsl:copy>
</xsl:copy>

<xsl:template match="@* | text() | comment() | processing-instruction()">
  <xsl:sequence select="."/>
</xsl:template>

これは、XSDによって管理される要素と属性のみを通過させる効果がありますが、それは理解できます。

エリオット

于 2013-02-12T15:54:44.740 に答える