2

XML:

<t>
  <ScreenSize>
    <Width>1440</Width>
    <Height>900</Height>
  </ScreenSize>
  <ConfigurationHotSpots>
    <Rectangle>
      <Location>
        <X>0</X>
        <Y>0</Y>
      </Location>
      <Size>
        <Width>50</Width>
        <Height>50</Height>
      </Size>
      <X>0</X>
      <Y>0</Y>
      <Width>50</Width>
      <Height>50</Height>
    </Rectangle>
  </ConfigurationHotSpots>
</t>

必要な出力XML:

<t>
  <ScreenSizeWidth>1440</ScreenSizeWidth>
  <ScreenSizeWidth>900</ScreenSizeWidth>
  <ConfigurationHotSpotsRectangleLocationX>0</ConfigurationHotSpotsRectangleLocationX>
  <ConfigurationHotSpotsRectangleLocationY>0</ConfigurationHotSpotsRectangleLocationY>
  <ConfigurationHotSpotsRectangleSizeWidth>50</ConfigurationHotSpotsRectangleSizeWidth>
  <ConfigurationHotSpotsRectangleSizeHeight>50</ConfigurationHotSpotsRectangleSizeHeight>
  <ConfigurationHotSpotsRectangleX>0</ConfigurationHotSpotsRectangleX>
  <ConfigurationHotSpotsRectangleY>0</ConfigurationHotSpotsRectangleY>
  <ConfigurationHotSpotsRectangleWidth>50</ConfigurationHotSpotsRectangleWidth>
  <ConfigurationHotSpotsRectangleHeight>50</ConfigurationHotSpotsRectangleHeight>
</t>

ルール:

  • 定義されたノードセット(この場合<ScreenSize> | <ConfigurationHotSpots>)のすべての要素について、次の手順を実行します。新しい要素が作成されるように、すべての葉の子孫(つまり、子のない子孫)を処理します。この新しい要素の名前は、現在のノードと子のない子孫の間のすべての要素を連結したものである必要があります。
  • ドキュメント全体でこれらの「ブロック」の数は可変であるため、手動テンプレートはありません(つまり、の子孫のみ<ScreenSize>を処理するもの、の子孫のみを処理するもの<ConfigurationHotSpots>など)。

私が現在持っているもの:

<?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="no" indent="yes" />
  <xsl:strip-space elements="*" />

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

  <xsl:template match="ScreenSize|ConfigurationHotSpots">
    <xsl:apply-templates select="descendant::*[not(*)]" mode="descendants" />
  </xsl:template>

  <xsl:template match="*" mode="descendants">
    <xsl:element name="{concat(name(ancestor::*[not(self::t)]), name())}">
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

問題はそのname(ancestor::*[not(self::t)])部分のようです。それは私が望んでいることをしていません(それらの要素の名前を魔法のように次々に出力します)。代わりに、これは私が得るものです:

<?xml version="1.0" encoding="UTF-8"?>
<t>
  <ScreenSizeWidth>1440</ScreenSizeWidth>
  <ScreenSizeHeight>900</ScreenSizeHeight>
  <ConfigurationHotSpotsX>0</ConfigurationHotSpotsX>
  <ConfigurationHotSpotsY>0</ConfigurationHotSpotsY>
  <ConfigurationHotSpotsWidth>50</ConfigurationHotSpotsWidth>
  <ConfigurationHotSpotsHeight>50</ConfigurationHotSpotsHeight>
  <ConfigurationHotSpotsX>0</ConfigurationHotSpotsX>
  <ConfigurationHotSpotsY>0</ConfigurationHotSpotsY>
  <ConfigurationHotSpotsWidth>50</ConfigurationHotSpotsWidth>
  <ConfigurationHotSpotsHeight>50</ConfigurationHotSpotsHeight>
</t>

前もって感謝します!

4

3 に答える 3

3

実行すると、名前のリストは返さname(ancestor::*[not(self::t)])れませんが、一致する最後の名前だけが返されます(または最初の名前ですか?)。

現在行っていることからそれほど遠くない、わずかに異なるアプローチは、「leaf」要素に直接ジャンプするのではなく、各レベルを順番に一致させますが、渡される要素名の連結を実行し続けますあるレベルからパラメータによる注釈へ。

このXSLTを試してください

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="ScreenSize|ConfigurationHotSpots">
        <xsl:apply-templates mode="descendants">
            <xsl:with-param name="name" select="local-name()" />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*" mode="descendants">
        <xsl:param name="name" />
        <xsl:apply-templates mode="descendants">
            <xsl:with-param name="name" select="concat($name, local-name())" />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*[not(*)]" mode="descendants">
        <xsl:param name="name" />
        <xsl:element name="{concat($name, local-name())}">
            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>

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

