Search code examples
pythonxmllisttabular

Printing data to list styled (table) from XML in Python


I'd like to print my servers as listed. Like this:

Machine  | Group               | IP            | Services
- Alpha  | Public Server Group | 192.168.1.251 | JBoss, Tomcat
- Public | Public Server Group | 192.168.1.253 | JBoss, Tomcat

My XML is:

<?xml version="1.0" ?>
<AllConfigurations>

<DeployConfigurations>

    <Servers>

        <Group id="1" name="Public Server Group" 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="Alpha" ip="192.168.1.251" path="/root/Desktop/jboss-as-7.0.2.Final/" username="" password="" state="" />
                <Server id="2" name="Public" 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="Alpha" ip="192.168.1.251" path="/root/Desktop/apache-tomcat-7.0.22/" username="" password="" state="" />
                <Server id="2" name="Public" ip="192.168.1.253" path="/root/Desktop/apache-tomcat-7.0.22/" username="" password="" state="" />
            </GApp>
        </Group>

    </Servers>

</DeployConfigurations>

</AllConfigurations>

I'm trying to do by this:

from xml.dom.minidom import parse

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

print (' ')
print ('Machine       |       Group       |       IP       |       Services')

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'):

                        print Server.getAttribute('name') + ' | ' + Group.getAttribute('name') + ' | ' + Server.getAttribute('ip') + ' | ' + GApp.getAttribute('type')

My result is:

Machine  | Group               | IP            | Services
Alpha | Public Server Group | 192.168.1.251 | JBoss
Public | Public Server Group | 192.168.1.253 | JBoss
Alpha | Public Server Group | 192.168.1.251 | JBoss
Public | Public Server Group | 192.168.1.253 | JBoss
Alpha | Public Server Group | 192.168.1.251 | Tomcat
Public | Public Server Group | 192.168.1.253 | Tomcat
Alpha | Public Server Group | 192.168.1.251 | Tomcat
Public | Public Server Group | 192.168.1.253 | Tomcat

What should I do?

Its printing for every possibility. I can't align Services side-by-side, print for one IP and look like table.

Need help..


Solution

  • First of all, you cannot print the lines right away; rather store the data (as tuples) in a list (servers). To group the services by machine / group / IP, you can use the itertools function groupby, specifying the first three fields as key tuple. (Before that, the list has to be sorted so groupby finds all duplicates.) groupby yields the key (3-tuple) and a generator for the rest of corresponding lines; here, we're interested in the unique values of the fourth value (the service), so we convert the values to a set and join them by spaces.

    The issue with aligning the table can be solved by using the string function ljust (left justify). I made a separate function to generalize the rendering of the header line and the data rows.

    Here's the code:

    from itertools import groupby
    
    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(8), group.ljust(20), ip.ljust(15), services])
    
    print line("Machine", "Group", "IP", "Services")
    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)))
    

    This prints

    Machine  | Group                | IP              | Services
    - Alpha  | Public Server Group  | 192.168.1.251   | JBoss, Tomcat
    - Public | Public Server Group  | 192.168.1.253   | Tomcat, JBoss