将XML中的<*></*>标签数据导出到CSV(多种不同XML样式格式)
--即使我学了一点XSLT,我也没用上,因为元数据/xls格式会变化,所以单一的样式表方法行不通---
我这几小时一直在尝试把一个csv文件里的数据提取出来,想把每个标签的数据放到一个新的CSV里,但一直没成功。我试过elemtree、parse和正则表达式,参考了论坛里的一些问答。
有一个例子在他的测试数据上运行得很好,但在我的xml上却不行(样本在问题的最后)。
tree = ET.parse("test2.xml")
doc = tree.getroot()
thingy = doc.find('custod')
print thingy.attrib
错误追踪(最近的调用最后): 文件 "", 第 1 行, 在 AttributeError: 'NoneType' 对象没有属性 'attrib'
doc
<Element anzmeta at 801a300>
thingy = doc.find('anzmeta')
print thingy.attrib
错误追踪(最近的调用最后): 文件 "", 第 1 行, 在 AttributeError: 'NoneType' 对象没有属性 'attrib'
doc.attrib
{}
--- 尝试使用REX
rex = re.compile(r'<custod.*?>(.*?)</custod>',re.S|re.M)
rex
<_sre.SRE_Pattern object at 0x080724A0>
match=rex.match('test2.xml')
match
text = match.groups()[0].strip()
错误追踪(最近的调用最后): 文件 "", 第 1 行, 在 AttributeError: 'NoneType' 对象没有属性 'groups'
我只需要系统能遍历我的xml文件,创建一个csv,里面每一列对应每个标签的完整内容。如果有新列需要添加,就加上,然后相应地填充数据。
=========== XML样本
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/xsl' href='ANZMeta.xsl'?>
<anzmeta>
<citeinfo>
<uniqueid />
<title><></title>
<origin>
<custod>ATGIS</custod>
<jurisdic>
<keyword thesaurus="">Tablelands Regional Council</keyword>
</jurisdic>
</origin>
</citeinfo>
<descript>
<abstract><>
</abstract>
<theme>
<keyword thesaurus="">EPSG</keyword>
</theme>
<spdom>
<keyword thesaurus="">GDA94</keyword>
<keyword thesaurus="">GRS80</keyword>
<keyword thesaurus="">Map Grid of Australia</keyword>
<keyword thesaurus="">Zone 55 (144E - 150E)</keyword>
<bounding>
<northbc />
<southbc />
<eastbc />
<westbc />
</bounding>
</spdom>
</descript>
<timeperd>
<begdate>
<date>2012</date>
</begdate>
<enddate>
<keyword thesaurus="">Completed</keyword>
</enddate>
</timeperd>
<status>
<progress>
<keyword thesaurus="">Ongoing</keyword>
<keyword thesaurus="">Completed</keyword>
</progress>
<update>
<keyword thesaurus="">As Required</keyword>
<keyword thesaurus="">As Required</keyword>
</update>
</status>
<distinfo>
<native>
<nondig>
<formname>File</formname>
</nondig>
<digform>
<formname>Type:</formname>
</digform>
</native>
<avlform>
<nondig>
<formname>Format:</formname>
</nondig>
<digform>
<formname>Size</formname>
</digform>
</avlform>
<accconst>Internal Use Only</accconst>
</distinfo>
<dataqual>
<lineage>~TBC~</lineage>
<procstep>
<procdesc Sync="TUE">Metadata imported.</procdesc>
<srcused Sync="TRUE">L:\Data_Admin\MetadataGenerator\trc_Metadata_Template.xml</srcused>
<date Sync="TRUE">20121206</date>
<time Sync="TRUE">15341400</time>
</procstep>
<posacc>~TBC~</posacc>
<attracc>~TBC~</attracc>
<logic>~TBC~</logic>
<complete>~TBC~</complete>
</dataqual>
<cntinfo>
<cntorg>Atherton Tablelands GIS</cntorg>
<cntpos>GIS Coordinator</cntpos>
<address>PO Box 1616, 8 Tolga Rd</address>
<city>Atherton</city>
<state>QLD</state>
<country>AUSTRALIA</country>
<postal>4883</postal>
<cntvoice>07 40918600</cntvoice>
<cntfax>07 40917035</cntfax>
<cntemail>info@atgis.com.au</cntemail>
</cntinfo>
<metainfo>
<metd>
<date />
</metd>
</metainfo>
</anzmeta>
--- 我的脚本开始
import os, xml, shutil, datetime
from xml.etree import ElementTree as et
SourceDIR=os.getcwd()
outDIR=os.getcwd()+'//out'
def locatexml(SourceDIR,outDIR):
xmllist=[]
for root, dirs, files in os.walk(SourceDIR, topdown=False):
for fl in files:
currentFile=os.path.join(root, fl)
ext=fl[fl.rfind('.')+1:]
if ext=='xml':
xmllist.append(currentFile)
print currentFile
readxml(currentFile)
print "finished"
return xmllist
def readxml(currentFile):
tree=et.parse(currentFile)
print "Processing: "+str(currentFile)
locatexml(SourceDIR,outDIR)
print xmllist
2 个回答
<anzmeta>
是你文档的根标签,所以你应该去找它的直接子标签,比如 citeinfo
,而不是直接去找根标签的名字。
你真的应该使用XSLT来完成这个工作,因为它是将XML转换成另一种格式。你可以查看这个问题的答案,了解一个例子:这个问题。
不过,如果你出于其他原因想用lxml
来做,下面有一些代码可以帮助你入门:
from lxml import etree
with open('test.xml') as f:
tree = etree.parse(f)
# At this point, we can step through the xml file
# and parse it, here is an example of the `cntinfo` tag
for element in tree.iter('cntinfo'):
for child in element.getchildren():
print "{0.tag}: {0.text}".format(child)
这段代码会输出:
cntorg: Atherton Tablelands GIS
cntpos: GIS Coordinator
address: PO Box 1616, 8 Tolga Rd
city: Atherton
state: QLD
country: AUSTRALIA
postal: 4883
cntvoice: 07 40918600
cntfax: 07 40917035
cntemail: info@atgis.com.au
你也可以以类似的方式遍历文件中的其他元素;但我强烈建议你使用XSLT。
这段代码片段将使用XSLT样式表把XML文档转换成CSV(来自这个问题):
# First, we load the stylesheet
with open(r'd:\test.xsl') as f:
temp = etree.parse(f)
style_sheet = etree.XSLT(temp)
# Apply it to the previously parsed document tree:
converted_xml = style_sheet(tree)
# Print the results:
str(converted_xml)
这将给你:
'"", "<>", "ATGISTablelands Regional Council"\r"<>", "EPSG",
"GDA94GRS80Map Grid of AustraliaZone 55 (144E - 150E)"\r"2012", "Completed"
\r"OngoingCompleted", "As RequiredAs Required"\r"FileType:", "Format:Size"
, "Internal Use Only"\r"~TBC~", "Metadata imported.L:\\Data_Admin\\Metadat
aGenerator\\trc_Metadata_Template.xml2012120615341400", "~TBC~", "~TBC~",
"~TBC~", "~TBC~"\r"Atherton Tablelands GIS", "GIS Coordinator", "PO
Box 1616, 8 Tolga Rd", "Atherton", "QLD", "AUSTRALIA", "4883", "0
7 40918600", "07 40917035", "info@atgis.com.au"\r""\r'