代码之家  ›  专栏  ›  技术社区  ›  Shaggy Frog

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

  •  36
  • Shaggy Frog  · 技术社区  · 15 年前

    我正在开发一个需要将XML发送到服务器后端的Web应用程序。我想在客户机端的内存中构建一个XML文档,但是使用XML操作例程,而不是将无数的字符串附加在一起。我希望jquery能帮助我。

    假设我需要用javascript生成这个(toy)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>
    

    首先,我需要用“report”根创建某种XML文档对象。我假设其中一个应该很接近,但没有一个工作得很好,和/或我不太清楚如何正确地使用对象:

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

    现在我想创建和附加元素。我该怎么做?我想是这样的:

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

    有什么想法吗?

    5 回复  |  直到 6 年前
        1
  •  26
  •   rath Cheeso    15 年前

    不说你是否 应该 使用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());
    

    输出:

    <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>
    
        2
  •  62
  •   robert4 DividedByZero    10 年前

    第二种方法似乎是一种很好的方法。它是为使用XML文档而设计的。 一旦创建了文档对象,就可以使用标准的XMLDOM操作方法来构造整个文档。

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

    这看起来有点冗长,但这是构建XML文档的正确方法。jquery实际上并不构造任何XML文档,而是依赖于 innerHTML 属性来解析和重建给定HTML字符串的DOM。这种方法的问题在于,当XML中的标记名与HTML中的标记名(如 <table> <option> ,则结果可能是不可预测的。 (编辑:从1.5开始 jQuery.parseXML() 哪一个 实际上构造一个XML文档,从而避免了这些问题,仅用于解析。)

    为了减少冗长的内容,可以编写一个小助手库,或者编写一个jquery插件来构造文档。

    下面是一个使用递归方法创建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')
            )
        )
    );
    

    返回:

    <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

        3
  •  2
  •   Alex Nolasco    14 年前

    我发现ArielFlesler的xmlWriter构造函数函数是从零开始(在内存中)创建XML的一个很好的开始,看看这个

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

    例子

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

    结果

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

    需要注意的是,它不会转义字符串,而且语法会让coyote++难看。

        4
  •  1
  •   qw3n    15 年前

    你考虑过JSON吗?您可以使用对象保存数据。然后你可以用 JSON.stringify(obj); 然后发送到服务器。

    一个简单的例子

    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
    }
    
        5
  •  0
  •   trincot Jakube    6 年前

    如果所需的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));