サンプルXMLに適用すると、次のように出力されます。

<t>
   <ScreenSizeWidth>1440</ScreenSizeWidth>
   <ScreenSizeHeight>900</ScreenSizeHeight>
   <ConfigurationHotSpotsRectangleLocationX>0</ConfigurationHotSpotsRectangleLocationX>
   <ConfigurationHotSpotsRectangleLocationY>0</ConfigurationHotSpotsRectangleLocationY>
   <ConfigurationHotSpotsRectangleSizeWidth>50</ConfigurationHotSpotsRectangleSizeWidth>
   <ConfigurationHotSpotsRectangleSizeHeight>50</ConfigurationHotSpotsRectangleSizeHeight>
   <ConfigurationHotSpotsRectangleX>0</ConfigurationHotSpotsRectangleX>
   <ConfigurationHotSpotsRectangleY>0</ConfigurationHotSpotsRectangleY>
   <ConfigurationHotSpotsRectangleWidth>50</ConfigurationHotSpotsRectangleWidth>
   <ConfigurationHotSpotsRectangleHeight>50</ConfigurationHotSpotsRectangleHeight>
</t>
于 2012-09-12T22:11:28.423 に答える
2

これは、可能な限り最短のソリューションの1つです。累積パスをパラメーターとして渡すほど効率的ではありませんが、あまり深くネストされていない構造の場合、これは重要ではありません。

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

 <xsl:template match=
 "*[not(*) and (ancestor::ScreenSize or ancestor::ConfigurationHotSpots)]">

    <xsl:variable name="vName">
        <xsl:for-each select=
        "ancestor-or-self::*
           [not(descendant::*
                   [self::ScreenSize or self::ConfigurationHotSpots])
           ]">
           <xsl:value-of select="name()"/>
      </xsl:for-each>
  </xsl:variable>
  <xsl:element name="{$vName}"><xsl:value-of select="."/></xsl:element>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

この変換が提供されたXMLドキュメントに適用される場合:

<t>
  <ScreenSize>
    <Width>1440</Width>
    <Height>900</Height>
  </ScreenSize>
  <ConfigurationHotSpots>
    <Rectangle>
      <Location>
        <X>0</X>
        <Y>0</Y>
      </Location>
      <Size>
        <Width>50</Width>
        <Height>50</Height>
      </Size>
      <X>0</X>
      <Y>0</Y>
      <Width>50</Width>
      <Height>50</Height>
    </Rectangle>
  </ConfigurationHotSpots>
</t>

必要な正しい結果が生成されます:

<ScreenSizeWidth>1440</ScreenSizeWidth>
<ScreenSizeHeight>900</ScreenSizeHeight>
<ConfigurationHotSpotsRectangleLocationX>0</ConfigurationHotSpotsRectangleLocationX>
<ConfigurationHotSpotsRectangleLocationY>0</ConfigurationHotSpotsRectangleLocationY>
<ConfigurationHotSpotsRectangleSizeWidth>50</ConfigurationHotSpotsRectangleSizeWidth>
<ConfigurationHotSpotsRectangleSizeHeight>50</ConfigurationHotSpotsRectangleSizeHeight>
<ConfigurationHotSpotsRectangleX>0</ConfigurationHotSpotsRectangleX>
<ConfigurationHotSpotsRectangleY>0</ConfigurationHotSpotsRectangleY>
<ConfigurationHotSpotsRectangleWidth>50</ConfigurationHotSpotsRectangleWidth>
<ConfigurationHotSpotsRectangleHeight>50</ConfigurationHotSpotsRectangleHeight>
于 2012-09-13T03:03:53.817 に答える
2

これがDimitreのソリューションの微調整です。OPのコメントによると、これはより単純で、ScreenSizeなどの既知のルート要素と既知の位置を活用しています...

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

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

 <xsl:template match="*[not(*)]
                       [ancestor::ScreenSize|ancestor::ConfigurationHotSpots]">   
    <xsl:variable name="vName">
        <xsl:for-each select="ancestor-or-self::*[not(self::t)]">
           <xsl:value-of select="local-name()"/>
        </xsl:for-each>
    </xsl:variable>
  <xsl:element name="{$vName}"><xsl:value-of select="."/></xsl:element>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

これが一致条件の代替形式です...

 <xsl:template match="(ScreenSize//* | ConfigurationHotSpots//*)[not(*)]">  

どちらが良いかは実際にはわかりません。パフォーマンスが大した問題ではない場合は、読みやすい方を使用してください。これは、テンプレートの一致試行ごとに2回のドキュメント全体のスキャンを意味することに注意してください。

于 2012-09-13T13:33:58.787 に答える