0

以前に投稿したシナリオについては素晴らしい回答を得ましたが、解決策は機能しませんでした (少なくとも、完全な XML ファイルに対しては機能しませんでした)。

素晴らしく機能する現在の XSLT を維持し、この非常にインデントされた情報にアクセスする機能を追加するものが必要です。

 <Root>
    <Subjects>
    <...more XML Data>
    <Data>
      <...other XML Data>
      <Demographic_Information>
            <Age1>33</Age1>
            <Age2>66</Age2>
            <Age3 />
            <Age4 />
            <Age5 />
            <Age6 />
            <Age7 />
            <Age8 />
            <Age9 />
            <Age10 />
            <Gender1>M</Gender1>
            <Gender2>F</Gender2>
            <Gender3 />
            <Gender4 />
            <Gender5 />
            <Gender6 />
            <Gender7 />
            <Gender8 />
            <Gender9 />
            <Gender10 />
            <Race1>W</Race1>
            <Race2>H</Race2>
            <Race3 />
            <Race4 />
            <Race5 />
            <Race6 />
            <Race7 />
            <Race8 />
            <Race9 />
            <Race10 />
        </Demographic_Information>
        </...other XML Data>
    </Data>
    </...more XML Data>
   </Subjects>
  </Root>

そして、人口統計情報の出力が次のようになる必要があります

<Person subject="1">
    <Age>33</Age>
    <Gender>M</Gender>
    <Race>W</Race>
</Person>
<Person subject="2">
    <Age>66</Age>
    <Gender>F</Gender>
    <Race>A</Race>
</Person>

また、コードで何が起こっているかについての簡単な説明もあると、学習が容易になります。提供された最後のバージョンをステップ実行しようとしましたが、特定の時点で迷子になり、それが何をしているのか本当にわかりませんでした.

いつものように、私は助けに感謝し、最良の回答を提供してくれた投稿者に感謝の意を表します.

4

2 に答える 2

0

以前の回答 ( XSLT For-Each loop to get data from enumerated tags? ) に続いて、これには簡単な変更が必要です。とはいえ、途中で道に迷ったということで、最後に説明を加えておきます。

この XSLT の場合:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable
     name="vNums"
     select="'0123456789'"/>

  <xsl:key
     name="kElemByNumber"
     match="Demographic_Information/*"
     use="translate(name(), translate(name(), $vNums, ''), '')"/>

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

  <xsl:template match="Demographic_Information">
    <Demographic_Information>
      <xsl:apply-templates 
        select="*[generate-id() = 
                  generate-id(key(
                    'kElemByNumber',
                    translate(name(), translate(name(), $vNums, ''),
                    ''
                  ))[1])][normalize-space()]">
        <xsl:sort
          select="translate(name(), translate(name(), $vNums, ''), '')"
          data-type="number"/>
      </xsl:apply-templates>
    </Demographic_Information>
  </xsl:template>

  <xsl:template match="Demographic_Information/*">
    <Person subject="{position()}">
      <xsl:apply-templates
        select="key('kElemByNumber', position())"
        mode="children">
        <xsl:sort select="name()"/>
      </xsl:apply-templates>
    </Person>
  </xsl:template>

  <xsl:template match="Demographic_Information/*" mode="children">
    <xsl:element name="{translate(name(), $vNums, '')}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

...ソース XML に対して適用されます (「他の/その他の XML データ」のインスタンスがコメントになるように少し変更されています [したがって、正しい XML ドキュメントを保証します]):

<Root>
  <Subjects>
    <!--<...more XML Data>-->
    <Data>
      <!--<...other XML Data>-->
      <Demographic_Information>
        <Age1>33</Age1>
        <Age2>66</Age2>
        <Age3/>
        <Age4/>
        <Age5/>
        <Age6/>
        <Age7/>
        <Age8/>
        <Age9/>
        <Age10/>
        <Gender1>M</Gender1>
        <Gender2>F</Gender2>
        <Gender3/>
        <Gender4/>
        <Gender5/>
        <Gender6/>
        <Gender7/>
        <Gender8/>
        <Gender9/>
        <Gender10/>
        <Race1>W</Race1>
        <Race2>H</Race2>
        <Race3/>
        <Race4/>
        <Race5/>
        <Race6/>
        <Race7/>
        <Race8/>
        <Race9/>
        <Race10/>
      </Demographic_Information>
      <!--</...other XML Data>-->
    </Data>
    <!--</...more XML Data>-->
  </Subjects>
</Root>

...必要な結果が生成されます。

<Root>
  <Subjects>
    <!--<...more XML Data>-->
    <Data>
      <!--<...other XML Data>-->
      <Demographic_Information>
        <Person subject="1">
          <Age>33</Age>
          <Gender>M</Gender>
          <Race>W</Race>
        </Person>
        <Person subject="2">
          <Age>66</Age>
          <Gender>F</Gender>
          <Race>H</Race>
        </Person>
      </Demographic_Information>
      <!--</...other XML Data>-->
    </Data>
    <!--</...more XML Data>-->
  </Subjects>
