1

isProduct、isActive、isMandatoryなどのフラグ付きノードを多数含むxmlドキュメントがあり、ノードテキストはTrueまたはFalseの場合があります。

ドキュメントを操作してその構造を維持する必要がありますが、上記のノードを以下のような言語表現に変換します。

< isProduct >True</ isProduct >   ===>   <Type>Product<Type>
< isProduct >False</ isProduct >  ===>   <Type/>

そして、他のフラグノードについても同じです。

展開後の摩擦を最小限に抑えて構成できる、拡張可能でスケーラブルなソリューションを求めています。

拡張可能; より多くのケースがあることを意味します。ステータスを表す2つのフラグのようなもの。つまり、isEmployeeとisCustomerは、4つの異なる名前の付いたものを表すためにドキュメントで使用されます。したがって、4つの可能な組み合わせは、「Employee」、「Customer」、「Customer-Employee」、「None」などの1つの文字列にのみ変換する必要があります。

スケーラブルによる; つまり、スキーマを事前に理解していなくても、ドキュメントサイズに制限がなくても、XMLドキュメントを処理するために使用できます。

これはXSLTを使用して行われる可能性があることを理解していますが、任意のドキュメントを受け入れ、追加のノードを追加または更新して同じドキュメントを生成するXSLTを作成できますか?

4

2 に答える 2

2

次のような入力を想定します。

<gizmo>
  <isProduct>True</isProduct>
  <isFoo>False</isFoo>
  <isBar>True</isBar>
</gizmo>

一般的なアプローチは次のとおりです。

<xsl:template match="gizmo">
  <xsl:copy>
    <xsl:apply-templates select="*" />
  </xsl:copy>
</xsl:template>

<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
  <Type>
    <xsl:if test=". = 'True'">
      <xsl:value-of select="substring-after(local-name(), 'is')" />
    </xsl:if>
  </Type>
</xsl:template>

生成するもの:

<gizmo>
  <Type>Product</Type>
  <Type />
  <Type>Bar</Type>
</gizmo>

さらに一般化されたアプローチでは、(大幅に)変更されたID変換を使用します。

<!-- the identity template... well, sort of -->
<xsl:template match="node() | @*">
  <xsl:copy>
    <!-- all element-type children that begin with 'is' -->
    <xsl:variable name="typeNodes"  select="
      *[substring(local-name(), 1, 2) = 'is']
    " />

    <!-- all other children (incl. elements that don't begin with 'this ' -->
    <xsl:variable name="otherNodes" select="
      @* | node()[not(self::*) or self::*[substring(local-name(), 1, 2) != 'is']]
    " />

    <!-- identity transform all the "other" nodes -->
    <xsl:apply-templates select="$otherNodes" />

    <!-- collapse all the "type" nodes into a string -->
    <xsl:if test="$typeNodes">
      <Type>
        <xsl:variable name="typeString">
          <xsl:apply-templates select="$typeNodes" />
        </xsl:variable>
        <xsl:value-of select="substring-after($typeString, '-')" />
      </Type>
    </xsl:if>
  </xsl:copy>
</xsl:template>

<!-- this collapses all the "type" nodes into a string -->
<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
  <xsl:if test=". = 'True'">
    <xsl:text>-</xsl:text>
    <xsl:value-of select="substring-after(local-name(), 'is')" />
  </xsl:if>
</xsl:template>

<!-- prevent the output of empty text nodes -->
<xsl:template match="text()">
  <xsl:if test="normalize-space() != ''">
    <xsl:value-of select="." />
  </xsl:if>
</xsl:template>

上記は、XML入力をすべて受け取り、同じ構造を出力します。名前が付けられた要素のみが、ダッシュで区切られた文字列として<is*>単一のノードに折りたたまれます。<Type>

<!-- in -->
<foo>
  <fancyNode />
  <gizmo>
    <isProduct>True</isProduct>
    <isFoo>False</isFoo>
    <isBar>True</isBar>
  </gizmo>
</foo>

<!-- out -->
<foo>
  <fancyNode />
  <gizmo>
    <Type>Product-Bar</Type>
  </gizmo>
</foo>
于 2009-07-23T10:02:08.907 に答える
1

ID変換に基づくXSLTのソリューションは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="isProduct">
    <xsl:choose>
      <xsl:when test=". = 'True'"><Type>Product</Type></xsl:when>
      <xsl:otherwise><Type/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
于 2009-07-23T09:53:42.777 に答える