用Python修正打印的项目

时间:2011-12-17 00:23:27

标签: python xml

我想更正一个脚本。但我的头是嵌套的。所以我想问问。

脚本是:

from xml.dom.minidom import parse
from itertools import groupby

yXML = parse('/root/Desktop/gb/data/yConfig.xml')

servers = []
for AllConfigurations in yXML.getElementsByTagName('AllConfigurations'):
    for DeployConfigurations in AllConfigurations.getElementsByTagName('DeployConfigurations'):
        for Servers in DeployConfigurations.getElementsByTagName('Servers'):
            for Group in Servers.getElementsByTagName('Group'):
                for GApp in Group.getElementsByTagName('GApp'):
                    for Server in Group.getElementsByTagName('Server'):
                        servers.append((Server.getAttribute('name'),
                                Group.getAttribute('name'),
                                Server.getAttribute('ip'),
                                GApp.getAttribute('type')))

def line(machine, group, ip, services):
    return " | ".join([machine.ljust(22), group.ljust(22), ip.ljust(18), services])

print line("Machine", "Group", "IP", "Services")
print line("----------", "----------", "----------", "----------")
for server, services in groupby(sorted(servers), lambda server: server[0:3]):
    print line("- " + server[0], server[1], server[2],
            ", ".join(service[3] for service in set(services)))

XML是:

<AllConfigurations>
      <DeployConfigurations>
            <Servers>
              <Group id="1" name="The Perfect Life" username="root" password="mypasswd123" state="">
            <GApp id="1" name="JBoss Servers" type="JBoss" path="/root/Desktop/jboss-as-7.0.2.Final/" state="">
                <Server id="1" name="Jboss1" ip="192.168.1.250" path="/root/Desktop/jboss-as-7.0.2.Final/" username="" password="" state="" />
                <Server id="2" name="Jboss2" ip="192.168.1.251" path="/root/Desktop/jboss-as-7.0.2.Final/" username="" password="" state="" />
                <Server id="3" name="Jboss3" ip="192.168.1.252" path="/root/Desktop/jboss-as-7.0.2.Final/" username="" password="" state="" />
                <Server id="4" name="Jboss4" ip="192.168.1.253" path="/root/Desktop/jboss-as-7.0.2.Final/" username="" password="" state="" />
            </GApp>
            <GApp id="2" name="Tomcat Servers" type="Tomcat" path="/root/Desktop/apache-tomcat-7.0.22/" state="">
                <Server id="1" name="Tom1" ip="192.168.1.250" path="/root/Desktop/apachee/" username="" password="" state="" />
                <Server id="2" name="Tom2" ip="192.168.1.251" path="/root/Desktop/apache-tomcat-7.0.22/" username="" password="" state="" />
                <Server id="3" name="Tom3" ip="192.168.1.252" path="/root/Desktop/apache-tomcat-7.0.22/" username="" password="" state="" />
                <Server id="4" name="Tom4" ip="192.168.1.111" path="/root/Desktop/apache-tomcat-7.0.22/" username="" password="" state="" />
            </GApp>
          </Group>
        </Servers>
    </DeployConfigurations>
</AllConfigurations>

当前输出为:

Machine                | Group                  | IP                 | Services
----------             | ----------             | ----------         | ----------
- Jboss1               | The Perfect Life       | 192.168.1.250      | Tomcat, JBoss
- Jboss2               | The Perfect Life       | 192.168.1.251      | Tomcat, JBoss
- Jboss3               | The Perfect Life       | 192.168.1.252      | JBoss, Tomcat
- Jboss4               | The Perfect Life       | 192.168.1.253      | JBoss, Tomcat
- Tom1                 | The Perfect Life       | 192.168.1.250      | JBoss, Tomcat
- Tom2                 | The Perfect Life       | 192.168.1.251      | Tomcat, JBoss
- Tom3                 | The Perfect Life       | 192.168.1.252      | JBoss, Tomcat
- Tom4                 | The Perfect Life       | 192.168.1.111      | JBoss, Tomcat

问题是:

1-正如您在Tom4上看到的那样,192.168.1.111上没有JBoss服务器。此服务器仅适用于Tomcat。 Jboss4只有JBoss(253),其他(250,251,252)都有。服务部分不起作用。

2- IP打印多次。我无法处理......

3-机器栏......

他们都必须是这样的:

Machine                | Group                  | IP                 | Services
----------             | ----------             | ----------         | ----------
- Jboss1 / Tom1        | The Perfect Life       | 192.168.1.250      | JBoss, Tomcat
- Jboss2 / Tom2        | The Perfect Life       | 192.168.1.251      | JBoss, Tomcat
- Jboss3 / Tom3        | The Perfect Life       | 192.168.1.252      | JBoss, Tomcat
- Jboss4               | The Perfect Life       | 192.168.1.253      | JBoss
- Tom4                 | The Perfect Life       | 192.168.1.111      | Tomcat

那么,我该怎么办?

由于

1 个答案:

答案 0 :(得分:2)

警告:此答案很大

您的代码中存在许多问题。

itertools.groupby()使用不正确

最相关的是您使用两个不同的键功能对服务器进行排序和分组。对序列进行分组时,应按照对其进行分组的相同键功能进行排序。在您的情况下,由于您要按IP分组(这是服务器元组的第三个元素),您的函数应该是:

