1

入力ファイルから何もない階層で出力するスタイルシートに取り組んでいます。入力ファイルのすべての要素は互いに兄弟であり、各「ヘッダー」要素は異なるセクションを示します。

サンプル入力ファイル (各ヘッダーの下の実際のセクションは、これより約 10 倍長くなります):

<Header>  
     Header1
</Header>
<Sub1>
     Sub1 first
</Sub1>
<Sub1>
     Sub1 second
</Sub1>
<Sub2>
     Sub2 first, Sub1 second
</Sub2>
<Sub1>
     Sub1 third
</Sub1>
<Sub2>
     Sub2 first, Sub1 third
</Sub2>

<Header>
     Header2
</Header>
Etc...

上記の入力の出力は次のようになります。

<Header>
     Header1
     <Step>
         Sub1 first
     </Step>
     <Step>
         Sub1 second
         <Step>
             Sub2 first, Sub1 second
         </Step>
     </Step>
     <Step>
         Sub1 third
         <Step>
             Sub2 first, Sub1 third
         </Step>
     </Step>
</Header>

<Header>
    Header2
    Etc.....
</Header>

今のところ、「Sub2先、sub1秒」まで出力できています。次の要素が別の Sub2 またはそれより深いサブ要素 (Sub3) ではないことがわかったら、Sub2 テンプレートを中断して、Sub1 テンプレートに戻ります。そしてここから、私の位置変数はまだ「サブ1秒」の位置を持っています。テンプレートが呼び出されるたびに位置情報が処理されるため、「Sub2 が最初、sub1 が 2 番目」のドキュメント順で現在の位置がすべて取得されますが、テンプレートから Sub1 のテンプレートに戻ると、その情報が失われます。ドキュメントの順序で現在の位置を取得して、実際の次の要素が何であるかを判断できないようです。変更可能なグローバル パラメーターまたは変数が理想的ですが、XSLT ではそれが不可能であることはわかっています。

これを達成する方法がわかりません。どんな提案も素晴らしいでしょう!

4

3 に答える 3

1

このXSLT2.0変換

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

 <xsl:template match="/*">
  <t>
   <xsl:apply-templates select="*[1]">
    <xsl:with-param name="pScope" select="*"/>
    <xsl:with-param name="pElemName" select="name(*[1])"/>
   </xsl:apply-templates>
  </t>
 </xsl:template>

 <xsl:template match="*">
  <xsl:param name="pScope"/>
  <xsl:param name="pElemName" select="'Step'"/>

    <xsl:for-each-group select="$pScope"
        group-starting-with="*[name()= name($pScope[1])]">
       <xsl:element name="{$pElemName}">
         <xsl:value-of select="."/>
         <xsl:apply-templates select="current-group()[2]">
          <xsl:with-param name="pScope" select=
           "current-group()[position() > 1]"/>
         </xsl:apply-templates>
       </xsl:element>
    </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

このXMLドキュメントに適用した場合(提供されたものに基づいていますが、top要素にラップされ、異なる名前のヘッダーがもう1つ追加されています):

<t>
    <Header>Header1</Header>
    <Sub1>Sub1 first</Sub1>
    <Sub1>Sub1 second</Sub1>
    <Sub2>Sub2 first, Sub1 second</Sub2>
    <Sub1>Sub1 third</Sub1>
    <Sub2>Sub2 first, Sub1 third</Sub2>
    <Header>Header2</Header>
    <x>Sub1 first</x>
    <x>Sub1 second</x>
    <y>Sub2 first, Sub1 second</y>
    <x>Sub1 third</x>
    <z>Sub2 first, Sub1 third</z>
</t>

必要な正しい出力を生成します

<t>
   <Header>Header1<Step>Sub1 first</Step>
      <Step>Sub1 second<Step>Sub2 first, Sub1 second</Step>
      </Step>
      <Step>Sub1 third<Step>Sub2 first, Sub1 third</Step>
      </Step>
   </Header>
   <Header>Header2<Step>Sub1 first</Step>
      <Step>Sub1 second<Step>Sub2 first, Sub1 second</Step>
      </Step>
      <Step>Sub1 third<Step>Sub2 first, Sub1 third</Step>
      </Step>
   </Header>
</t>

説明

  1. 属性で使用<xsl:for-each-group>group-starting-withます。

  2. きめ細かい処理-テンプレートはの2番目の要素に適用されcurrent-group()、次のグループ化のスコープがパラメーターとして渡されます。

于 2011-02-16T04:12:02.123 に答える
0

XSLT 1.0 スタイルシートをお楽しみください:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="*">
        <xsl:param name="pNames" select="'|'"/>
        <xsl:if test="not(contains($pNames,concat('|',name(),'|')))">
            <xsl:variable name="vNext" select="following-sibling::*[1]"/>
            <xsl:copy>
                <xsl:apply-templates select="node()[1]"/>
                <xsl:apply-templates select="$vNext">
                    <xsl:with-param name="pNames"
                                    select="concat($pNames,name(),'|')"/>
                </xsl:apply-templates>
            </xsl:copy>
            <xsl:apply-templates select="$vNext" mode="search">
                <xsl:with-param name="pNames" select="$pNames"/>
                <xsl:with-param name="pSearch" select="name()"/>
            </xsl:apply-templates>
        </xsl:if>
    </xsl:template>
    <xsl:template match="*" mode="search">
        <xsl:param name="pNames"/>
        <xsl:param name="pSearch"/>
        <xsl:if test="not(contains($pNames,concat('|',name(),'|')))">
            <xsl:choose>
                <xsl:when test="name()=$pSearch">
                    <xsl:apply-templates select=".">
                        <xsl:with-param name="pNames" select="$pNames"/>
                    </xsl:apply-templates>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="following-sibling::*[1]"
                                         mode="search">
                        <xsl:with-param name="pNames" select="$pNames"/>
                        <xsl:with-param name="pSearch" select="$pSearch"/>
                    </xsl:apply-templates>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

