달력

3

« 2024/3 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2010. 1. 29. 19:09

XML 특수 문자 파싱 오류 확인 그거/Java2010. 1. 29. 19:09


<?xml version=\"1.0\" encoding=\"euc-kr\"?><root><data>한&#123;글1234 &#xF;5678&#15; &#16; English日本0A</data></root>

이런 XML을 파싱을 하다 보면...

[Fatal Error] :4:13: Character reference "&#15" is an invalid XML character.
org.xml.sax.SAXParseException: Character reference "&#15" is an invalid XML character.
 at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
 at cis.jcaps.app.XMLParserTest.handle(XMLParserTest.java:75)
 at cis.jcaps.app.XMLParserTest.doIt(XMLParserTest.java:53)
 at cis.jcaps.app.XMLParserTest.main(XMLParserTest.java:177)

이런 에러가 납니다.

바로 &#15; 요놈!. 특수문자가 변환된 놈 때문이지요..

이걸 HTML 파일로 저장해서 보면..



이렇게 보입니다.. 꼭 벌레같다는..

암튼. 저 데이터를 XML로 변환을 하면.. &#15; 가 되지요.

이  &#15; 를 다시 원래 벌레로 만들려면 XML 파서가 바로 위 같은 에러를 뱉어냅니다.

이 문제를 해결하기 위해서..

final Pattern nonValidPattern = Pattern.compile("&#(x?)([0-9a-fA-F]+);");

 public String stripNonValidXMLCharacters(String str) {
  StringBuffer out = new StringBuffer();
  Matcher matcher = nonValidPattern.matcher(str);
  int value = 0;
  boolean isHex = false;
  boolean valid = false;
  while (matcher.find())
  {
   isHex = matcher.group(1) != null;
   value = Integer.parseInt(matcher.group(2), isHex ? 16 : 10);
   valid = false;
   if ((value == 0x9) ||
     (value == 0xA) ||
     (value == 0xD) ||
     ((value >= 0x20) && (value <= 0xD7FF)) ||
     ((value >= 0xE000) && (value <= 0xFFFD)) ||
     ((value >= 0x10000) && (value <= 0x10FFFF)))
    valid = true;
   if (!valid)
    matcher.appendReplacement(out, "");
  }
  matcher.appendTail(out);
  return out.toString();
 }

이 method를 사용하면 됩니다.

"&#(x?)([0-9a-fA-F]+);"

바로 이 패턴을 이용하여, &#xx; 이런식의 문자열을 지워버리는거죠.

&#로 시작하고,
&#뒤에 x가 0번 혹은 1번만 나오고.
&#뒤에 뒤에 숫자, 또는 영문자 a~f 까지만 허용되는 문자열이 1번 이상 나오고,
마지막은 ; 로 끝나는 문자열을 찾는거죠.

해당 문자열을 찾은 후에

   if ((value == 0x9) ||
     (value == 0xA) ||
     (value == 0xD) ||
     ((value >= 0x20) && (value <= 0xD7FF)) ||
     ((value >= 0xE000) && (value <= 0xFFFD)) ||
     ((value >= 0x10000) && (value <= 0x10FFFF)))
    valid = true;


이 루틴을 이용해서, XML 파싱에 허용되는 문자들만 거르게 되는겁니다!! 냐하하하.

:
Posted by 뽀기