(一)现象

很偶然的发现,很普通的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;');

添加回车换行的转义字符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;');

(四)总结

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

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

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

直接用dom4j是没法解决问题的,因为在第一步parseText返回 Document对象的候内部节点属性值中回车就被删了。 通过所谓的setTrim 那个方法没有用,因为第一步就错了 需要用到 dom4j 和 jsoup <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --> <dependency> <groupId>org.jsoup</g 有朋友反馈说在xml中的换行符(“\n”)不起作用,原因是解析xml,把”\n”变成了”\\n”,这样就会把换行符原样输出了,解决方法很简单,直接把”\\n”替换成”\n”就可以了,添加一个字符串替换函数。原理:遍历原字符串,查找要替换的字符串在原字符串中的位置pos,然后截取从i到pos的子字符串再跟新字符串拼接,然后更新i,继续查找。 string replace(string public static void main(String[] args) throws Exception { // TODO Auto-generated method stub //读取xml文件 SAXReader reader=new SAXReader(); Doc... 当标签中出现换行,使用传统的读取方法可能出现为空的情况:像截图中的title标签使用下面的方法读取到的内容就可能为空:@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {// TODO Auto-generated method stubsuper.characters(ch...