2010-02-16 8 views
2

J'ai créé une feuille de style censée copier de manière sélective le contenu d'un document XML afin de pouvoir supprimer les données dont nous n'avons pas besoin. J'ai fourni 2 exemples ci-dessous et la feuille de style que nous utilisons actuellement pour le faire. La feuille de style fonctionne, mais je pense qu'il y a probablement une meilleure façon de le faire parce que dans la version actuelle, je vérifie la même chose dans deux endroits différents (author = 'John Doe').XSLT plus performant - Inclusion sélective dans la sortie

Les règles pour inclure un élément XML dans la sortie est la suivante:

  • S'il y a un élément de bloc-notes dans les blocs-notes qui contient le texte de l'auteur égal à « John Doe » comprennent alors l'élément de blocs-notes dans la
  • Si l'élément notepad a un élément author avec un texte égal à 'John Doe', incluez tous les éléments dans l'élément notepad dans la sortie xml.

Entrée Exemple # 1

<transaction> 
<policy> 
    <insco>CC</insco> 
    <notepads> 
     <notepad> 
     <author>Andy</author> 
     <notepad> 
     <notepad> 
     <author>John Doe</author> 
     <notepad> 
     <notepad> 
     <author>Barney</author> 
     <notepad> 
    </notepads> 
    </policy> 
</transaction> 

Résultat escompté pour l'entrée # 1

<transaction> 
    <policy> 
    <insco>CC</insco> 
    <notepads> 
     <notepad> 
     <author>John Doe</author> 
     <notepad> 
    </notepads> 
    </policy> 
</transaction> 

Entrée Exemple # 2

<transaction> 
    <policy> 
    <insco>CC</insco> 
    <notepads> 
     <notepad> 
     <author>Andy</author> 
     <notepad> 
    </notepads> 
    </policy> 
</transaction> 

Résultat prévu pour l'entrée # 2

<transaction> 
    <policy> 
    <insco>CC</insco> 
    </policy> 
</transaction> 

La version actuelle de Stylesheet

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn"> 
    <xsl:template match="*"> 
     <xsl:choose> 
     <xsl:when test="name()='notepads'"> 
      <xsl:if test="/transaction/policy/insco='CC' and (notepad/author='John Doe')"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy>    
      </xsl:if> 
     </xsl:when> 
     <xsl:when test="name()='notepad'"> 
      <xsl:if test="author='John Doe'"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy>    
      </xsl:if>     
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:copy> 
      <xsl:apply-templates /> 
      </xsl:copy> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

Répondre

2

Je peux penser à deux façons de le faire.

1) modèle d'identité, nom de l'auteur codé en dur:

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

    <!-- nodepads generally get removed... -->  
    <xsl:template match="notepad" /> 

    <!-- ...unless their author is 'Jon Doe' -->  
    <xsl:template match="notepad[author='John Doe']"> 
    <xsl:copy-of select="." /> 
    </xsl:template> 

</xsl:stylesheet> 

2) modèle d'identité modifiée, clé XSL, paramétrés nom de l'auteur:

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:param name="theAuthor" select="'John Doe'" /> 

    <xsl:key 
    name="kNotepad" match="notepad[author]" 
    use="concat(generate-id(..), '|', author)" 
    /> 

    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select=" 
     node()[not(self::notepad)] 
     |key('kNotepad', concat(generate-id(), '|', $theAuthor)) 
     |@*" 
     /> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

La deuxième approche nécessite une petite explication:

  • les indexent tous les noeuds <nodepad> qui ont un <author> par leur identifiant unique de parent et le nom de l'auteur
  • disons que l'ID unique de <notepads> est 'id0815', puis sur la touche aux <notepad> s qui vous intéressent serait 'id0815|Jon Doe'
  • les copies de modèle d'identité chaque noeud qui est passé à travers il.Il est modifié d'une manière qu'il ne pas passe chaque nœud qu'il trouve par lui-même, mais seulement:
    • un nœud qui n'est pas <notepad>: node()[not(self::notepad)]
    • tout attribut: @*
    • un nœud cela est retourné par la clé.
  • l'appel à key() revient naturellement jamais que quoi que ce soit sur <notepads> éléments (parce qu'il contient leur ID unique)
  • donc lorsque le modèle est en train de traiter un élément <notepads> ('id0815' dans notre cas), key() retournera ses 'Jon Doe' enfants seulement, dans tous les autres cas, il se retrouvera vide
  • contrairement à la solution 1) celui-ci peut être alimenté avec un paramètre, en changeant son comportement sans changer son code
  • il est à noter que tout reste dans l'ordre de document d'entrée
+0

Merci pour votre réponse. Je ne sais pas si la complexité ajoutée en vaut la peine (le nom ne devrait pas changer ou si cela change tous les deux ans), mais je peux certainement voir l'utilité de la technique que vous avez affichée ici. – jwmajors81

+0

La complexité des deux approches est à peu près comparable - bien sûr en fonction de votre connaissance de XSLT. En tout cas, vous décidez. ;) – Tomalak

+0

Il me semble que vous avez "perdu" le contrôle '/ transaction/policy/insco = 'CC'' ... – Lucero

2

Utilisez templates, ils sont généralement plus efficaces, et éviter name() contrôles, ils sont lents et peu fiables (préfixes et namespaces ne fonctionnent pas bien avec ceux):

<?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="*"> 
     <xsl:copy> 
      <xsl:apply-templates /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="notepads"> 
     <xsl:if test="(ancestor::policy/insco='CC') and (notepad/author='John Doe')"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="notepad"> 
     <xsl:if test="author='John Doe'"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Merci pour la suggestion. Cela semble beaucoup plus propre que la version actuelle. – jwmajors81