整形式入力の場合:

<root>
    <Header>Header1</Header>
    <Sub1>Sub1 first</Sub1>
    <Sub1>Sub1 second</Sub1>
    <Sub2>Sub2 first, Sub1 second</Sub2>
    <Sub1>Sub1 third</Sub1>
    <Sub2>Sub2 first, Sub1 third</Sub2>
    <Header>Header2</Header>
</root>

出力:

<root>
    <Header>Header1
        <Sub1>Sub1 first</Sub1>
        <Sub1>Sub1 second
            <Sub2>Sub2 first, Sub1 second</Sub2>
        </Sub1>
        <Sub1>Sub1 third
            <Sub2>Sub2 first, Sub1 third</Sub2>
        </Sub1>
    </Header>
    <Header>Header2</Header>
</root>

名前の置換と複数の名前を持つ 1 つのレベルの新しい要求により、このスタイルシートは次のようになります。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:r="rules"
 exclude-result-prefixes="r">
    <r:r m="|Header|">Header</r:r>
    <r:r m="|Sub1|">Step</r:r>
    <r:r m="|Sub2|">Step</r:r>
    <xsl:variable name="vRules" select="document('')/*/r:r"/>
    <xsl:template match="*">
        <xsl:param name="pNames" select="'|'"/>
        <xsl:variable name="vName" select="concat('|',name(),'|')"/>
        <xsl:if test="not(contains($pNames,$vName))">
            <xsl:variable name="vNext" select="following-sibling::*[1]"/>
            <xsl:variable name="vMatch"
                          select="$vRules[contains(@m,$vName)]"/>
            <xsl:variable name="vReplace"
                 select="concat($vMatch,name((.)[not($vMatch)]))"/>
            <xsl:variable name="vSearch"
                          select="concat($vMatch/@m,$vName)"/>
            <xsl:element name="{$vReplace}">
                <xsl:apply-templates select="node()[1]"/>
                <xsl:apply-templates select="$vNext">
                    <xsl:with-param name="pNames"
                                    select="concat($pNames,$vSearch)"/>
                </xsl:apply-templates>
            </xsl:element>
            <xsl:apply-templates select="$vNext" mode="search">
                <xsl:with-param name="pNames" select="$pNames"/>
                <xsl:with-param name="pSearch" select="$vSearch"/>
            </xsl:apply-templates>
        </xsl:if>
    </xsl:template>
    <xsl:template match="*" mode="search">
        <xsl:param name="pNames"/>
        <xsl:param name="pSearch"/>
        <xsl:variable name="vName" select="concat('|',name(),'|')"/>
        <xsl:choose>
            <xsl:when test="contains($pNames,$vName)"/>
            <xsl:when test="contains($pSearch,$vName)">
                <xsl:apply-templates select=".">
                    <xsl:with-param name="pNames" select="$pNames"/>
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="following-sibling::*[1]"
                                         mode="search">
                    <xsl:with-param name="pNames" select="$pNames"/>
                    <xsl:with-param name="pSearch" select="$pSearch"/>
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

出力:

<root>
    <Header>Header1
        <Step>Sub1 first</Step>
        <Step>Sub1 second
            <Step>Sub2 first, Sub1 second</Step>
        </Step>
        <Step>Sub1 third
            <Step>Sub2 first, Sub1 third</Step>
        </Step>
    </Header>
    <Header>Header2</Header>
</root>

: 同じレベルの同義語は、r:r/@m

于 2011-02-17T19:10:50.520 に答える
-1

入力 xml は実際には xml ではないため、ルート ノードを追加しました。この種の処理を行うために xslt を使用しないことをお勧めします。しかし、もしそうしなければならない場合は、ここから始めましょう。

ところで。サブセクションには何らかの ID がありますか?

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/Root">
    <Root>
      <xsl:apply-templates select="Header"/>
    </Root>
  </xsl:template>

  <xsl:template match="Header">
    <Header>
      <xsl:copy-of select="text()"/>
      <xsl:variable name="current" select="."/>
      <xsl:apply-templates select="/Root/Sub1[preceding-sibling::Header[1]/. = $current]"/>
    </Header>
  </xsl:template>

  <xsl:template match="Sub1">
    <Step>
      <xsl:copy-of select="text()"/>
      <xsl:variable name="current" select="."/>
      <xsl:apply-templates select="/Root/Sub2[preceding-sibling::Sub1[1]/. = $current]"/>
    </Step>
  </xsl:template>

  <xsl:template match="Sub2">
    <Step>
      <xsl:copy-of select="text()"/>
      <!-- todo -->
    </Step>
  </xsl:template>

</xsl:stylesheet>
于 2011-02-16T00:33:43.970 に答える