외부 DTD 파일에 <?xml version ... ?> 같은 XML 파일임을 나타내는 PI가 들어있으면 xmerl_scan:(file|string)에서는 다음과 같은 에러를 내면서 parsing이 안된다 (java 쪽에서는 별 문제가 없었던 DTD 파일이다).
error msg:
1066- fatal: {invalid_target_name," version=\""} ** exception exit: {fatal,{{invalid_target_name," version=\""}, {file,"/path/to/dtd.dtd"}, {line,6}, {col,18}}} in function xmerl_scan:fatal/2 in call from xmerl_scan:scan_ext_subset/2 in call from xmerl_scan:scan_decl_sep/2 in call from xmerl_scan:scan_ext_subset/2 in call from xmerl_scan:scan_decl/2 in call from xmerl_scan:fetch_and_parse/3 in call from xmerl_scan:fetch_DTD/2 in call from xmerl_scan:scan_doctype2/3
간편 해결책: DTD 들이 있는 디렉토리에서 다음을 실행해주자 (DTD 파일이 여러개일때...)
$ sed -i -r "/<\?xml .*\?>/s/.*//" *.dtd # remove xml PI stuff. $ sed -i '/./,/^$/!d' *.dtd # remove leading blank line(s).
문제를 푸는 것자체는 그다지 어렵지 않았으나, 멋있게 풀어보려고, 오늘 출근길 지하철에서 타블렛에 좀 끄적였다. W by H 행렬이라 보고, top left에서, 시계방향, 반시계방향 Spiral Array를 출력해주는 것을 만들었다. (물론 요즘은 erlang에 심취해있으므로, 구현언어는 당연히 erlang이다.)
요지는 조건 검사 같은 것을 하는 것이아니라, 수열을 사용한다. 즉, 동일한 상태 이동의 반복 회수가 수열이다. 연속된 transition의 개수를 구하는 함수를 f(x)라 하면,
f(x) = f(x - 2) - 1
x가 2보다 크면 무조건 성립이고, x = 1, 2 일때의 값은 clockwise, counterclockwise에 따라 W 또는 H로 조금 달라지기는 하지만 중요한 요점은 수열을 이용해 계산으로 구한다는것이다. 자세한 건 코드 참조!
2008-08-18 : 거의 동일한 방법으로 푼 사람이 이미 있었다. 맨앞에 몇개와 끝부분의 erlang 버전만 확인하고서 획기적인 방법이라고 좋아라하고 있었다니.... Orz. 그래도 high order function을 사용해서 functional에 걸맞는 멋진 프로그램이라고 나 자신에게 조금은 구차한(?) 최면을 거는 중이다.
unit test - makefile에서... make file에 다음과 같은 부분을 추가한 후에, make test 하면 간편하게 명령행에서 unit test를 수행할 수있다. (makefile 뼈대는 Programming Erlang을 기초로 했다.)
...... MODS = doc str_util db i18n tiny_scan ......
test: compile test_subdirs rm -rf Mnesia.nonode@nohost # removes previous mneisa db (optional). @for m in ${MODS};\ do \ echo "testing $$m";\ ${ERL} -noshell -pz "subdir1" -pz "subdir2" -s $$m test -s init stop;\ done
test_subdirs: cd subdir1; make test cd subdir2; make test
unit test, coverage test - 개발중 REPL(distel 또는 erl prompt) 에서... REPL을 사용해서 (멋지게) 코딩-테스트를 반복중이라면, 다음과 같은 모듈을 하나 디렉토리에 넣어서 test:unit() 또는 test:cover() 를 실행시켜서 unit test 및 coverage test를 시시때때로 수행해 볼 수 있다.
%%%------------------------------------------------------------------- %%% File : test.erl %%% Author : manywaypark <manywaypark@gmail.com> %%% Description : some test codes. %%% %%% Created : 11 Aug 2008 by manywaypark <manywaypark@gmail.com> %%%------------------------------------------------------------------- -module(test).
83> foo:save_xml("/tmp/foo.xml", Root). ** exception exit: {badarg,[{io,format, [<0.3348.0>,"~s~n", [[60,63,120,109,108,32,118,101,114,115,105, 111,110,61,34,49,46,48,34|...]]]}, {erl_eval,do_apply,5}, {shell,exprs,6}, {shell,eval_exprs,6}, {shell,eval_loop,3}]} in function io:o_request/2
이거 분명히 예전에 공부할 때 예제가 동작하는 것을 확인한 함수였는데.... binary로 써보기로했다.
84> Export=xmerl:export_simple([Root], xmerl_xml). ........ 85> file:write_file("/tmp/1.xml", list_to_binary(lists:flatten(Export))). ** exception error: bad argument in function list_to_binary/1 called as list_to_binary([60,63,120,109,108,32,118,101,114,115,105, 111,110,61,34,49,46,48,34,63,62,60,111,108, 100,114,103,112|...])
한글이 포함되어 안되는 것으로 짐작이 갔다.
99> list_to_binary([0, 1, 2]). <<0,1,2>> 100> list_to_binary([0, 1, 2, 255]). <<0,1,2,255>> 101> list_to_binary([0, 1, 2, 255, 256]). ** exception error: bad argument in function list_to_binary/1 called as list_to_binary([0,1,2,255,256])
결론은 list_to_binary가 255를 넘어가는 non-ascii를 제대로 처리하지 못해서였다.
esolr를 사용하려고 좀 만지작 거리다가, 버그를 하나 발견해서, 리포팅했다. 설명에 나온 기본 세팅으로 하면 잘 되는 것처럼 보이지만, select_url과 search_url 두개의 key가 Option을 설정할 때와 읽어올 때 혼동되게 되어있어서, solr의 URL을 정해주면 제대로 동작하지 않는 버그였다. 딸리는 영어지만 원작자의 페이지에 댓글을 달아두었다. ^^;