2009-07-23 7 views
1

Nous avons des documents xml qui contiennent beaucoup de nœuds marqués comme isProduct, isActive, isMandatory où le texte du nœud peut être vrai ou faux.Générique Xml Manipulation de documents

Il est nécessaire de manipuler les documents et garder leur structure, mais convertir les nœuds ci-dessus en une représentation verbale comme ci-dessous:

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

Et la même chose pour les autres nœuds de drapeau.

Nous recherchons une solution extensible et évolutive pouvant être configurée avec un minimum de friction après le déploiement.

Par extensible; nous voulons dire qu'il y aura plus de cas; comme 2 drapeaux qui représentent un statut; c'est-à-dire isEmployee et isCustomer est utilisé dans le document pour représenter 4 choses nommées différentes .; par conséquent, les 4 combinaisons possibles ne doivent être traduites qu'en une chaîne comme "Employé", "Client", "Client-Employé" ou "Aucun".

Par scalable; nous voulons dire qu'il peut être utilisé pour traiter n'importe quel document XML sans une compréhension préalable de son schéma et aucune restriction sur la taille du document.

Nous comprenons que cela peut être fait en utilisant XSLT, pouvons-nous écrire un XSLT qui accepter un document et produire le même document avec des nœuds supplémentaires ajoutés ou mettre à jour?

+0

Alors ce qui doit être fait si un nœud a ' vrai' ainsi que ' True '? –

Répondre

2

En supposant une entrée comme ceci:

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

L'approche générique serait:

<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> 

Qui produit:

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

Une approche encore plus généralisée utilise une identité modifiée (fortement) transform:

<!-- 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> 

Les prises ci-dessus toute entrée XML que ce soit et fournit la même structure, seuls les éléments nommés <is*> sont regroupés en une seule <Type> noeud comme une chaîne délimitée par le tableau de bord:

<!-- 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> 
+0

Le modèle de copie supprimera également tous les attributs des documents XML. – mkoeller

+0

Oui, je sais. Je voulais faire un point sur la façon de sélectionner et gérer les nœuds "intéressants" dans mon premier exemple. J'ai ajouté une solution généralisée comme deuxième moyen de faire plus de ce que le PO a décrit. – Tomalak

1

est ici une solution XSLT basée sur la transformation de l'identité :

<?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> 
+0

Alors, comment cela va-t-il gérer le noeud isEmployee? –

+0

Ajoutez un modèle similaire correspondant à "isEmployee" ou rendez le générique donné comme dans la réponse de Tomalak. – mkoeller