(一)现象
很偶然的发现,很普通的SQL语句,在我们自己的Java程序中执行出错。
但是在数据库工具中执行正常,类似如下:
select '<YYYY>','<MM>','<DD>','<DDD>' -- test the datetime
,sysdate,systimestamp from dual
看日志,我们执行的语句变成了:
select '2022','09','14','257' -- test the datetime ,sysdate,systimestamp from dual
由于多行变单行,所以注释掉了后续所有内容,导致报错:
业务处理错误: ORA-00923: FROM keyword not found where expected
(二)分析
这段SQL语句是保存在XML当中的,检查原始XML内容发现换行是存在的:
换行也是明显存在的。
......
<Task FileQ="XXX" SQL="select xxx,yyy,zzz -- test the datetime
,sysdate,systimestamp from dual" CHK="1" />
......
但是dom4j(org.w3c.dom也一样)读出来SAXReader.read()
的时候呢,
数据内容中的换行就已经被替换成空格了。
研究了一阵,得到的结论是,Java并没有错……
因为XML格式,数据内容中的回车换行\r
\n
,应该使用转义字符


。
也就是说,上面那段XML,应该保存成如下格式:
......
<Task FileQ="XXX" SQL="select xxx,yyy,zzz -- test the datetime
,sysdate,systimestamp from dual" CHK="1" />
......
(三)解决
只需要保存XML时使用转义字符就可以了。
Java程序在执行SQL时就可以读取到多行,第一行末的注释,也不会再影响后续行了。
正常情况下,这里就完结了。
⭕️
……
可是我们的Windows下的配置界面不是Web页面,也不是Java程序。
读写XML部分使用的是 🔗OmniXML。
测试了一下,OmniXML读取转义/非转义的换行符都正常。
但是它保存换行符时,似乎只能非转义,也就是直接存,没有参数选项……
幸好有源代码。
检查源文件,找到转换转义字符的代码:
case Ord(Value[iValue]) of
34: Store('"');
38: Store('&');
39: Store(''');
60: Store('<');
62: Store('>');
else
添加回车换行的转义字符13
10
,也就是\r
\n
(Pascal并不这样写)。
case Ord(Value[iValue]) of
10: Store('
');
13: Store('
');
34: Store('"');
38: Store('&');
39: Store(''');
60: Store('<');
62: Store('>');
else
(四)总结
这是 不同语言 / 不同时代 的程序模块,配合时出现的问题。
我们应该遵守规范:🔗 XML格式标准。
但现实中我们无法完全控制输入的内容格式。
所以Java如果在XML读写上,给个选项(是否兼容原始未转义\r
\n
)才能完全解决。