![XML 数据到 CSV](https://linux22.com/image/173653/XML%20%E6%95%B0%E6%8D%AE%E5%88%B0%20CSV.png)
需要一些快速帮助,因为我无法获得所需的输出:
2020-05-19 19:03:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE><DN1>99847</DN1><AMOUNT>49</AMOUNT></COMMAND> -
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE><DN1>92847</DN1><AMOUNT>19</AMOUNT></COMMAND> -
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><DN1>947</DN1><TYPE>RC</TYPE><AMOUNT>29</AMOUNT></COMMAND> -
所需输出:
Time,DN1,AMOUNT
2020-05-19 19:03:07,99847,49
2020-05-19 19:05:07,92847,19
2020-05-19 19:05:07,947,29
答案1
$ awk '
BEGIN { FS=",|</?(DN1|AMOUNT)>"; OFS=","; print "Time", "DN1", "AMOUNT" }
{ print $1, $3, $(NF-1) }
' file
Time,DN1,AMOUNT
2020-05-19 19:03:07,99847,49
2020-05-19 19:05:07,92847,19
2020-05-19 19:05:07,947,29
上面的代码告诉 awk 将输入分成由与存储在FS
(即,
、<DN1>
、</DN1>
、<AMOUNT>
和</AMOUNT>
)中的正则表达式匹配的字符串分隔的字段,然后打印第 1 个、第 3 个和倒数第 2 个这样的字段。
以下是上面如何将每个记录拆分为字段的方法:
$ awk -F',|</?(DN1|AMOUNT)>' '{print "----" ORS $0; for (i=1;i<=NF;i++) print NR, i "/" NF, $i}' file
----
2020-05-19 19:03:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE><DN1>99847</DN1><AMOUNT>49</AMOUNT></COMMAND> -
1 1/6 2020-05-19 19:03:07
1 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE>
1 3/6 99847
1 4/6
1 5/6 49
1 6/6 </COMMAND> -
----
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE><DN1>92847</DN1><AMOUNT>19</AMOUNT></COMMAND> -
2 1/6 2020-05-19 19:05:07
2 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE>
2 3/6 92847
2 4/6
2 5/6 19
2 6/6 </COMMAND> -
----
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><DN1>947</DN1><TYPE>RC</TYPE><AMOUNT>29</AMOUNT></COMMAND> -
3 1/6 2020-05-19 19:05:07
3 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND>
3 3/6 947
3 4/6 <TYPE>RC</TYPE>
3 5/6 29
3 6/6 </COMMAND> -
答案2
结构良好的行可以用以下方式解析sed
:
sed -En 's|^([^,]+),.*<DN1>(.+)</DN1>.*<AMOUNT>(.+)</AMOUNT>.*|\1,\2,\3|p' file
-E
启用扩展正则表达式-n
禁止自动打印读取行s|...|___|
搜索与该...
部分匹配的行并将其替换为___
^([^,]+),
匹配开头直到第一个,
并将其放入\1
<DN1>(.+)</DN1> matches the
DN1element and puts its content into
\2`<AMOUNT>(.+)</AMOUNT>
做同样的事情AMOUNT
\1,\2,\3
替换结果p
确保任何匹配的行都打印在标准输出上
答案3
awk
可以通过以下命令完成sed
:
awk 'BEGIN { FS="AMOUNT|,|DN1" ;OFS=","}; {print $1,$3,$5}' xmlfile | sed 's/<\|>\|\///g' > output.csv
答案4
这种情况用 oneliner 处理有点奇怪,我会坚持将 XML 作为 XML 对象而不是字符串处理,因此我选择了 Python。它将日期解析为字符串并找到用于加载的 XML 字符串。如果您希望将来为来自 XML 或输入行中其他字段的更多节点附加脚本,则此方法将为您提供更大的灵活性。
传递给脚本的第一个参数是您的输入文件。
#!/usr/bin/python
import sys
import xml.etree.ElementTree as ET
def get_lines():
file_name = str(sys.argv[1])
f = open(file_name, 'r')
return f.readlines()
def print_header():
print("Time,DN1,AMOUNT")
def process_xml(xml):
doc = ET.ElementTree(ET.fromstring(xml))
elements = [
doc.find("DN1").text,
doc.find("AMOUNT").text
]
return (",").join(elements)
def process_date(line):
date = line.split()[:2]
date = " ".join(date).split(",")[0]
return date
def process_line(line):
fields = []
date = process_date(line)
xml = process_xml(line.split("<?xml version=\"1.0\"? >")[1][:-3])
fields.append(date)
fields.append(xml)
return (",").join(fields)
def process_all(lines):
print_header()
for line in lines:
print(process_line(line))
if __name__ == "__main__":
lines = get_lines()
process_all(lines)