1

学校のクラスの生徒向けのデータベースアプリケーションがあります。1つのパッケージで大量のデータをユーザーインターフェイスに送信します。複雑なXMLをアセンブルするには、複数のデータをXMLとしてフェッチしてから、それらを組み合わせる必要があります。

XSLTを使用してSQLJOINに似た何かを実行する方法を見つけようとしています。たとえば、次の2つのXMLドキュメントがあるとします。

<Xml>
    <Classes>
        <Class Name="BIOLOGY101" ClassId="11"/>
        <Class Name="PHYSICS101" ClassId="13"/>
        <Class Name="CALCULUS101" ClassId="17"/>
        <Class Name="BIOLOGY101" ClassId="19"/>
    </Classes>
</Xml>


<Xml>
    <Students>
        <Student Name="Bob Johnson" ClassId="11"/>
        <Student Name="Bob Johnson" ClassId="17"/>
        <Student Name="Bob Johnson" ClassId="19"/>
        <Student Name="Joe Jackson" ClassId="11"/>
        <Student Name="Joe Jackson" ClassId="13"/>
        <Student Name="Joe Jackson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="13"/>
        <Student Name="Rick Robertson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="19"/>
    </Students>
</Xml>

これを生成するために、単一のXSLTを介してそれらを実行したいと思います。

<Xml>
    <Classes>
        <Class Name="BIOLOGY101" ClassId="11">
            <Student Name="Bob Johnson"/>
            <Student Name="Joe Jackson"/>
        </Class>
        <Class Name="PHYSICS101" ClassId="13">
            <Student Name="Joe Jackson"/>
            <Student Name="Rick Robertson"/>
        </Class>
        <Class Name="CALCULUS101" ClassId="17">
            <Student Name="Rick Robertson" "/>
            <Student Name="Joe Jackson"/>
            <Student Name="Bob Johnson"/>
        </Class>
        <Class Name="BIOLOGY101" ClassId="19">
            <Student Name="Bob Johnson"/>
            <Student Name="Rick Robertson" />
        </Class>
    </Classes>
</Xml>

<Student>ノードからClassId属性を省略したことに注意してください。

処理が簡単になる場合は、2つのXMLドキュメントを1つのドキュメントにまとめてXSLTに渡すことができます。

このデータはデータベースからのものであるため、さまざまなXMLドキュメントに参加します。クラスを学校に、成績を生徒に、またはアクティビティを学校に参加させる場合があります。ただし、これらはすべて同じパターンに従います。子ノードの数値属性は、親ノードの数値属性に対応します。

4

3 に答える 3

3

XSLTでこれを達成することは、SQLの場合ほど簡単ではありませんが、事前に2つの入力ファイルを1つのドキュメントにアセンブルしたと仮定します(問題がなければ、これをお勧めします)。

<Xml>
    <Classes>
        <Class Name="BIOLOGY101" ClassId="11"/>
        <Class Name="PHYSICS101" ClassId="13"/>
        <Class Name="CALCULUS101" ClassId="17"/>
        <Class Name="BIOLOGY101" ClassId="19"/>
    </Classes>
    <Students>
        <Student Name="Bob Johnson" ClassId="11"/>
        <Student Name="Bob Johnson" ClassId="17"/>
        <Student Name="Bob Johnson" ClassId="19"/>
        <Student Name="Joe Jackson" ClassId="11"/>
        <Student Name="Joe Jackson" ClassId="13"/>
        <Student Name="Joe Jackson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="13"/>
        <Student Name="Rick Robertson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="19"/>
    </Students>
</Xml>

このXSLTを使用して、データを結合できます。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <!-- Key to allow retrieving students by their class -->
  <xsl:key name="kStudentByClass" match="Student" use="@ClassId"/>

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

  <xsl:template match="Class">
    <xsl:copy>
      <!-- Copy all attributes for this Class element -->
      <xsl:apply-templates select="@*" />

      <!-- Copy in all students for the current class -->
      <xsl:apply-templates select="key('kStudentByClass', @ClassId)" />
    </xsl:copy>
  </xsl:template>

  <!-- Omit the Students element and Students' ClassId 
       attribute from the output -->
  <xsl:template match="Students | Student/@ClassId" />
</xsl:stylesheet>

上記の入力XMLでこれを実行すると、次のようになります。

<Xml>
  <Classes>
    <Class Name="BIOLOGY101" ClassId="11">
      <Student Name="Bob Johnson" />
      <Student Name="Joe Jackson" />
    </Class>
    <Class Name="PHYSICS101" ClassId="13">
      <Student Name="Joe Jackson" />
      <Student Name="Rick Robertson" />
    </Class>
    <Class Name="CALCULUS101" ClassId="17">
      <Student Name="Bob Johnson" />
      <Student Name="Joe Jackson" />
      <Student Name="Rick Robertson" />
    </Class>
    <Class Name="BIOLOGY101" ClassId="19">
      <Student Name="Bob Johnson" />
      <Student Name="Rick Robertson" />
    </Class>
  </Classes>
</Xml>

また、XMLを少し変更して、外側のグループと内側のグループ、および一致する属性を次のように示すことができる場合は、次のようになります。

<Xml>
  <Classes outer="true" matchAttribute="ClassId">
     ....
  </Classes>
  <Students inner="true">
     ....
  </Students>
