Oracle数据库XML数据导出为CSV后Shell脚本读取异常求助
Oracle导出XML到CSV后,Shell脚本无法正确解析多行XML内容
我需要从Oracle数据库提取XML数据并导出为CSV格式,再通过Shell脚本读取这些数据,但目前脚本的输出完全不符合预期,恳请大家帮忙排查问题。
我的SQL查询语句
select routeset_name as routeset_name, Trim(Replace(a.XML_MSG.getStringVal(),' ','')) as xml_msg from ums_lrt_staging_routeset_xml_msg a
我的Shell脚本
while IFS="," read -r ROUTESET_NAME XML_MSG do echo "ROUTESET_NAME: $ROUTESET_NAME" echo "XML_MSG: $XML_MSG" echo "" done < <(tail RouteSets.csv)
当前RouteSets.csv内容
ROUTESET_NAME,XML_MSG test,<?xml version="1.0" standalone='yes'?> <localRoutes> <route> <user type="string">100</user> <next type="regex">100</next> </route> <emsVersion> <version>1</version> </emsVersion> </localRoutes>
实际输出结果
ROUTESET_NAME: XML_MSG XML_MSG: ROUTESET_NAME: "<pre><?xml version=""1.0"" standalone='yes'?>" XML_MSG: ROUTESET_NAME: XML_MSG: ROUTESET_NAME: XML_MSG: ROUTESET_NAME: XML_MSG: ROUTESET_NAME: XML_MSG: ROUTESET_NAME: XML_MSG:
期望输出结果
ROUTESET_NAME: test XML_MSG:<?xml version="1.0" standalone='yes'?><localRoutes><route><user type="string">100</user><next type="regex">100</next></route><emsVersion><version>1</version></emsVersion></localRoutes>
已尝试的解决方法
- 使用
getStringValue方法将XML转换为字符串,但无效; - 使用
Trim方法去除首尾空格,无效; - 使用
Replace方法去除标签间空格,无效。
问题根源分析
你的核心问题出在CSV格式不规范和Shell读取逻辑不匹配:
- 导出的XML是多行格式化的,但CSV默认是每行一条记录,且字段内的换行需要用双引号包裹,否则Shell的
read命令会把每一行XML都当成独立的记录处理; - 你用
tail RouteSets.csv没有跳过表头行,导致表头被当成一条记录读取; - 即使去掉空格,XML的换行依然存在,无法让
read把整个XML识别为单个字段。
解决方案
1. 修正SQL,生成规范的单行CSV
要让XML成为CSV的单个字段,需要把XML转成单行无格式字符串,并用双引号包裹(符合CSV规范)。推荐使用Oracle的XMLSERIALIZE函数直接生成无缩进的单行XML:
SELECT routeset_name AS routeset_name, '"' || XMLSERIALIZE(CONTENT a.XML_MSG AS VARCHAR2(4000) NO INDENT) || '"' AS xml_msg FROM ums_lrt_staging_routeset_xml_msg a;
NO INDENT会去掉XML的所有缩进和换行,直接输出单行字符串;- 用双引号包裹XML字段,确保CSV解析器将其识别为单个字段。
如果无法使用XMLSERIALIZE,也可以手动去除换行符:
SELECT routeset_name AS routeset_name, '"' || REPLACE(REPLACE(a.XML_MSG.getStringVal(), CHR(10), ''), CHR(13), '') || '"' AS xml_msg FROM ums_lrt_staging_routeset_xml_msg a;
这里CHR(10)是换行符,CHR(13)是回车符,双重替换确保XML完全单行。
2. 修正Shell脚本,正确读取CSV
现在CSV是规范格式了,我们可以用更可靠的方式读取,比如用awk(原生工具,无需额外安装)来处理带引号的字段:
awk -F ',' 'BEGIN {OFS=","} NR>1 { gsub(/^"|"$/, "", $2) # 去掉XML字段前后的双引号 print "ROUTESET_NAME: " $1 print "XML_MSG:" $2 print "" }' RouteSets.csv
NR>1跳过表头行;gsub去掉XML字段的首尾双引号,避免输出带引号的内容;- 直接输出你需要的格式。
如果坚持用while read循环,可以用以下方法(处理带引号的字段):
while IFS= read -r line do # 跳过表头 if [[ "$line" == ROUTESET_NAME* ]]; then continue fi # 拆分字段:第一个逗号前是ROUTESET_NAME,后面的是XML_MSG(包括引号) ROUTESET_NAME="${line%%,*}" XML_MSG="${line#*,}" # 去掉XML_MSG的首尾引号 XML_MSG="${XML_MSG%\"}" XML_MSG="${XML_MSG#\"}" echo "ROUTESET_NAME: $ROUTESET_NAME" echo "XML_MSG:$XML_MSG" echo "" done < RouteSets.csv
验证结果
执行修正后的SQL导出CSV后,再运行新的Shell脚本,就能得到你期望的输出了。
内容的提问来源于stack exchange,提问作者akt
相关产品推荐
相关产品推荐

