我最近在弄一个 docx 文档的处理工具,docx 文档的数据储存方式其实就是 xml ,听说我雷大哥(雷军)以前也是弄 WPS 的,想想曾经的偶像之一也许也弄过类似的事情还是挺有干劲的……

好了废话说了一大堆,开始进入主题吧。

首先我直接找了轮子,毕竟 docx 文档的 xml 不是给正常人看的,现在好像比较强的是 xml2js

NPM 安装地址:https://www.npmjs.com/package/xml2js

GitHub:https://github.com/Leonidas-from-XIV/node-xml2js

这个轮子使用起来还是比较舒服的,开头我还是先简单翻译一下文档

npm 安装

npm install xml2js

简单的使用,xml2js 会将 var xml 变量中的 xml 字符串传入 xml2js 中导出的 parseString 方法中处理,parseString 方法接收两个一个是待处理的 xml 字符串,还有一个是 callback function 也就是回调函数,解析后会执行这个方法这个方法返回两个参数 err 和 result,其中 err 是解析失败后的错误对象,result 则是解析成功后返回 xml 对应的 json 对象,不过这个对象不是完美还原 xml 出来的有点小瑕疵我们放到后面说…

var parseString = require('xml2js').parseString;
var xml = "<root>Hello xml2js!</root>"
parseString(xml, function (err, result) {
    console.dir(result);
});

普通的解析就直接使用 xml2js.parseString 方法就可以了,但是遇到特殊的我们就还需要在 parseString 中传入第三个参数,配置对象

var parseString = require('xml2js').parseString;
var xml = "<root>Hello xml2js!</root>"
parseString(xml, {trim: true}, function (err, result) {
    console.dir(result);
});

看起来和上面的方法没有太大差别,但是在调用的时候多传入了一个对象里面 trim: true 的配置,别着急下面我会慢慢介绍都有那些xml2js配置参数的(毕竟这篇博客也就这点东西能骗骗访问量了…)

参数:attrkey ,默认值:$ ,描述:用于访问 xml 节点属性的前缀,也就是说 xml 的属性都放在节点下面的 $ 对象中,你可以改成你喜欢的,如果你不知道 xml 的属性是啥的话你就别管这个

参数:charkey ,默认值:_ ,描述:用于访问字符内容的前缀,也就是说 xml 的内容是字符的话都放在节点下面的 _ 对象中,你可以改成你喜欢的前缀,如果你不知道的话就别改

参数:explicitCharkey ,默认值:false

参数:trim ,默认值:false ,描述:在文本节点的开头和结尾处修剪空格

参数:normalizeTags ,默认值:false ,描述:将所有标签名称标准化为小写

参数:normalize ,默认值:false ,描述:处理掉文本节点内的空格

参数:explicitRoot ,默认值:true ,描述:是否获取结果对象中的根节点

参数:emptyTag ,默认值:'' ,描述:空节点默认值

参数:explicitArray ,默认值:true ,描述:如果为true,则始终将子节点放入数组中;否则,仅当存在多个数组时才创建一个数组。

参数:ignoreAttrs ,默认值:false ,描述:忽略所有 xml 属性,仅创建文本节点

参数:mergeAttrs ,默认值:false ,描述:合并属性和子元素作为父元素的属性,而不是从子属性对象中键入属性。如果 ignoreAttrs 为 true,则忽略此选项

参数:validator ,默认值:null ,描述:您可以根据需要指定一个以某种方式验证结果结构的可调用对象

参数:xmlns ,默认值:false ,描述:给每个元素一个通常称为“ $ ns”的字段(第一个字符与 attrkey 相同),其中包含其本地名称和名称空间URI

参数:explicitChildren ,默认值:$ ,描述:将子元素放在单独的属性中,不适用于mergeAttrs = true,如果 element 没有子级,则不会创建“子级”。在 0.2.5 版本开始支持设置

参数:childkey ,默认值:$$ ,描述:如果 explicitChildren 设置为 true,则用于访问子元素的前缀。在 0.2.5 版本开始支持设置

参数:preserveChildrenOrder ,默认值:false ,描述:修改 explicitChildren 的行为,使“children”属性的值成为有序数组。当这个值为 true 时,每个节点还将获得一个#name字段,其值将对应于XML节点名,因此您可以迭代“子”数组,仍然能够确定节点名。在这个配置中,命名(可能是无序的)属性也保留在与有序的“子”数组相同的级别。在 0.4.9 版本开始支持设置

参数:charsAsChildren ,默认值:false ,描述:确定如果打开explicitChildren,则是否应将 char 视为子级,在 0.2.5 版本开始支持设置

参数:includeWhiteChars ,默认值:false ,描述:确定是否应包含仅空白文本节点。在 0.4.17 版本开始支持设置

参数:async ,默认值:false ,描述:回调应该异步吗?如果您的代码依赖于回调的同步执行,则这可能是不兼容的更改。未来的 xml2js 版本可能会更改此默认设置,因此建议无论如何不要依赖于同步执行。在 0.2.6 版本开始支持设置

参数:strict ,默认值:true ,描述:将 sax-js 设置为严格或非严格解析模式。强烈建议将其默认设置为 true,因为解析格式不正确的 XML 的 HTML 可能会产生几乎所有结果。在 0.2.7 版本开始支持设置

参数:attrNameProcessors ,默认值:null ,描述:允许添加属性名称处理功能。在 0.4.14 版本开始支持设置。接受具有以下签名的函数数组:

function (name){
    //do something with `name`
    return name
}

参数:attrValueProcessors ,默认值:null ,描述:允许添加属性值处理功能。在 0.4.1 版本开始支持设置。接受具有以下签名的函数数组:

function (value, name){
  //do something with `name`
  return name
}

参数:tagNameProcessors ,默认值:null ,描述:允许添加标签名称处理功能。在 0.4.1 版本开始支持设置。接受具有以下签名的函数数组:

function (name){
  //do something with `name`
  return name
}

参数:valueProcessors ,默认值:null ,描述:允许添加元素值处理功能。在 0.4.6 版本开始支持设置。接受具有以下签名的函数数组:

function (value, name){
  //do something with `name`
  return name
}

好了,解析 xml 的相关配置讲完了,我们再看看它怎么把 json 给解析回 xml 的吧

在 xml2js 中有一个 Builder 函数,可以直接转换过去…

var xml2js = require('xml2js');

var obj = {root: {$: {id: "my id"}, _: "my inner text"}};

var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);

关于 Builder 的一些配置参数的话我在这就先不翻译了,其实和上面解析配置差不多,当然如过有需要的小伙伴可以去它的 github 看看,也可以给我这篇博客 https://bin.zmide.com/?p=494 留言我一定会回复的,需要我翻译的话也请小伙伴告诉我哦 (虽然我的技术也很菜)...