Question

Je veux traduire un fichier XML avec des données comme suit:

<FlatData>
    <Details1_Collection>
        <Details1 Customer1="Customer" Total1="3" />
        ...
    </Details1_Collection>
</FlatData>

Les données que je suis intéressé sont les attributs et leurs valeurs dans chaque Details1. Le problème est que ces attributs ne vont pas nécessairement être le même dans chaque fichier XML que je veux traduire, et je veux un objectif général qui pourrait gérer XSL telle Details1 comme ceux-ci:

<Details1 Customer1="Customer" Total1="3" />
<Details1 Name="Jim" Age="14" Weight="180" />
<Details1 Date="2009-07-27" Range="1-5" Option1="True" />

Ces différentes Details1 ne se produirait pas dans le même fichier XML source, mais plutôt dans des fichiers différents. Cependant, je voudrais utiliser la même XSL sur chacun.

Je pensais que je besoin de quelque chose comme <xsl:value-of select="@attribute_name"/> mais qu'est-ce que je mets pour @attribute_name quand je ne sais pas à l'avance quels sont les attributs, il y aura? En outre, comment puis-je capturer le nom d'attribut? Je voudrais faire exploser le XML source ci-dessus à quelque chose comme:

<Details1>
    <Customer1>Customer</Customer1>
    <Total1>3</Total1>
</Details1>

Modifier Merci pour les réponses! Je vais avoir du mal à obtenir plus que la sortie suivante, cependant:

<?xml version="1.0" encoding="UTF-8"?>
<FlatData>
<Details1_Collection></Details1_Collection>
</FlatData>

J'ai essayé les deux années Lavinio et les réponses de Jörn Horstmann, ainsi que d'essayer de combiner les deux. Je lance cette commande:

msxsl.exe -o output.xml input.xml transform.xsl

Je pense que quelque chose qui de prendre le chemin est un espace de noms dans le fichier d'entrée :

<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport">
Était-ce utile?

La solution

Il a augmenté la difficulté en raison de l'espace de noms Microsoft SQL Reporting Services 2008, qui faisait partie du XML d'entrée. Je ne savais pas au début que <Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> était une telle ligne importante. Merci à Pavel Minaev pour l'espace de noms commentaire . Le suivant a travaillé pour XSL extraire les données que je voulais:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="EXQC005">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="/">
    <xsl:for-each select="a:Report/a:FlatData/a:Details1_Collection/a:Details1">
      <xsl:element name="{name(.)}">
        <xsl:for-each select="@*">
          <xsl:element name="{name(.)}">
            <xsl:value-of select="."/>
          </xsl:element>
        </xsl:for-each>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Je pense que je vais essayer de nettoyer ce pour utiliser le style apply-templates que Jörn Horstmann pour le code select="@*" dans les boucles de for-each . Il serait intéressant de savoir pourquoi les rapports Reporting Services sont d'abord l'objet de dumping avec la valeur xmlns définie sur le nom du rapport, et non un URL de schéma .

Je vais continuer à mettre à jour cette réponse que je Détailler cette XSL.

Modifier Voici une version d'espace de nom agnostique puisque, pour chaque rapport différent de Reporting Services, il y aura apparemment un espace de noms différent:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="/">
    <xsl:for-each select="*[local-name()='Report']/*[local-name()='FlatData']/*[local-name()='Details1_Collection']/*[local-name()='Details1']">
      <Details>
        <xsl:for-each select="@*">
          <xsl:element name="{name(.)}">
            <xsl:value-of select="."/>
          </xsl:element>
        </xsl:for-each>
      </Details>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Autres conseils

Vous pouvez utiliser "@*" pour désigner tous les attributs, comme ces exemples:

  • <xsl:value-of select="@*"/>
  • <xsl:apply-templates select="@*"/>
  • <xsl:template match="@*">

La construction de <xsl:element name=""> peut être utilisé pour créer un nouvel élément avec un nom arbitraire, et les fonctions name() ou local-name() retourne le nom d'un attribut spécifique.

Pour faire ce que vous voulez, essayez quelque chose le long de ces lignes:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <FlatData>
            <Details1_Collection>
                <xsl:apply-templates select="FlatData/Details1_Collection/Details1"/>
            </Details1_Collection>
        </FlatData>
    </xsl:template>
    <xsl:template match="Details1">
        <Details1>
            <xsl:apply-templates select="@*"/>
        </Details1>
    </xsl:template>
    <xsl:template match="@*">
        <xsl:element name="{name()}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Pour résoudre le problème d'espace de noms (pour les deux réponses), ajoutez une déclaration d'espace de noms avec un préfixe à votre XLST:

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

et ensuite l'utiliser dans toutes vos expressions XPath pour qualifier les éléments, par exemple:

<xsl:template match="//r:Details1">

Est-ce que cette transformation donne le résultat que vous voulez?

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

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

    <xsl:template match="//Details1">
        <Details1>
            <xsl:for-each select="@*">
                <xsl:element name="{name(.)}"><xsl:value-of select="." /></xsl:element>
            </xsl:for-each>
        </Details1>
    </xsl:template>

</xsl:stylesheet>

autre façon d'écrire la réponse de Jörn Horstmann (si vous avez besoin de le faire avec Details1, Details2, et ainsi de suite ...) serait:

<xsl:template match="//Details1 | //Details2 | //whatever">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="@*">
  <xsl:element name="{name(.)}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

Probablement la façon de le faire plus simple, il:

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

  <xsl:template match="/">
    <FlatData>
      <xsl:copy-of select="//Details1" />
    </FlatData>
  </xsl:template>
</xsl:stylesheet>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top