Je suis en train de développer un éditeur XML spécifique qui utilise les fichier XML Schema. Ce dernier me permet de remplir des menus déroulants en fonction de l'élément XML courant sélectionné dans mon éditeur.

Mais voilà, les requêtes XPath sont un peu lentes sous Visual Basic. Aussi j'ai décidé d'utiliser XSLT pour générer un fichier simplifié. Voilà, le contexte de mon problème.

Et maintenant le problème à proprement dit. Le "namespace" du fichier XML-Schema peut varier (xs:,xsd:,etc...). Comment paramétrer ma tranformation XSLT pour être la plus générique possible actuellement.

Je fais chose suivante, ça marche, mais ce n'est pas beau! Je teste le contenu du nom de la balise. C'est un peu lourd mais je n'ai que "template". Sinon j'utilise les "xsl:key" pour ne pas rendre mon code trop illisble.

<xsl:template match="*[contains(name(),'element')]">
     ......
</xsl:template>


Avez-vous une solution un peu plus distinguée qui utiliserait tout la subtilité de ce langage.

krisgraf
Il manque des éléments pour préciser ton problème, mais peut-être entretiens-tu une confusion entre préfixe et espace de noms ?

xs:, xsd:, ... sont des préfixes.
Les espaces de noms sont des URI, mais tu n'as pas évoqué celle(s) que tu utilises dans ton développement.
Les préfixes sont utilisés pour repérer localement les espaces de noms en utilisant une syntaxe simplificatrice. Pour ce faire il faut créer un mapping entre préfixes et espaces de noms. Ce mapping n'est pas nécessairement bijectif.

Logiquement il faut définir un ou des préfixe(s) pour le ou les espaces de noms dans le XSLT puis utiliser ce ou ces préfixe(s) :
<xsl:template match="monprefixe:element">
     ......
</xsl:template>

Ceci est également correcte :
<xsl:template match="monprefixe:element | monprefixe2:element2">
     ......
</xsl:template>


Si les espaces de noms utilisés sont totalement imprévisibles vus du XSLT, alors il n'y a pas d'autre type de solution que celui que tu proposes. Tu peux simplement remplacer le tandem contain et name par local-name pour être légèrement plus propre.
Cependant, je dirais que transformer un document dont on ne sait rien devrait amener à se poser des questions...
Je pense que tu as assez bien compris mon problème même si je n'ai présenté tout le contexte de mon projet de développement.

En fait voilà, ce que je réalise. Je veux pouvoir créer de façon rapide et intuitive un nouveau document XML à partir de sa description XML-Schema. Donc je charge le fichier XSD (XML-Schema) à l'aide d'un objet DOMDocument et ensuite je passe des requêtes XPath via les méthodes "selectNodes" et "selectSingleNode" pour récupérer sous VB la description des données. Mais voilà avec la complexité du XML-Schema (element, elementType, complexType, etc.), je m'en sortais plus.

Donc j'ai fait un petit script XSLT pour extraire une liste exhausive des elementx XML "element". J'ai testé cela sur diffférents fichier XSD que j'avais sous la main et effectivement, certains utilisait le préfixe "xsd:" ou "xs:". Et donc ma transformation ne fonctionnait pas, MSXML me réclame une définition préalable de ce préfixe.

Je pense donc qu'avec la fonction local-name je vais pouvoir m'en sortir.
Et si mon programme d'éditeur XML intéresse certains, je suis prêt à diffuser les mises à jour successives.

Merci
Je suppose donc que tu utilises des espaces de noms classiques. Si ton fichier XML Schéma est correcte il définit probablement ces espaces de noms :
- http://www.w3.org/2001/XMLSchema
et
- http://www.w3.org/2001/XMLSchema-datatypes
auxquels sont respectivement associées les préfixes xs et xsd.

Dans ce cas l'utilisation de local-name n'est pas idéale. Il vaut mieux :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema-datatypes" exclude-result-prefixes="xs xsd">
    .....
   <xsl:template match="xs:element | xsd:element">
          ......
   </xsl:template>
    .....
