很偶然的发现,很普通的SQL语句,在我们自己的Java程序中执行出错。
但是在数据库工具中执行正常,类似如下:
select '<YYYY>','<MM>','<DD>','<DDD>'
,sysdate,systimestamp from dual
看日志,我们执行的语句变成了:
select '2022','09','14','257'
由于多行变单行,所以注释掉了后续所有内容,导致报错:
业务处理错误: 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('>');
添加回车换行的转义字符13
10
,也就是\r
\n
(Pascal并不这样写)。
case Ord(Value[iValue]) of
10: Store('
');
13: Store('
');
34: Store('"');
38: Store('&');
39: Store(''');
60: Store('<');
62: Store('>');
这是 不同语言 / 不同时代 的程序模块,配合时出现的问题。
我们应该遵守规范:🔗 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...