def get_ip(server):
    return server[2]

现在,您甚至可以在处理服务器之前对其进行排序,以便明确:

sorted_servers = sorted(servers, key=get_ip)

groupby()迭代器将产生各种对,由键和迭代器组成,它产生该键的所有结果,正如您可能已经知道的那样。由于密钥是IP,我将按如下方式声明循环。请注意,该功能与对服务器进行排序的功能相同:

for ip, servers in groupby(sorted_servers, get_ip):

连接值以形成列

在循环内部,我们将做什么?对于每个IP,我们将获得所有机器的集合,所有组的集合*以及与IP相关联的所有服务的集合。首先,我们将创建空集:

    machine_set = set()
    group_set = set()
    service_set = set()

然后,我们将迭代由groupby()为给定IP返回的迭代器产生的所有服务器。对于每个服务器,我们将每个服务器信息添加到相应的集合:

    for machine, group, _, service in servers:
        machine_set.add(machine)
        group_set.add(group)
        service_set.add(service)

这样,我们将加入机器,组和服务,每个集合在一个字符串中。然后将这些值传递给line()函数并打印结果:

    machines = " / ".join(machine_set)
    groups = ", ".join(group_set)
    services = ", ".join(service_set)
    print line("- " +  machines, groups, ip, services)

检查点

为清楚起见,结果代码如下。您可以在声明line()函数之前通过以下代码替换所有代码:

def get_ip(server):
    return server[2]

sorted_servers = sorted(servers, key=get_ip)

print line("Machine", "Group", "IP", "Services")
print line("----------", "----------", "----------", "----------")

for ip, servers in groupby(sorted_servers, get_ip):
    machine_set = set()
    group_set = set()
    service_set = set()
    for machine, group, _, service in servers:
        machine_set.add(machine)
        group_set.add(group)
        service_set.add(service)

    machines = " / ".join(machine_set)
    groups = ", ".join(group_set)
    services = ", ".join(service_set)
    print line("- " +  machines, groups, ip, services)

打印结果如下:

Machine                | Group                  | IP                 | Services
----------             | ----------             | ----------         | ----------
- Tom4                 | The Perfect Life       | 192.168.1.111      | JBoss, Tomcat
- Jboss1 / Tom1        | The Perfect Life       | 192.168.1.250      | JBoss, Tomcat
- Tom2 / Jboss2        | The Perfect Life       | 192.168.1.251      | JBoss, Tomcat
- Jboss3 / Tom3        | The Perfect Life       | 192.168.1.252      | JBoss, Tomcat
- Jboss4               | The Perfect Life       | 192.168.1.253      | JBoss, Tomcat

按机器名称

排序

当然:这是我们之前对服务器进行排序的方式。要按你的要求排序,我会建议这个解决方案:在for之前,在变量中创建一个列表。不是打印该行,而是将带有值的元组附加到此列表中:

lines = []
for ip, servers in groupby(sorted_servers, get_ip):
    # ... Same stuff here
    machines = " / ".join(machine_set)
    groups = ", ".join(group_set)
    services = ", ".join(service_set)
    # No more "print line("- " +  machines, groups, ip, services)"
    lines.append((machines, groups, ip, services))

然后,按元组的第一项(机器名称)对列表进行排序:

lines = sorted(lines, key=lambda l: l[0])

现在遍历所有服务器元组并打印行:

for machine, group, ip, service in lines:
    print line(machine, group, ip, service)

加分点:移除循环庞然大物

在程序开始时,您有不少于六个嵌套for循环。男人,这是疯狂(或SPARTAAA,但两者都是坏主意)。您可以通过这种方式轻松删除所有这些嵌套:直接从Server对象检索所有yXML标记。从每个标记中,您可以通过调用server.getAttribute('name')来获取服务器名称。 Group代码是Server代码的祖父母,因此您可以使用server.parentNode.parentNode.getAttribute('name')获取群组名称。可以轻松地从服务器标签中检索IP:server.getAttribute('ip')。服务名称是服务器标签的父级中的属性,因此您可以通过以下方式获取:server.parentNode.getAttribute('type')

总结一下,您可以使用下面相当小的循环获取所有服务器:

for server in yXML.getElementsByTagName('Server'):
    name = server.getAttribute('name')
    group = server.parentNode.parentNode.getAttribute('name')
    ip = server.getAttribute('ip')
    service = server.parentNode.getAttribute('type')
    servers.append((name, group, ip, service))

请记住Zen of Python

  

Flat比嵌套好。

对机器名称

进行排序

哦,当然,还有一个问题:机器名称排序不好。但这很容易修复:只需对集合进行排序即可。替换下面的行

    machines = " / ".join(machine_set)
    groups = ", ".join(group_set)
    services = ", ".join(service_set)

通过以下几行:

    machines = " / ".join(sorted(machine_set))
    groups = ", ".join(sorted(group_set))
    services = ", ".join(sorted(service_set))

在这个例子中,我们正在排序所有集合,而不仅仅是机器名称。我敢打赌这也是一个不错的选择。

我知道这个答案不够长,但我希望两者都能解决你的问题,并澄清了许多观点。

  

*甚至不需要创建一组组,因为您的示例始终只显示一个组。但我会这样做是为了统一。