Generate XML document in-memory with JavaScript

前端 未结 5 547
谎友^
谎友^ 2020-11-27 13:15

I am working on a Web application that needs to send XML to a server backend. I\'d like to build a XML document in-memory on the client-side, but using XML manipulation rout

相关标签:
5条回答
  • 2020-11-27 13:29

    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

    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.

    0 讨论(0)
  • 2020-11-27 13:31

    Without addressing whether you should use jQuery to build XML, here are some ideas on how you might do it:

    // 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>
    
    0 讨论(0)
  • 2020-11-27 13:35

    Have you considered JSON? You could save the data using objects. Then you could use 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
    }
    
    0 讨论(0)
  • 2020-11-27 13:38

    The second approach seems a good way to go. It was designed to work with XML documents. Once you have the document object created, use the standard XML DOM manipulation methods to construct the entire 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);
    

    This may seem a little verbose but is the right way to build the XML document. 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. 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. (EDIT: since 1.5 there's jQuery.parseXML() which does actually construct an XML document and thus avoids these problems — for parsing only.)

    To cut down on the verboseness, write a small helper library, or maybe a jQuery plugin to construct the document.

    Here's a quick and dirty solution to creating a XML document using a recursive approach.

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

    0 讨论(0)
  • 2020-11-27 13:40

    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:

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

    0 讨论(0)
提交回复
热议问题