1. 程式人生 > >過濾xml非法字元

過濾xml非法字元

xml支援的字元範圍

Character Range
Char     ::=     #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]  /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
意思是xml支援的字元範圍是任何unicode字元,排除surrogate blocks(代理塊),  FFFE和 FFFF.

其中0xD800 至 0xDBFF(高代理high surrogate) 和 0xDC00 至 0xDFFF(低代理low surrogate)被稱為surrogate blocks(代理塊)

代理塊是為了表示增補字元 增補字元是在 [#x10000-#x10FFFF] 範圍之間的字元

增補字元是擴充套件16位unicode不能表示的字元。Unicode 最初設計是作為一種固定寬度的 16 位字元編碼。16 位編碼的所有 65,536 個字元並不能完全表示全世界所有正在使用或曾經使用的字元。於是,Unicode 標準擴充套件到包含多達 1,112,064 個字元,這些擴充套件字元就是增補字元。

xml中需要過濾的字元分為兩類:

一類是不允許出現在xml中的字元,這些字元不在xml的定義範圍之內。

另一類是xml自身要使用的字元,如果內容中有這些字元則需被替換成別的字元。

第一類字元

對於第一類字元,我們可以通過W3C的XML文件來檢視都有哪些字元不被允許出現在xml文件中。
XML允許的字元範圍是“#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]”。因此我們可以把這個範圍之外的字元過濾掉。
需要過濾的字元的範圍為:
0x00-0x08
0x0b-0x0c
0x0e-0x1f


第二類字元
對於第二類字元一共有5個,如下:
字元                HTML字元        字元編碼
和(and) &        &            &
單引號  ’ '            '
雙引號  ”          "            "
大於號  >        >                  >
小於號  <        &lt;                   &#60;
我們只需要對這個五個字元,進行相應的替換就可以了


相關程式碼:
 
可以利用.NET中 Regex的 Replace 方法對字串中在這3個範圍段的字元進行替換,如:
string content = “as fas fasfadfasdfasdf<234234546456″;
content = Regex.Replace(content, “[//x00-//x08//x0b-//x0c//x0e-//x1f]“, “*”);
Response.Write(content);
 
利用PB8,對這個範圍的字元進行過濾如下:
string content = “as fas fasfadfasdfasdf<234234546456″;
int i_count_eliminate=30
char i_spechar_eliminate[]={“~001″ , “~002″ , &
“~003″ , “~004″ , “~005″ , “~006″ , “~007″ , &
“~008″ , “~011″ , “~012″ , “~014″ , “~015″ , &
“~016″ , “~017″ , “~018″ , “~019″ , “~020″ , &
“~021″ , “~022″ , “~023″ , “~024″ , “~025″ , &
“~026″ , “~027″ , “~028″ , “~029″ , “~030″ , &
“~031″ , ‘”‘    , “`”  } //需要消除的字元,將直接替換為空
for vi=1 to i_count_eliminate
vpos=1
vlen=lenw(i_spechar_eliminate[vi])
do while true
vpos = posw(content,i_spechar_eliminate[vi],vpos)
if vpos<1 then exit
content=replacew(content,vpos,vlen,”")
loop
next
 
STL中可以這樣處理:
string filter_xml_marks(string in)
{
 string out;
 for(unsigned int i=0 ; i<in.length(); i++)
 {
  if(in[i] == '&')
  {
   out += "&";
   continue;
  }
  else if(in[i] == '/'')
  {
   out += "'";
   continue;
  }
  else if(in[i] == '/"')
  {
   out += """;
   continue;
  }
  else if(in[i] == '<')
  {
   out += "<";
   continue;
  }
  else if(in[i] == '>')
  {
   out += ">";
   continue;
  }
  else if((in[i]>= 0x00 &&in[i]<=0x08)||(in[i]>=0x0b&&in[i]<=0x0c)||(in[i]>=0x0e&&in[i]<=0x1f))
   continue;

  out += in[i];  
 }

 return out;
}

XMLCheck用於檢查xml檔案中包含非法xml字元的個數。

使用方法 XMLCheck filename

import java.io.*;

public class XMLCheck {

 /**
  * @author lxn
  *
  */
 public static void main(String[] args) throws IOException{
 
  if(args.length == 0)
  {
   System.out.print("Usage: XMLCheck filename");
   return;
  }
 
 
  File xmlFile = new File(args[0]);
  if(!xmlFile.exists())
  {
   System.out.print("File not exist");
   return;
  }
 
  //輸入xml檔案
  BufferedReader  in = new BufferedReader(new FileReader(xmlFile));
  String s;
  StringBuilder xmlSb = new StringBuilder();
  //xml檔案轉換成String
  while((s = in.readLine())!=null)
   xmlSb.append(s+"/n");
  in.close();
  String xmlString = xmlSb.toString();
  // TODO Auto-generated method stub
  //無特殊字元的
  //int i = checkCharacterData("<?xml version=/"1.0/" encoding=/"gbk/"?><CC>卡號</CC>");
  //有特殊字元的
  //int i = checkCharacterData("<?xml version=/"1.0/" encoding=/"gbk/"?><CC>/u001E卡號</CC>");
 
  int errorChar = checkCharacterData(xmlString);
  System.out.println("This XML file contain "+errorChar+" errorChar.");
 }
 
 //判斷字串中是否有非法字元
 public static int checkCharacterData(String text){
  int errorChar=0;
  if(text==null){
   return errorChar;
  }
  char[] data = text.toCharArray();
  for(int i=0,len=data.length;i<len;i++){
   char c = data[i];
   int result=c;
   //先判斷是否在代理範圍(surrogate blocks)
   //增補字元編碼為兩個程式碼單元,
   //第一個單元來自於高代理(high surrogate)範圍(0xD800 至 0xDBFF),
   //第二個單元來自於低代理(low surrogate)範圍(0xDC00 至 0xDFFF)。
   if(result>=0xD800 && result<=0xDBFF){
    //解碼代理對(surrogate pair)
    int high = c;
    try{
     int low=text.charAt(i+1);
   
     if(low<0xDC00||low>0xDFFF){
      char ch=(char)low;
     }
     //unicode說明定義的演算法 計算出增補字元範圍0x10000 至 0x10FFFF
     //即若result是增補字符集,應該在0x10000到0x10FFFF之間,isXMLCharacter中有判斷
     result = (high-0xD800)*0x400+(low-0xDC00)+0x10000;
     i++;
    }
    catch(Exception e){
     e.printStackTrace();
    }
   }
   if(!isXMLCharacter(result)){
     errorChar++;
   }
  }
   return errorChar;
 }
 private static boolean isXMLCharacter(int c){
  //根據xml規範中的Character Range檢測xml不支援的字元
  if(c <= 0xD7FF){
   if(c >= 0x20)return true;
   else{
    if (c == '/n') return true;
    if (c == '/r') return true;
    if (c == '/t') return true;
    return false;
   }
  }
  if (c < 0xE000) return false;  if (c <= 0xFFFD) return true;
  if (c < 0x10000) return false;  if (c <= 0x10FFFF) return true;
    return false;
 }

}