最近项目中遇到一个跟xml非法字符有关的bug,于是了解了一下相关内容,在前端对xml非法字符进行过滤,以便前端能做更多的事情。先了解一下几个概念。
什么是XML
xml(eXtensible Markup Language)是被设计出来传输和存储数据的语言,它的结构和html很像,而html的用途是显示数据。我们可以在一些ajax请求的form data中看到类似的内容:
<!--demo来着菜鸟教程-->
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="CHILDREN">
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
复制代码
这个就是xml,他就是以这种方式来传递数据。第一行为声明,表明xml版本和编码。xml可以使用任何名词作为它的元素名,但是越简洁越好,避免在名称中使用“-”,“.”,“:”。可以通过元素内容或属性来携带信息。
ASCII码
定义了英语字符和二进制之间的关系,用一个字节(8位)表示一个字符。一共表示128个字符,其中还包括32个不能打印的控制符号。并且只占用一个字节的后面7位,第一位为0。ASCII表对应维基百科ASCII table
unicode码
ASCII表只能表示有限的字符,而unicode则是一个更广的字符集,码点范围从U+0000一直到U+10FFFF。几乎包括了所有的字符。然后关于unicode码的存储方式有多种,比如utf-8,utf-16,utf-32等编码方式,他们规定了怎么存储和解析unicode符号。
JavaScript对unicode的表示
在javascript中可以使用unicode表示字符。在es6之前,可以使用\uxxxx
的方式来表示\u0000
~uffff
之间的符号。超过这个范围的就要使用两个双字节来表示。而es6之后,可以通过一个大括号来表示任何的unicode符号。比如 \u{23333}
console.log('\u0061')
// a
console.log('\u{61}')
// a
复制代码
并且es6还实现了正则表达式对u
修饰符的支持,含义为Unicode模式
,可以直接匹配大于\ufff
的字符。
sWords = sWords.replace(/\u{23333}/u,"")
复制代码
解决问题
了解了这些东西之后就可以对我们的xml进行非法字符的过滤了。首先我们查看一下xml1.0版本(目前针对1.0)的字符范围:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
复制代码
那么不在这个范围里面的属于xml非法字符了,而且这么巧,大于uffff
的符号都支持,然后不支持的符号我们可以通过正则去把他们过滤掉:
sXml = sXml.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\ud800-\udfff\ufffe\uffff]/g, "")
复制代码
这样我们就把xml1.0不支持的符号过滤掉了。其他版本同理。