Jaspersoft - Python - LXML - CSV - 变量 Children 标签
Jaspersoft - Python - LXML - CSV - Variable Children Tags
我正在尝试将用户列表从 Jaspersoft 服务器导出为 CSV 格式,因为我们目前无法访问数据库或任何管理面板,我们必须提出支持请求并等待 2 天时间我们想要一个列表。我想我会使用 REST API 和 python 来碰碰运气,在请求模块的帮助下,我设法导出了包含此信息的 XML。提取出来的XML格式是这样的。
样本XML:
<?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>
到目前为止我的代码:
import lxml.etree as ET
import csv
# load file
tree = ET.parse('Format.xml')
# iterate through each user tag
users = tree.findall('.//user')
with open('user_list.csv', "wb") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
for user in users:
email = user.find('emailAddress').text
enabled = user.find('enabled').text
externallyDefined = user.find('externallyDefined').text
fullName = user.find('fullName').text
tenantId = user.find('tenantId').text
username = user.find('username').text
writer.writerow(email + ',' + enabled + ',' + externallyDefined + ',' + fullName + ',' + tenantId + ',' + username)
如您所知 - 我不是程序员,甚至还不够接近,所以如果你的眼睛流血,我深表歉意 - 3 周前开始学习 python。由于多种原因,我的代码无法正常工作:
- 每个用户可以拥有 1 到 X 数量的角色,因此我设法找到的所有示例都具有标准数量的 children。
- 某些用户属性可能缺失,因此在找不到时出现错误。
- 有些属性在重复,例如在用户和角色中都在外部定义!
- 我的循环将每个字母导出到一个单独的单元格,但我相信我可以解决这个问题。
我的最终目标是这样的:
任何 help/direction 我将如何解决这些问题中的任何一个都将不胜感激,因为此时我完全迷失了。周末愉快!
尝试这样的事情:
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 表达式的值,
- return 嵌套列表(即 "rows of columns")
为此我们基本上需要
- 一个函数,我们称它为
extract_val()
,它接受一个 XML 节点,对其运行 XPath,并 return 第一个找到的值。
这是必要的,因为 lxml 的 .xpath()
方法 can return 既有简单值(字符串、布尔值、浮点数)也有节点或值列表。
- 一个函数,比方说
xml_extract()
,它可以接受一个 XML 文档,遍历对象并将我们的 extract_val()
应用于每个对象,returning a值列表
- 我们要提取的 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 中提取值表,您可能希望 turn it into a module 重复使用。
我正在尝试将用户列表从 Jaspersoft 服务器导出为 CSV 格式,因为我们目前无法访问数据库或任何管理面板,我们必须提出支持请求并等待 2 天时间我们想要一个列表。我想我会使用 REST API 和 python 来碰碰运气,在请求模块的帮助下,我设法导出了包含此信息的 XML。提取出来的XML格式是这样的。
样本XML:
<?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>
到目前为止我的代码:
import lxml.etree as ET
import csv
# load file
tree = ET.parse('Format.xml')
# iterate through each user tag
users = tree.findall('.//user')
with open('user_list.csv', "wb") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
for user in users:
email = user.find('emailAddress').text
enabled = user.find('enabled').text
externallyDefined = user.find('externallyDefined').text
fullName = user.find('fullName').text
tenantId = user.find('tenantId').text
username = user.find('username').text
writer.writerow(email + ',' + enabled + ',' + externallyDefined + ',' + fullName + ',' + tenantId + ',' + username)
如您所知 - 我不是程序员,甚至还不够接近,所以如果你的眼睛流血,我深表歉意 - 3 周前开始学习 python。由于多种原因,我的代码无法正常工作:
- 每个用户可以拥有 1 到 X 数量的角色,因此我设法找到的所有示例都具有标准数量的 children。
- 某些用户属性可能缺失,因此在找不到时出现错误。
- 有些属性在重复,例如在用户和角色中都在外部定义!
- 我的循环将每个字母导出到一个单独的单元格,但我相信我可以解决这个问题。
我的最终目标是这样的:
任何 help/direction 我将如何解决这些问题中的任何一个都将不胜感激,因为此时我完全迷失了。周末愉快!
尝试这样的事情:
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 表达式的值,
- return 嵌套列表(即 "rows of columns")
为此我们基本上需要
- 一个函数,我们称它为
extract_val()
,它接受一个 XML 节点,对其运行 XPath,并 return 第一个找到的值。
这是必要的,因为 lxml 的.xpath()
方法 can return 既有简单值(字符串、布尔值、浮点数)也有节点或值列表。 - 一个函数,比方说
xml_extract()
,它可以接受一个 XML 文档,遍历对象并将我们的extract_val()
应用于每个对象,returning a值列表 - 我们要提取的 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 中提取值表,您可能希望 turn it into a module 重复使用。