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。由于多种原因,我的代码无法正常工作:

我的最终目标是这样的:

任何 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 重复使用。