简体   繁体   English

使用JavaScript在内存中生成XML文档

[英]Generate XML document in-memory with JavaScript

I am working on a Web application that needs to send XML to a server backend. 我正在开发一个需要将XML发送到服务器后端的Web应用程序。 I'd like to build a XML document in-memory on the client-side, but using XML manipulation routines, instead of appending countless strings together. 我想在客户端内部构建一个XML文档,但是使用XML操作例程,而不是将无数字符串附加在一起。 I'm hoping jQuery can help me out. 我希望jQuery可以帮助我。

Let's say I need to generate this (toy) XML document with JavaScript: 假设我需要用JavaScript生成这个(玩具)XML文档:

<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>

To start, I need to create some kind of an XML document object with the "report" root. 首先,我需要使用“report”根创建某种XML文档对象。 I'm assuming one of these should be close, but none of them work quite right, and/or I can't quite figure out how to use the object properly: 我假设其中一个应该很接近,但它们都没有正常工作,和/或我无法弄清楚如何正确使用该对象:

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;
}

Now I want to create and append elements. 现在我想创建和追加元素。 How do I do that? 我怎么做? I imagine it's something like this: 我想它是这样的:

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;
}

Any ideas? 有任何想法吗?

The second approach seems a good way to go. 第二种方法似乎是一个很好的方法。 It was designed to work with XML documents. 它旨在使用XML文档。 Once you have the document object created, use the standard XML DOM manipulation methods to construct the entire document. 创建文档对象后,使用标准XML DOM操作方法构造整个文档。

// 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);

This may seem a little verbose but is the right way to build the XML document. 这看起来有点冗长,但却是构建XML文档的正确方法。 jQuery does not actually construct any XML document, but just relies on the innerHTML property to parse and reconstruct a DOM given an HTML string. jQuery实际上并不构造任何XML文档,而只是依赖于innerHTML属性来解析和重构给定HTML字符串的DOM。 The problem with that approach is that when tag names in your XML collide with tag names in HTML such as <table> or <option> , then the results can be unpredictable. 这种方法的问题在于,当XML中的标记名称与HTML中的标记名称(例如<table><option>发生冲突时,结果可能是不可预测的。 (EDIT: since 1.5 there's jQuery.parseXML() which does actually construct an XML document and thus avoids these problems — for parsing only.) (编辑:自1.5有jQuery.parseXML()这实际上构建XML文档,从而避免了这些问题-只为解析。)

To cut down on the verboseness, write a small helper library, or maybe a jQuery plugin to construct the document. 要减少冗长,请编写一个小帮助程序库,或者编写一个jQuery插件来构建文档。

Here's a quick and dirty solution to creating a XML document using a recursive approach. 这是使用递归方法创建XML文档的快速而肮脏的解决方案。

// 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')
        )
    )
);

Returns: 返回:

<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>​

See example 见例子

Without addressing whether you should use jQuery to build XML, here are some ideas on how you might do it: 如果不解决是否应该使用jQuery构建XML,这里有一些关于如何实现它的想法:

// 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());

Output: 输出:

<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>

I've found Ariel Flesler's XMLWriter constructor function to be a good start for creating XML from scratch (in memory), take a look at this 我发现Ariel Flesler的XMLWriter构造函数是从头开始创建XML的好开始(在内存中),看看这个

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

Example

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() );
}

Result 结果

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

A couple of caveats, it doesn't escape strings and the syntax can get coyote++ ugly. 一些警告,它不会逃避字符串,语法可以让coyote ++丑陋。

Have you considered JSON? 你考虑过JSON吗? You could save the data using objects. 您可以使用对象保存数据。 Then you could use JSON.stringify(obj); 然后你可以使用JSON.stringify(obj); and send that to the server. 并将其发送到服务器。

a simple example 一个简单的例子

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
}

If your desired XML structure can be represented in a JavaScript object having the same structure, then you could create such an object and use the following function to convert that object to XML: 如果您所需的XML结构可以在具有相同结构的JavaScript对象中表示,那么您可以创建这样的对象并使用以下函数将该对象转换为XML:

 /* Arguments: name: name of the root XML-element val: the data to convert to XML Returns: XML string Example: toXml("root", { items: { item: [1, 2] } }) returns: "<root><items><item>1</item><item>2</item></items></root>" */ function toXml(name, val) { const map = {"<":"&lt;", ">":"&gt;", "&":"&amp;", "'":"&apos", '"':"&quot;"}; if (Array.isArray(val)) return val.map(elem => toXml(name, elem)).join``; const content = Object(val) === val ? Object.keys(val).map(key => toXml(key, val[key])).join`` : String(val).replace(/[<>&'"]/g, m => map[m]); return `<${name}>${content}</${name}>`; } // Example: const report = { submitter: { name: "John Doe" }, students: { student: [{ name: "Alice", grade: 80 }, { name: "Bob", grade: 90 }] } }; console.log( '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>' + toXml("report", report)); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM