37 votes

Générer un document XML en mémoire avec JavaScript

Je travaille sur une application Web qui doit envoyer du XML à un serveur dorsal. J'aimerais construire un document XML en mémoire du côté client, mais en utilisant des routines de manipulation XML, au lieu d'ajouter d'innombrables chaînes de caractères. J'espère que jQuery pourra m'aider.

Disons que je dois générer ce document XML (jouet) avec JavaScript :

<report>
    <submitter>
        <name>John Doe</name>
    </submitter>
    <students>
        <student>
            <name>Alice</name>
            <grade>80</grade>
        </student>
        <student>
            <name>Bob</name>
            <grade>90</grade>
        </student>
    </students>
</report>

Pour commencer, je dois créer une sorte d'objet document XML avec la racine "report". Je suppose que l'un de ces objets devrait être proche, mais aucun d'entre eux ne fonctionne correctement, et/ou je n'arrive pas à comprendre comment utiliser l'objet correctement :

function generateDocument1()
{
    var report = $('<report></report>');
    return report;
}

function generateDocument2()
{
    var report = document.implementation.createDocument(null, "report", null);

    return new XMLSerializer().serializeToString(report);   
}

function createXmlDocument(string)
{
    var doc;
    if (window.DOMParser)
    {
        parser = new DOMParser();
        doc = parser.parseFromString(string, "application/xml");
    }
    else // Internet Explorer
    {
        doc = new ActiveXObject("Microsoft.XMLDOM");
        doc.async = "false";
        doc.loadXML(string); 
    }
    return doc;
}

function generateDocument3()
{
    var report = createXmlDocument('<report></report>');

    return report;
}

Maintenant, je veux créer et ajouter des éléments. Comment dois-je m'y prendre ? J'imagine que c'est quelque chose comme ça :

function generateReportXml()
{
    // Somehow generate the XML document object with root
    var report = /*???*/;

    // Somehow create the XML nodes
    var submitter = /*???*/;
    var name = /*???*/;

    // Somehow append name to submitter, and submitter to report
    submitter.append(name); /*???*/
    report.append(submitter); /*???*/

    // ... append the rest of the XML

    return report;
}

Des idées ?

0 votes

N'oubliez pas de consulter la solution de @AlexanderN à la fin si vous voulez une excellente méthode de plugin js pour créer des structures XML, y compris les attributs et CDATA.

65voto

Anurag Points 66470

La deuxième approche semble être une bonne solution. Elle a été conçue pour fonctionner avec des documents XML. Une fois l'objet document créé, utilisez les méthodes standard de manipulation du DOM XML pour construire l'ensemble du document.

// creates a Document object with root "<report>"
var doc = document.implementation.createDocument(null, "report", null);

// create the <submitter>, <name>, and text node
var submitterElement = doc.createElement("submitter");
var nameElement = doc.createElement("name");
var name = doc.createTextNode("John Doe");

// append nodes to parents
nameElement.appendChild(name);
submitterElement.appendChild(nameElement);

// append to document
doc.documentElement.appendChild(submitterElement);

Cela peut sembler un peu verbeux, mais c'est la bonne façon de construire le document XML. jQuery ne construit pas réellement de document XML, mais se contente de s'appuyer sur la balise innerHTML pour analyser et reconstruire un DOM à partir d'une chaîne HTML. Le problème avec cette approche est que lorsque les noms de balises dans votre XML entrent en collision avec les noms de balises dans le HTML tels que <table> o <option> alors les résultats peuvent être imprévisibles. (EDIT : depuis la version 1.5 il y a jQuery.parseXML() dont fait construit réellement un document XML et évite ainsi ces problèmes - pour l'analyse syntaxique uniquement).

Pour réduire le nombre de mots, écrivez une petite bibliothèque d'aide, ou peut-être un plugin jQuery pour construire le document.

Voici une solution rapide et pratique pour créer un document XML en utilisant une approche récursive.

// use this document for creating XML
var doc = document.implementation.createDocument(null, null, null);

// function that creates the XML structure
function Σ() {
    var node = doc.createElement(arguments[0]), text, child;

    for(var i = 1; i < arguments.length; i++) {
        child = arguments[i];
        if(typeof child == 'string') {
            child = doc.createTextNode(child);
        }
        node.appendChild(child);
    }

    return node;
};

// create the XML structure recursively
Σ('report',
    Σ('submitter',
        Σ('name', 'John Doe')
    ),
    Σ('students',
        Σ('student',
            Σ('name', 'Alice'),
            Σ('grade', '80')
        ),
        Σ('student',
            Σ('name', 'Bob'),
            Σ('grade', '90')
        )
    )
);

Les retours :

<report>​
    <submitter>​
        <name>​John Doe​</name>​
    </submitter>​
    <students>​
        <student>​
            <name>​Alice​</name>​
            <grade>​80​</grade>​
        </student>​
        <student>​
            <name>​Bob​</name>​
            <grade>​90​</grade>​
        </student>​
    </students>​
