1
votes

Exclure des éléments spécifiques de XML à l'aide de XPath ou XSLT

Considérez le XML suivant:

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

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

  <!-- For each element, create a new element with the same local-name (no namespace) -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:copy-of select="@*"/> 
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="*[not(self::company)]"/>
  </xsl:template>

</xsl:stylesheet>

Le but est d'exclure l'élément "contents" et d'obtenir le XML tel quel.

J'ai essayé des axes et d'autres opérateurs . Cependant, il ne semble pas possible d'y parvenir en utilisant XPath. Veuillez me corriger si je me trompe.

Si la solultion XPath n'est pas possible, le XSLT suivant peut-il fonctionner?

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>

<book category="cooking">
  <title lang="en">Everyday Italian</title>
  <author>Giada De Laurentiis</author>
  <price>30.00</price>
  <contents>jjjadLKjlkdasndlakjd...</contents>
</book>

<book category="children">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <price>29.99</price>
</book>

<book category="web" cover="paperback">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <price>39.95</price>
  <contents>jjjadLKjlkdasndlakjd...</contents>
</book>

</bookstore>


1 commentaires

XPath ne peut sélectionner que des éléments du document source, il ne peut en aucun cas les modifier (par exemple en supprimant certains enfants)


3 Réponses :


-3
votes

Utilisation de Xml Linq:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            List<XElement> contents = doc.Descendants("contents").ToList();
            for (int i = contents.Count - 1; i >= 0; i--)
            {
                contents[i].Remove();
            }
        }
    }
}


0 commentaires

2
votes

Remplacez simplement le deuxième modèle de votre XSLT par un modèle vide:

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

Aussi, si vous souhaitez conserver l'espace de noms (pour conserver le reste de votre XML "TEL QUEL") , vous pouvez simplement utiliser le modèle d'identité:

<xsl:template match="contents" />


2 commentaires

Merci, je vais essayer ceci. Juste une pensée, l'élément "contenu" ici est un document PDF de 3 à 4 Mo au format de chaîne de base 64. On peut utiliser regex pour sélectionner la partie désirée du XML ou remplacer la balise "contents" par une chaîne vide. Quelle approche est la meilleure à votre avis? XSLT ou regex?


L'utilisation de RegEx pour filtrer les fichiers XML est considérée comme une mauvaise pratique, donc XSLT est la langue de choix. Si vous devez filtrer le contenu base64 de l'élément avec RegEx, vous devrez utiliser XSLT-2.0 ou supérieur (recherchez la fonction fn: replace ) , mais XSLT-2.0 ne fait pas partie du framework .Net et vous auriez donc besoin d'un processeur XSLT-2.0 ou XSLT-3.0 externe dans ce cas.



0
votes

Si vous souhaitez exclure l'élément contents , vous devez utiliser:

<xsl:template match="book">
  <xsl:element name="{local-name()}">
    <xsl:apply-templates select="@* | *[not(self::contents)]"/>
  </xsl:element>
</xsl:template>

au lieu de votre:

<xsl:template match="book">
  <xsl:copy>
    <xsl:apply-templates select="@* | *[not(self::contents)]"/>
  </xsl:copy>
</xsl:template>


1 commentaires

merci, "entreprise" était une faute de frappe. cela aurait dû être "contenu".