Jaspersoft-Python-LXML-CSV-Variable子标签
我正在尝试将Jaspersoft服务器上的用户列表导出为CSV格式,因为我们目前无法访问数据库或任何管理面板,每次需要列表时,我们都必须提交支持通知单并等待2天。我想我会用RESTAPI和python试试运气,在请求模块的帮助下,我成功地导出了保存这些信息的XML。提取的XML的格式如下所示 示例XML:Jaspersoft-Python-LXML-CSV-Variable子标签,python,xml,csv,lxml,Python,Xml,Csv,Lxml,我正在尝试将Jaspersoft服务器上的用户列表导出为CSV格式,因为我们目前无法访问数据库或任何管理面板,每次需要列表时,我们都必须提交支持通知单并等待2天。我想我会用RESTAPI和python试试运气,在请求模块的帮助下,我成功地导出了保存这些信息的XML。提取的XML的格式如下所示 示例XML: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <users> <user>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<users>
<user>
<emailAddress>doejoe@email.com</emailAddress>
<enabled>true</enabled>
<fullName>John Doe</fullName>
<username>doejoe</username>
<roles>
<role>
<externallyDefined>false</externallyDefined>
<name>MANAGER</name>
<desc>Beatings will continue until morale improves</desc>
</role>
<role>
<externallyDefined>false</externallyDefined>
<name>DIRECTOR</name>
</role>
</roles>
</user>
<user>
<emailAddress>kathysmith@email.com</emailAddress>
<enabled>true</enabled>
<fullName>Kathy Smith</fullName>
<username>kathysmith</username>
<externallyDefined>false</externallyDefined>
<roles>
<role>
<externallyDefined>false</externallyDefined>
<name>USER</name>
<desc>User Description</desc>
</role>
<role>
<externallyDefined>false</externallyDefined>
<name>SUPER_MANAGER</name>
<desc>Super Manager description.</desc>
</role>
<role>
<externallyDefined>false</externallyDefined>
<name>SUPER_DIRECTOR</name>
</role>
</roles>
</user>
</users>
正如你所知道的——我不是一个程序员,也不是一个程序员,所以如果你的眼睛流血的话,我向你道歉——我是在3周前开始学习python的。我的代码不起作用有以下几个原因:
- 每个用户可以有1到X个角色,因此我找到的所有示例都有标准数量的子对象
- 某些用户属性可能丢失,因此找不到时出错
- 某些属性正在重复自身,例如,在用户和角色中都定义了外部属性李>
- 我的循环将每个字母导出到一个单独的单元格,但我相信这是我能解决的问题
import lxml.etree as ET
import csv
# load file
tree = ET.parse('users.xml')
# iterate through each user tag
users = tree.findall('.//user')
# just w mode, no wb. wb is for binary data
with open('user_list.csv', "w") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
# write headers
writer.writerow([
'email', 'enabled', 'externallyDefined',
'fullName', 'tenantId', 'username', 'director',
'manager', 'user', 'super manager', 'super director'
])
for user in users:
email = user.find('emailAddress').text
enabled = user.find('enabled').text
# process optional element
externallyDefined = user.find('externallyDefined')
if externallyDefined is not None:
externallyDefined = externallyDefined.text
fullName = user.find('fullName').text
# another optional element
tenantId = user.find('tenantId')
if tenantId is not None:
tenantId = tenantId.text
username = user.find('username').text
# collect nested elements (roles)
user_roles = {}
roles = user.find('roles').findall('role')
for role in roles:
user_roles[role.find('name').text] = True
writer.writerow([
email, enabled, externallyDefined, fullName,
tenantId, username, user_roles.get('DIRECTOR'),
user_roles.get('MANAGER'), user_roles.get('USER'),
user_roles.get('SUPER_MANAGER'), user_roles.get('SUPER_DIRECTOR')
])
对于我如何解决这些问题的任何帮助/指导,我将不胜感激,因为此时我完全不知所措。祝你周末愉快 试试这样的方法:
import lxml.etree as ET
import csv
# load file
tree = ET.parse('users.xml')
# iterate through each user tag
users = tree.findall('.//user')
# just w mode, no wb. wb is for binary data
with open('user_list.csv', "w") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
# write headers
writer.writerow([
'email', 'enabled', 'externallyDefined',
'fullName', 'tenantId', 'username', 'director',
'manager', 'user', 'super manager', 'super director'
])
for user in users:
email = user.find('emailAddress').text
enabled = user.find('enabled').text
# process optional element
externallyDefined = user.find('externallyDefined')
if externallyDefined is not None:
externallyDefined = externallyDefined.text
fullName = user.find('fullName').text
# another optional element
tenantId = user.find('tenantId')
if tenantId is not None:
tenantId = tenantId.text
username = user.find('username').text
# collect nested elements (roles)
user_roles = {}
roles = user.find('roles').findall('role')
for role in roles:
user_roles[role.find('name').text] = True
writer.writerow([
email, enabled, externallyDefined, fullName,
tenantId, username, user_roles.get('DIRECTOR'),
user_roles.get('MANAGER'), user_roles.get('USER'),
user_roles.get('SUPER_MANAGER'), user_roles.get('SUPER_DIRECTOR')
])
一般的方法很简单
- 迭代所有用户
- 提取每个用户的固定XPath表达式集的值
- 将这些值写入CSV文件
- 迭代初始XPath表达式的所有结果
- 提取每个结果的固定XPath表达式集的值
- 将其作为嵌套列表返回(即“列的行”)
- 一个函数,我们称之为
,它接受一个XML节点,对其运行XPath,并返回第一个找到的值。extract_val()
这是必要的,因为lxml的
方法既有简单值(字符串、布尔值、浮点值)也有节点或值列表.xpath()
- 一个函数,比如说
,它可以获取一个xml文档,迭代对象,并将我们的xml\u extract()
应用到每个对象,返回一个值列表extract\u val()
- 我们要提取的XPath列表-这将对应于我们稍后的CSV列
- 最后,
一次写出它们csv.writerows()
import lxml.etree as ET
def extract_val(context_node, xpath):
'''Extracts one value from an XML node'''
result = context_node.xpath(xpath)
if isinstance(result, list):
result = result[0] if len(result) > 0 else None
if isinstance(result, ET._Element):
return result.text
if isinstance(result, (bool, float, str)):
return result
def xml_extract(tree_or_path, object_xpath, property_xpaths):
'''Extracts lists of values from an XML tree (or path to an XML file)'''
if isinstance(tree_or_path, ET._ElementTree):
tree = tree_or_path
if isinstance(tree_or_path, str):
tree = ET.parse(tree_or_path)
for elem in tree.xpath(object_xpath):
yield [extract_val(elem, path) for path in property_xpaths]
#----------------------------------------------------------------------
import csv
with open('user_list.csv', 'w', encoding='utf8', newline='') as csv_file:
writer = csv.writer(csv_file, delimiter=',')
rows = xml_extract('Format.xml', '//user', [
'emailAddress',
'enabled',
'externallyDefined',
'fullName',
'tenantId',
'username',
'count(roles/role[name = "DIRECTOR"]) > 0',
'count(roles/role[name = "MANAGER"]) > 0',
])
writer.writerows(rows)
这种方法非常灵活,可以从任何XML中提取值表(您可能希望这样做),以便重用。您应该包括所需的输出,特别是对于重复的内容和具有多个角色的人员。@Tomalak谢谢,我添加了一个屏幕截图,显示了我们为数百名用户手动执行的操作。任何接近这一点的都可以!非常感谢你!唯一的问题[这是我没有解释的过错]是示例只包含5个角色。是否有任何方法可以从XML中读取所有独特的角色并填写它们?如果没有,那没关系-我仍然可以硬编码它们@HRG,是的,这是可能的。但我不知道开销是否会很大(对于大型xml文件)。@HRG还有一个问题——角色列的顺序可能是随机的,因为我使用set来收集它们。如果需要,您可以按字母顺序对角色集合进行排序,也可以只对角色列表进行硬编码。非常感谢您-数据集非常小[少于1000个用户],因此处理时间不到一秒钟。我觉得很好,非常感谢!