La manipulation des caractères spéciaux dans XSLT pour obtenir le bien-formé de sortie XML
J'avais exigence de transformation ci-dessous XML d'entrée à la sortie souhaitée format XML. Avec l'aide de ce forum, j'ai eu la solution ci-dessous:
XML d'entrée
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="Employee Id" />
<item name="Employee Name" />
<item name="Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
Transformation XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:c="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:template match="/*/c:data">
<dataset>
<xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
<xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{translate($vNames[$vPos], ' ', '_')}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
De Sortie désiré XML
<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<Employee_Id>1</Employee_Id>
<Employee_Name Salutation="Dr.">John</Employee_Name>
<Department_Name>Finance</Department_Name>
</row>
<row>
<Employee_Id>2</Employee_Id>
<Employee_Name Salutation="Mr.">Peter</Employee_Name>
<Department_Name>Admin</Department_Name>
</row>
Cependant, je suis tombé sur un scénario particulier qui rompt cette solution. Les valeurs d'attribut XML d'Entrée peut commencer avec Nombre, Caractère Spécial ou de l'Espace.
Nouvelle Entrée XML
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="1Employee Id" />
<item name=" Employee Name" />
<item name="$Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
Depuis nom les valeurs d'attribut sont convertis en noms d'éléments, de transformation ci-dessus échoue comme les noms d'Élément ne peut pas démarrer avec le Numéro ou l'Espace.
Dans ce cas, je voudrais remplacer ces caractères avec certains caractères valides pour les noms de dire _
ou C_
pour obtenir le même souhaité XML de Sortie.
Bien vouloir me faire savoir comment gérer ce scénario.
Toute aide serait très appréciée.
Merci d'avance.
Ce qui concerne
- Aurez-vous le Nombre, ni de Caractères Spéciaux dans les valeurs d'attribut, ou juste au début? Dans le cas de numéros, si une valeur d'attribut est terminée avec un certain nombre, voulez-vous voulez toujours figurant dans le outputed nom de l'élément?
- Si vous ne pouvez pas être sûr de votre colonne de noms XML valide les noms, alors vous seriez sûr d'opter pour un format de sortie comme
<c n="X">value</c>
plutôt que<X>value</X>
. Ce serait sans doute moins verbeux pour les longs noms de colonne que vous n'avez pas le nom répété à la fois l'ouverture et la balise de fermeture. - D'accord avec Ian.
- Merci pour la suggestion. La sortie XML doit être consommé par une autre application, qui s'attend à être dans ce format.
Vous devez vous connecter pour publier un commentaire.
Ici est une solution complète qui n'utilise pas du tout codé en dur caractères spéciaux:
Lorsque cette transformation est appliquée sur le document XML:
le voulait, résultat correct est produit:
Explication:
Nous permet d'identifier l'ensemble des caractères qui n'appartiennent pas à un ensemble donné de caractères en utilisant la double-traduire méthode, présentée pour la première fois par Michael Kay.
Si à l'intérieur de les noms il y a d'autres caractères illégaux en plus des espaces, la même double traduire technique peut être utilisée pour remplacer le (inconnu à l'avance) personnage avec une personnalité juridique.
code
<valeur>P&G<\la valeur>code
. Une solution que je peux penser à est de placer toutes les valeurs en sortie xml à l'aide CDATA mais je ne suis pas en mesure de réaliser que dans XSLT. Pouvez-vous s'il vous plaît laissez-moi savoir si mon approche de l'emballage avec CDATA est le problème? Si non, alors comment faire pour l'atteindre. Merci.C'est très facile. Juste étendre la portée de votre translate() appel pour régler le problème des caractères (caractères que vous utilisez dans l'attribut, mais que XML interdit pour les noms d'élément).
Par exemple, le changement...
...à...
Mise à jour
En réponse à l'OP de précisions, ici, est de savoir comment traduire seulement le premier caractère. Supposons que notre tentative nom de l'élément avec un premier caractère est $vName. Pour illustration, nous disons que nous sommes simplement en regardant
$
comme la seule possible dangereuses premier caractère. Ce que nous faisons est de dépouiller le premier caractère, de la traduire, puis ajouter sur le dos, comme ça......ou...
Note
Si vous êtes en mesure de passer à XSLT 2.0, alors il devient plus facile avec les regex...