我想更正一个脚本。但我的头是嵌套的。所以我想问问。
脚本是:
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
那么,我该怎么办?
由于
答案 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))
在这个例子中,我们正在排序所有集合,而不仅仅是机器名称。我敢打赌这也是一个不错的选择。
我知道这个答案不够长,但我希望两者都能解决你的问题,并澄清了许多观点。
*甚至不需要创建一组组,因为您的示例始终只显示一个组。但我会这样做是为了统一。