[커리어리 디스코드 봇] RSS XML에서 유효하지 않은 문자 제거 - Invalid bytes in character encoding
안녕하세요.
최근 디스코드 봇 용으로 커리어리 RSS 피드를 조회해 디스코드 웹훅으로 보내주는 스크립트를 만들었습니다.
트러블 슈팅 5번으로 RSS 피드를 불러올 때 XML에 아래처럼 오류가 나는데요.
Invalid bytes in character encoding 오류로 유효하지 않은 문자가 들어가 읽을 수 없다는 오류였습니다.
아주 가끔~ 해당 인코딩이 잘못 들어갔겠거니 싶어서 임시로 replace 를 해줬습니다.
그 이후로도 간간히 RSS 피드를 읽을 수 없어 Invalid bytes in character encoding 오류가 발생하더라고요.
보름 정도 하루에 한 번 스크립트를 돌렸는데 3~4번 정도 오류가 발생했습니다.
이 RSS 피드를 읽어 슬랙으로 보내는 공식 봇도 똑같이 오류가 발생할텐데... 어떻게 처리했는지 궁금하네요.
RSS 피드를 발행할 때 XML 규격에 허용되지 않는 문자열은 제외되면 좋을 것 같네요..!
디스코드 봇에서 XML에 유효하지 않는 문자를 지웠습니다.
XML에서 유효한 문자 기준
XML에 유효한 문자는 버전별로 상이합니다.
유니코드 기준이며, 해당 범위로 유효한지 검사합니다.
우선 커리어리는 XML 1.0 버전입니다.
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>커리어리 | 요즘 개발자 커뮤니티 </title>
XML 1.0 에서 유효한 문자 범위
- U+0009 : 수평 탭
- U+000A : 줄 바꿈
- U+000D : 캐리지 리턴
- U+0020 ~ U+D7FF : 유니코드 문자
- U+E000 ~ U+FFFD : 유니코드 문자
- U+10000 ~ U+10FFFF : 유니코드 보조 문자
XML 1.1 에서 유효한 문자 범위
- U+0001 ~ U+D7FF
- U+E000 ~ U+FFFD
- U+10000 ~ U+10FFFF
XML 1.1 에서 유효하다고 해도, 여전히 XML 1.0 에서 쓰이지 않는 범위는 권장하지 않습니다.
출처 : https://en.wikipedia.org/wiki/Valid_characters_in_XML
유효하지 않은 범위 정규식 제거
kotlin String 확장 함수로 sanitizeInvalidUnicode 를 만듭니다.
정규식은 String 의 toRegex() 메소드를 사용해 만들 수 있고, Regex 클래스로 만들 수 있습니다.
아래처럼 정규식이 길므로 코드 가독성 측면에서 Regex 클래스로 생성했습니다.
너무 길면 뒤의 toRegex() 가 눈에 안들어 올 수 있죠.
fun String.sanitizeInvalidXMLUnicode(): String {
val SANITIZE_REGEX = Regex("[^\\x09\\x0A\\x0D\\x20-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]")
return this.replace(SANITIZE_REGEX, "");
}
정규식에서 '[]' 는 문자 하나에 해당하는 조건이 여러개일 때 한 번에 묶어줍니다.
'^' 은 부정을 나타내며, 뒤 범위가 아닌 문자를 찾는 조건으로 바뀝니다.
Regex 객체를 생성하는 데 비용이 비싸 전역으로 만들까 하다
한 번만 실행되고 말 스크립트고, 접근 범위로 관리하기 편하게 해당 메소드안에서 Regex 클래스를 생성했습니다.
fun main() = runBlocking {
val rssParser = RssParser()
val rss = REQUEST_URL.httpGet().body.sanitizeInvalidXMLUnicode()
val rssChannel = rssParser.parse(rss)
...
}
위처럼 RSS 텍스트를 읽을 때 유효하지 않은 범위를 제거했습니다.
유효하지 않은 문자열을 제거한 후 테스트 결과
여전히 RSS 피드에 들어가면, Invalid bytes in character encoding, 오류가 뜨지만
아래처럼 RSS Reader 가 정상적으로 동작하는 걸 확인했습니다.
XML 1.0 스펙을 살펴봐서 유효한 범위가 어딘지 꼼꼼히 살펴봤습니다.
이정도는 RSS 라이브러리나 XML 라이브러리에서 자체적으로 해줄 법도 한데...
XML 스펙이 언제 변할지 몰라서 호환성 이슈가 생길 수 있어 안했을 거란 생각도 드네요.
다음에 다른 기능이나 이슈가 생기면 찾아뵙도록 하겠습니다!