</Xml>

次に、このより一般的なXSLTを使用できます。これは、効率は劣りますが、上記と同様の入力に対して機能するはずです。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:variable name="innerItems"
                select="/*/*[@inner = 'true']/*" />
  <xsl:variable name="matchAttribute" 
                select="/*/*[@outer = 'true']/@matchAttribute" />

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

  <xsl:template match="/*/*[@outer = 'true']/*">
    <xsl:copy>
      <!-- Copy all attributes for this element -->
      <xsl:apply-templates select="@*" />

      <xsl:variable name="matchValue" 
                    select="@*[local-name() = $matchAttribute]"/>
      <!-- Copy in all matching items -->
      <xsl:apply-templates 
        select="$innerItems[@*[local-name() = $matchAttribute] =
                      $matchValue]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*/*[@inner = 'true']/*">
    <xsl:copy>
      <xsl:apply-templates 
         select="@*[local-name() != $matchAttribute] | node()" />
    </xsl:copy>
  </xsl:template>

  <!-- Omit the inner group element, and the meta attributes-->
  <xsl:template match="/*/*[@inner = 'true'] | @outer | @matchAttribute" />
</xsl:stylesheet>
于 2013-03-08T20:32:36.377 に答える
3

JLRisheの答えは正しいものであり、完全に機能しますが、誰かが見に来た場合に備えて、XSLTを使用して2つのファイルを結合する必要がある場合は、次のようにすることができます。

a.xml

<Xml>
    <Classes>
        <Class Name="BIOLOGY101" ClassId="11"/>
        <Class Name="PHYSICS101" ClassId="13"/>
        <Class Name="CALCULUS101" ClassId="17"/>
        <Class Name="BIOLOGY101" ClassId="19"/>
    </Classes>
</Xml>

b.xml

<Xml>
    <Students>
        <Student Name="Bob Johnson" ClassId="11"/>
        <Student Name="Bob Johnson" ClassId="17"/>
        <Student Name="Bob Johnson" ClassId="19"/>
        <Student Name="Joe Jackson" ClassId="11"/>
        <Student Name="Joe Jackson" ClassId="13"/>
        <Student Name="Joe Jackson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="13"/>
        <Student Name="Rick Robertson" ClassId="17"/>
        <Student Name="Rick Robertson" ClassId="19"/>
    </Students>
</Xml>

スタイルシート

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="Class">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <!-- Apply <Student> elements from b.xml -->
      <xsl:apply-templates
        select="document('b.xml')/Xml/Students/Student
          [@ClassId = current()/@ClassId]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Student">
    <xsl:copy>
      <xsl:apply-templates select="@Name"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

出力

<?xml version="1.0"?>
<Xml>
  <Classes>
    <Class Name="BIOLOGY101" ClassId="11">
      <Student Name="Bob Johnson"/>
      <Student Name="Joe Jackson"/>
    </Class>
    <Class Name="PHYSICS101" ClassId="13">
      <Student Name="Joe Jackson"/>
      <Student Name="Rick Robertson"/>
    </Class>
    <Class Name="CALCULUS101" ClassId="17">
      <Student Name="Bob Johnson"/>
      <Student Name="Joe Jackson"/>
      <Student Name="Rick Robertson"/>
    </Class>
    <Class Name="BIOLOGY101" ClassId="19">
      <Student Name="Bob Johnson"/>
      <Student Name="Rick Robertson"/>
    </Class>
  </Classes>
</Xml>
于 2013-03-08T20:45:47.993 に答える
0

JLRisheの答えは素晴らしかった。それを手に入れるまで私は迷子になりました。(質問を投稿しました。)

SQL Serverからのデータを処理していることがわかっているので、常に2つのテーブルに対応する親ノードと子ノードがあり、それらを接続する属性は2つのテーブルのフィールドです。主キーフィールドを持つ独立したテーブルと外部キーフィールドを持つ従属テーブル。そこで、私は自分の非常に具体的なニーズに合わせてソリューションを次のように一般化しました。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>


    <!-- Parameters to make solution general -->
    <xsl:param name="ParentNode">Class</xsl:param>
    <xsl:param name="ParentIdAttribute">ClassId</xsl:param>
    <xsl:param name="ChildNode">Student</xsl:param>
    <xsl:param name="ChildReferenceAttribute">ClassId</xsl:param>

    <!-- Key to allow retrieving child nodes by the Parent node -->
    <xsl:key name="kChildByParent" match="*[name() = $ChildNode]" use="@*[name()=$ChildReferenceAttribute]"/>

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


    <!-- Parent Node Matching Template -->
    <xsl:template match="*[name() = $ParentNode]">
        <xsl:copy>
            <!-- Copy all attributes and child nodes for the Parent element -->
            <xsl:apply-templates select="@* | node()" />

            <!-- Copy in all children that reference the current parent -->
            <xsl:apply-templates select="key('kChildByParent', @*[name()=$ParentIdAttribute])" />
        </xsl:copy>
    </xsl:template>

    <!-- Omit the child nodes and reference attribute of the child nodes, -->
    <xsl:template match="ChildNodes | *[name() = $ChildNode]/@*[name()=$ChildReferenceAttribute]" />

</xsl:stylesheet>
于 2013-03-09T01:41:27.867 に答える