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

IT技术 javascript jquery xml
2021-02-25 01:48:01

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

假设我需要用 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>

首先,我需要使用“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个回答

第二种方法似乎是一个不错的方法。它旨在处理 XML 文档。一旦创建了文档对象,就可以使用标准的 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);

这可能看起来有点冗长,但却是构建 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>​

查看示例

结合new XMLSerializer().serializeToString(yourXml)和 它形成了构建结构化文档以在 AJAX 消息中发送的好方法。高超!
2021-04-20 01:48:01
@Anurag 是 Σ 对象是字符串还是数组?我的意思是我想从那个对象创建一个完整的字符串,我该怎么做?
2021-04-26 01:48:01
这可能会也可能不会很快+脏,但它绝对非常漂亮!
2021-04-28 01:48:01
这就是我需要的,但不知何故我无法使它工作,这个jsfiddle.net/vquyT/1也不起作用?你能更新这个链接还是我遗漏了什么?
2021-04-28 01:48:01
@SpaceDust - 我能够在 Safari 6 上运行 jsfiddle。你在什么浏览器上尝试这个,你看到任何错误或异常吗?
2021-05-06 01:48:01

没有解决是否应该使用 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>
很好的警告“没有解决你是否应该......”,它让我思考并帮助
2021-05-08 01:48:01
这种方法的一个问题是,在 HTML 中标记名称不区分大小写,而在 XML 中它们区分大小写。因此 jQuery 会将所有标签转换为小写,这可能不是您想要的。
2021-05-12 01:48:01

我发现 Ariel Flesler 的 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++ 变得丑陋。

我没有点击链接。我认为这个例子是独立的。
2021-04-27 01:48:01
ReferenceError: XMLWriter is not defined (Chrome 版本 30.0.1599.101 m)
2021-05-05 01:48:01
console.log( v.flush() ); 对我很有用。谢谢
2021-05-07 01:48:01
是的,点击链接!如果您需要将 XML 字符串发送到 C#/VB.NET 方法,或加载到数据库中以重新创建保存的布局,则非常有用。
2021-05-08 01:48:01
@Michal Stefanow 您是否包含 XmlWriter 函数?
2021-05-10 01:48:01

你考虑过 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
}
JSON 不能存储大量的数据结构,而 XML 可以存储任何东西。
2021-04-27 01:48:01

如果您想要的 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));