</Root>

説明:

<xsl:template>各宣言から始めて、この手順を順を追って見ていきましょう。

テンプレート #1: ID テンプレート

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

このテンプレート (ちなみに、この回答と以前の回答との間の唯一の変更点です) には、すべてのノード (要素、テキスト ノード、コメント、および処理命令) とすべての属性をソース XML から結果の XML。したがって、そのままにしておくと、この 1 つのテンプレートで元の XML の正確なコピーが作成されます。このテンプレートを他のテンプレートでオーバーライドすることは、XSLT の最も基本的な設計パターンの 1 つです。

私たちの場合、このテンプレートは、直接一致しないノード/属性 (一部またはその子ではないすべてのノード/属性など<Demographic_Information>) がそのまま結果ドキュメントにコピーされることを保証します。

テンプレート #2: 変更<Demographic_Information>

<xsl:template match="Demographic_Information">
  <Demographic_Information>
    <xsl:apply-templates 
      select="*[generate-id() = 
                generate-id(key(
                  'kElemByNumber',
                  translate(name(), translate(name(), $vNums, ''),
                  ''
                ))[1])][normalize-space()]">
      <xsl:sort
        select="translate(name(), translate(name(), $vNums, ''), '')"
        data-type="number"/>
    </xsl:apply-templates>
  </Demographic_Information>
</xsl:template>

このテンプレート (すべての<Demographic_Information>要素に一致) は、Muenchian Groupingと呼ばれる手法を利用しています。これは、XSLT 1.0 で同様の要素をグループ化する方法です。この手法について詳しく説明するつもりはありません。SO で簡単に検索すると手順を示すいくつかの 質問 表示されます。

Muenchian Grouping を理解したら、XSLT の上部で使用しているキーに注意してください。

<xsl:key
  name="kElemByNumber"
  match="Demographic_Information/*"
  use="translate(name(), translate(name(), $vNums, ''), '')"/>

<Demographic_Information>実際には、これは「名前の数値部分に基づいて のすべての子要素を教えてください」と言っています。したがって、すべての「1」要素がグループ化され、すべての「2」要素がグループ化されます。

「名前の数値部分」の部分は、特定の文字セットのみを保持する方法であるDouble Translate Methodを使用して実現されます。この場合、このメソッドを使用して、数値の文字のみをキーとして選択します。

テンプレート #3: の子要素を変更する<Demographic_Information>

<xsl:template match="Demographic_Information/*">
  <Person subject="{position()}">
    <xsl:apply-templates
      select="key('kElemByNumber', position())"
      mode="children">
      <xsl:sort select="name()"/>
    </xsl:apply-templates>
  </Person>
</xsl:template>

このテンプレートは前のテンプレートから実行されることに注意してください。したがって、これは Muenchian Grouping シーケンスの一部です。戦術的には、これは、このテンプレートが、数値部分が一意であるノードに対してのみ実行されることを意味します (つまり、最初の "1" 要素、最初の "2" 要素などに対して実行されます)。

の子要素が見つかる<Demographic_Information>と、プロセッサは新しい要素を作成し、作業ツリー (この場合は のすべての子) 内の現在の位置の値を持つ属性を<Person>与えるように指示されます。次に、正しい基準に一致するキー内のすべての要素 ( の子要素で構成されていることを思い出してください) にテンプレートを適用し、処理時に名前で並べ替えます。subject<Demographic_Information><Demographic_Information>

この呼び出しmode="children"に割り当てた属性に注意してください。<xsl:apply-templates>これは、現在のセットアップで必要です: もしそれがなければ、無限ループを作成します ( の子に一致するテンプレートは、現在のテンプレートに一致する の<Demographic_Children>すべての子に対してテンプレートを適用するように指示されます)。 <Demographic_Information>.)。

テンプレート #4: の子要素の変更<Demographic_Information>(「子」モード)

<xsl:template match="Demographic_Information/*" mode="children">
  <xsl:element name="{translate(name(), $vNums, '')}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<Demographic_Information>これはかなり単純です: (モードの下で) foundのすべての子に対してchildren、新しい要素が作成され、現在の要素と同じ名前が付けられますが、数値部分は削除されます。最後に、現在のノードの残っている子にテンプレートを適用することによって、この要素のコンテンツが取り込まれます (この場合、text()ノードのみが残ります。したがって、<xsl:apply-templates>テキストを出力するプロセッサの既定のテンプレートが使用されます)。これにより、最終出力が生成されます。


この説明があっても、ここでは多くのことが行われています。私が提供できる明確さが他にあれば教えてください。

于 2013-04-30T05:22:11.257 に答える