Question

J'ai un document XML et je souhaite modifier les valeurs de l'un des attributs.

D'abord, j'ai tout copié de l'entrée à la sortie en utilisant:

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

Et maintenant, je souhaite modifier la valeur de l'attribut "type" dans tout élément nommé "propriété" / .

Était-ce utile?

La solution

Testé sur un exemple simple, fonctionne bien:

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="@type[parent::property]">
  <xsl:attribute name="type">
    <xsl:value-of select="'your value here'"/>
  </xsl:attribute>
</xsl:template>

Modifié pour inclure la suggestion de Tomalak.

Autres conseils

Ce problème a une solution classique : Utiliser et remplacer le modèle d'identité est l'un des modèles de conception XSLT les plus fondamentaux et les plus puissants :

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

    <xsl:param name="pNewType" select="'myNewType'"/>

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

    <xsl:template match="property/@type">
        <xsl:attribute name="type">
            <xsl:value-of select="$pNewType"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Appliqué à ce document XML :

<t>
  <property>value1</property>
  <property type="old">value2</property>
</t>

le résultat souhaité est généré :

<t>
  <property>value1</property>
  <property type="myNewType">value2</property>
</t>

Les deux premières réponses ne fonctionneront pas s'il existe une définition xmlns dans l'élément racine:

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
    <property type="old"/>
</html>

Toutes les solutions ne fonctionneront pas pour le code XML ci-dessus.

La solution possible est la suivante:

<?xml version="1.0"?> 

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="node()[local-name()='property']/@*[local-name()='type']">
      <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
                some new value here
          </xsl:attribute>
  </xsl:template>

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

Vous avez besoin d'un modèle qui corresponde à votre attribut cible et rien d'autre.

<xsl:template match='XPath/@myAttr'>
  <xsl:attribute name='myAttr'>This is the value</xsl:attribute>
</xsl:template>

C’est en plus de la liste " copier tout " vous avez déjà (et est toujours toujours présent par défaut dans XSLT). Ayant une correspondance plus spécifique, il sera utilisé de préférence.

Dans un cas similaire, je voulais supprimer un attribut d'un simple nœud et je ne pouvais pas savoir quel axe me permettait de lire le nom de l'attribut. À la fin, tout ce que je devais faire était d’utiliser

@ * [name (.)! = 'AttributeNameToDelete']

Pour le XML suivant:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <property type="foo"/>
    <node id="1"/>
    <property type="bar">
        <sub-property/>
    </property>
</root>

J'ai pu le faire fonctionner avec le XSLT suivant:

<?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="//property">
        <xsl:copy>
            <xsl:attribute name="type">
                <xsl:value-of select="@type"/>
                <xsl:text>-added</xsl:text>
            </xsl:attribute>
            <xsl:copy-of select="child::*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Si votre document XML source possède son propre espace de noms, vous devez le déclarer dans votre feuille de style, lui attribuer un préfixe et utiliser ce préfixe lorsque vous vous référez aux éléments du code source, par exemple:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml">

<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />

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

<!-- exception-->    
<xsl:template match="xhtml:property/@type">
    <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

Ou, si vous préférez:

...
<!-- exception-->    
<xsl:template match="@type[parent::xhtml:property]">
  <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
  </xsl:attribute>
</xsl:template>
...

ADDENDUM: Dans le cas très improbable où l'espace de nom XML n'est pas connu à l'avance, vous pouvez effectuer les actions suivantes:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />

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

<!-- exception -->
<xsl:template match="*[local-name()='property']/@type">
    <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
    </xsl:attribute>
</xsl:template>

Bien entendu, il est très difficile d’imaginer un scénario dans lequel vous sauriez à l’avance que le document XML source contient un élément nommé "propriété" avec un attribut nommé "type". cela doit être remplacé - mais ne connais toujours pas l'espace de noms du document. J'ai ajouté ceci principalement pour montrer comment votre propre solution pourrait être rationalisée.

J'ai aussi rencontré le même problème et je l'ai résolu comme suit:

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

<!-- copy property element while only changing its type attribute -->
<xsl:template match="property">
  <xsl:copy>
    <xsl:attribute name="type">
      <xsl:value-of select="'your value here'"/>
    </xsl:attribute>
    <xsl:apply-templates select="@*[not(local-name()='type')]|node()"/>
  <xsl:copy>
</xsl:template>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top