(一)现象

很偶然的发现,很普通的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,应该使用转义字符&#0013; &#0010;
也就是说,上面那段XML,应该保存成如下格式:

......
<Task FileQ="XXX" SQL="select xxx,yyy,zzz -- test the datetime&#0013;&#0010;,sysdate,systimestamp from dual" CHK="1" />
......

(三)解决

只需要保存XML时使用转义字符就可以了。
Java程序在执行SQL时就可以读取到多行,第一行末的注释,也不会再影响后续行了。

正常情况下,这里就完结了。

⭕️

……

可是我们的Windows下的配置界面不是Web页面,也不是Java程序。
读写XML部分使用的是 🔗OmniXML

测试了一下,OmniXML读取转义/非转义的换行符都正常。
但是它保存换行符时,似乎只能非转义,也就是直接存,没有参数选项……

幸好有源代码。

检查源文件,找到转换转义字符的代码:

    case Ord(Value[iValue]) of
      34: Store('&quot;');
      38: Store('&amp;');
      39: Store('&apos;');
      60: Store('&lt;');
      62: Store('&gt;');
    else

添加回车换行的转义字符13 10,也就是\r \n(Pascal并不这样写)。

    case Ord(Value[iValue]) of
      10: Store('&#0010;');
      13: Store('&#0013;');
      34: Store('&quot;');
      38: Store('&amp;');
      39: Store('&apos;');
      60: Store('&lt;');
      62: Store('&gt;');
    else

(四)总结

这是 不同语言 / 不同时代 的程序模块,配合时出现的问题。

我们应该遵守规范:🔗 XML格式标准
但现实中我们无法完全控制输入的内容格式。

所以Java如果在XML读写上,给个选项(是否兼容原始未转义\r \n)才能完全解决。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