</xsl:stylesheet> 

2 commentaires pour terminer :
- je ne sais pas si exclude-result-prefixes est utile dans ton cas car j'ignore comment tu utilises le résultat de la transformation.
- les préfixes choisis dans la transformation XSLT sont parfaitement arbitraires, tu peux mettre n'importe quoi. Ce qui compte c'est l'utilisation correcte des espaces de noms en concordance avec le fichier XML source.
Voilà le traitement que je fais dans XSLT:


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

	<xsl:key match="*" name="nameSearch" use="@name"/>
	<xsl:key match="*[local-name()='element']" name="elementSearch" use="@name"/>

	<xsl:template match="*[local-name()='schema']">
		<xsl:element name="schema">
			<xsl:attribute name="root"><xsl:value-of select="*[local-name()='element']/@name"/></xsl:attribute>
			<xsl:apply-templates select="//*[local-name()='element'][generate-id()=generate-id(key('elementSearch',@name)[1])]">
				<xsl:sort select="@name"/>
			</xsl:apply-templates>
		</xsl:element>
	</xsl:template>

	<xsl:template match="*[local-name()='element']">
		<xsl:element name="element">
			<xsl:apply-templates select="@*"/>
			<xsl:apply-templates select="key('nameSearch',@type)"/>
		</xsl:element>
	</xsl:template>

	<xsl:template match=" @*"><xsl:copy/></xsl:template>

	<xsl:template match="*[local-name()='group']">
		<xsl:for-each select="descendant::*">
			<xsl:choose>
				<xsl:when test="*[local-name()='group']">
					<xsl:apply-templates select="key('nameSearch',@ref)"/>
				</xsl:when>
				<xsl:when test="*[local-name()='element']">
					<xsl:element name="element">
						<xsl:apply-templates select="@*"/>
					</xsl:element>
				</xsl:when>
			</xsl:choose>
		</xsl:for-each>
	</xsl:template>

	<xsl:template match="*[local-name()='complexType']">
		<xsl:if test="@mixed='true'"><xsl:attribute name="mixed">true</xsl:attribute></xsl:if>
		<xsl:choose>
			<xsl:when test="*[local-name()='sequence']">
				<xsl:element name="sequence">
				<xsl:for-each select="descendant::*[local-name()='element']">
					<xsl:element name="element">
						<xsl:apply-templates select="@*"/>
					</xsl:element>
				</xsl:for-each>
				</xsl:element>
			</xsl:when>
			<xsl:when test="*[local-name()='group']">
				<xsl:element name="sequence">
					<xsl:apply-templates select="key('nameSearch',*/@ref)"/>
				</xsl:element>
			</xsl:when>
		</xsl:choose>
	</xsl:template>

</xsl:stylesheet>


Cela me permet de mettre à plat la définition de l'arborescence des éléments pour savoir très vite pour chaque élément, quels sont ses fils.

Voilà par exemple le traitement que j'en fais dans Visual Basic:

Je charge le fichier XSLT et puis je fait la transformation suivante:

Call schemaXML.transformNodeToObject(XSLTransform, elementXML)


Ensuite j'utilise l'objet elementXML comme suit:
- Pour récupérer l'élément racine:

qName = "/schema"
Racine = elementXML.selectSingleNode(qName).Attributes.getNamedItem("root").nodeTypedValue

- Pour récupérer les éléments fils pour remplir un ComBox:

qName = "/schema/element[@name='" + strElement + "']/sequence/element"
Set Liste = elementXML.selectNodes(qName)
For Each Element In List
    MyComboBox.AddItem Element.getAttribute("name")
Next Element
En regardant rapidement tes éléments, je ne vois pas d'obstacle à utiliser la syntaxe que je t'ai donnée dans le précédent message.
Tu peux laisser le exclude-result-prefixes.

Encore une fois pour que tout fonctionne correctement il faut que ton fichier source déclare correctement les espaces de noms utilisés.