</report>​

Voir exemple

4 votes

C'est peut-être ou pas rapide et sale, mais c'est certainement très joli !

8 votes

Combinez avec new XMLSerializer().serializeToString(yourXml) et il constitue un excellent moyen de construire des documents structurés à envoyer dans des messages AJAX. Superbe !

0 votes

C'est ce dont j'ai besoin, mais je n'ai pas réussi à le faire fonctionner. jsfiddle.net/vquyT/1 ne fonctionne pas non plus ? Pourriez-vous mettre à jour ce lien ou est-ce que je rate quelque chose ?

26voto

rath Points 322

Sans chercher à savoir si vous devrait utiliser jQuery pour construire le XML, voici quelques idées sur comment vous pourriez le faire :

// Simple helper function creates a new element from a name, so you don't have to add the brackets etc.
$.createElement = function(name)
{
    return $('<'+name+' />');
};

// JQ plugin appends a new element created from 'name' to each matched element.
$.fn.appendNewElement = function(name)
{
    this.each(function(i)
    {
        $(this).append('<'+name+' />');
    });
    return this;
}

/* xml root element - because html() does not include the root element and we want to 
 * include <report /> in the output. There may be a better way to do this.
 */
var $root = $('<XMLDocument />');

$root.append
(
    // one method of adding a basic structure
    $('<report />').append
    (
        $('<submitter />').append
        (
            $('<name />').text('John Doe')
        )
    )
    // example of our plugin
    .appendNewElement('students')
);

// get a reference to report
var $report = $root.find('report');

// get a reference to students
var $students = $report.find('students');
// or find students from the $root like this: $root.find('report>students');

// create 'Alice'
var $newStudent = $.createElement('student');
// add 'name' element using standard jQuery
$newStudent.append($('<name />').text('Alice'));
// add 'grade' element using our helper
$newStudent.append($.createElement('grade').text('80'));

// add 'Alice' to <students />
$students.append($newStudent);

// create 'Bob'
$newStudent = $.createElement('student');
$newStudent.append($('<name />').text('Bob'));
$newStudent.append($.createElement('grade').text('90'));

// add 'Bob' to <students />
$students.append($newStudent);

// display the markup as text
alert($root.html());

Sortie :

<report>
    <submitter>
        <name>John Doe</name>
    </submitter>
    <students>
        <student>
            <name>Alice</name>
            <grade>80</grade>
        </student>
        <student>
            <name>Bob</name>
            <grade>90</grade>
        </student>
    </students>
</report>

6 votes

Le problème de cette approche est qu'en HTML, les noms de balises ne sont pas sensibles à la casse, alors qu'en XML, ils le sont. Par conséquent, jQuery convertira toutes les balises en minuscules, ce qui n'est peut-être pas ce que vous souhaitez.

1 votes

Bon avertissement "Sans chercher à savoir si vous devrait ", cela m'a fait réfléchir et m'a aidé à

4voto

Matveev Dmitriy Points 54

Note :

$.createElement = function(name)
{
  return $('<'+name+' />');
};

jquery crée des éléments en minuscules, $("<topMenu />") y $("<topmenu />") crée des éléments égaux <topmenu />

2voto

AlexanderN Points 5805

J'ai trouvé que la fonction constructeur XMLWriter d'Ariel Flesler est un bon point de départ pour créer du XML à partir de zéro (en mémoire), jetez un oeil à ceci

http://flesler.blogspot.com/2008/03/xmlwriter-for-javascript.html

Exemple

function test(){    
   // XMLWriter will use DOMParser or Microsoft.XMLDOM
   var v = new  XMLWriter();
   v.writeStartDocument(true);
   v.writeElementString('test','Hello World');
   v.writeAttributeString('foo','bar');
   v.writeEndDocument();
   console.log( v.flush() );
}

Résultat

<?xml version="1.0" encoding="ISO-8859-1" standalone="true" ?>
<test foo="bar">Hello World</test>

Quelques mises en garde, il n'échappe pas les chaînes de caractères et la syntaxe peut devenir coyote++ moche.

0 votes

ReferenceError: XMLWriter is not defined (Chrome Version 30.0.1599.101 m)

0 votes

@Michal Stefanow avez-vous inclus la fonction XmlWriter ?

0 votes

Je n'ai pas cliqué sur le lien. Je pensais que l'exemple se suffisait à lui-même.

1voto

qw3n Points 2697

Avez-vous pensé à JSON ? Vous pourriez enregistrer les données en utilisant des objets. Vous pourriez alors utiliser JSON.stringify(obj); et l'envoyer au serveur.

un exemple simple

var obj = new student('Alice',80);

function student(a,b){
  this.name=a;
  this.grade=b;
}

function sendToServer(){
  var dataString = JSON.stringify(obj);
  //the HTTP request
}

0 votes

JSON n'est pas capable de stocker de nombreuses structures de données, alors que XML peut tout stocker.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X