一般的なXMLドキュメント操作
-
19-09-2019 - |
質問
ISProduct、ISACTIVE、ISMANDATORYなどのフラグ付きノードを含むXMLドキュメントがあります。
ドキュメントを操作して構造を維持する必要がありますが、上記のノードを以下のように口頭表現に変換する必要があります。
< isProduct >True</ isProduct > ===> <Type>Product<Type>
< isProduct >False</ isProduct > ===> <Type/>
他のフラグノードについても同じです。
展開後に最小限の摩擦で構成できる拡張可能でスケーラブルなソリューションを求めています。
拡張可能;私たちは、より多くのケースがあることを意味します。ステータスを表す2つのフラグのように。 IE iSemployeeとiScustomerは、4つの異なる名前のものを表すためにドキュメントで使用されています。したがって、4つの可能な組み合わせは、「従業員」、「顧客」、「顧客雇用者」、または「なし」などの1つの文字列にのみ変換する必要があります。
スケーラブルによって;このスキーマを事前に理解せずにXMLドキュメントを処理するために使用できることを意味し、ドキュメントサイズを制限しないことを意味します。
これはXSLTを使用して行われる可能性があることを理解しています。ドキュメントを受け入れ、追加のノードを追加または更新して同じドキュメントを作成するXSLTを記述できますか?
解決
このような入力を仮定すると:
<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>
さらに一般化されたアプローチは、(重く)修正されたアイデンティティ変換を使用します。
<!-- 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>
Dash Delimited文字列としてのノード:
<!-- 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>
他のヒント
これに基づいた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>