-2

the last time I asked for help, it did not turn out to what is was looking for. Instead it was more talked about my non-well-formed XML. Therefore let me please try again to describe my problem:

The company of my client is using a huge XML file containing test departments including users of those test departments and more. An extract of a department called "Fighters" would look as following (copied 1:1 (but with different names and numbers)):

<config name="department" version="1.11">
     <xad version="1459" nocheckoutver="1701">
        <!-- ... -->
        <department name="/fighters" id="123879" group="channel" case="none" use="no">
            <replication region="4334">
                <options index_name="index.html" listing="0" sum="no" allowed="no" />
                <!-- ... -->
            </replication>   
            <target prefix="http" suffix=".net" />
            <!-- ... -->
            <user name="T:106603" />
            <user name="T:123879" />
            <user name="test" />
            <user name="ele::123456" />
            <user name="company-temp" />
            <user name="companymw2" />
            <user name="bird" />
            <user name="coding11" />
            <user name="plazamedia" />
            <allow go="123456=abcdefghijklmnopqrstuvwxyz" />    
            <!-- ... -->
        </department>
        <department name="/dancers" id="876543" group="floor" case="yes" use="no">
            <!-- ... -->
        </department>
    <!-- ... -->    
    </xad>
</config>    

Each test department is facing a unique id (here 123879).

So I want to get the number of all users stored in an variable by just searching for the department-id (which is included in " "). How would the command look like in detail?

Note: The number of users in a department vary and the department-id is stored in a variable, let us call it $dept.

Many thanks in advance for a solution and your patience with me still fighting with bash programming. Please note: If the solution would be to run e.g. a Perl script I appreciate too in getting the related code for this.

Borodin
  • 126,100
  • 9
  • 70
  • 144
m_s
  • 37
  • 4

2 Answers2

1

If I fix your data to be well-formed XML (see below), you can use a tool like xmlstarlet to process it

$ xmlstarlet sel -t -v '//department[@id="123879"]/user/@name' -n file.xml 
T:106603
T:123879
test
ele::123456
company-temp
companymw2
bird
coding11
plazamedia
$ xmlstarlet sel -t -v '//department[@id="123879"]/user/@name' -n file.xml |wc -l
9

The XML:

<config name="department" version="1.11">
     <xad version="1459" nocheckoutver="1701">
        <!-- ... -->
        <department name="/fighters" id="123879" group="channel" case="none" use="no">
            <replication region="4334">
                <options index_name="index.html" listing="0" sum="no" allowed="no" />
                <!-- ... -->
            </replication>   
            <target prefix="http" suffix=".net" />
            <!-- ... -->
            <user name="T:106603" />
            <user name="T:123879" />
            <user name="test" />
            <user name="ele::123456" />
            <user name="company-temp" />
            <user name="companymw2" />
            <user name="bird" />
            <user name="coding11" />
            <user name="plazamedia" />
            <allow go="123456=abcdefghijklmnopqrstuvwxyz" />    
            <!-- ... -->
        </department>
        <department name="/dancers" id="876543" group="floor" case="yes" use="no">
            <!-- ... -->
        </department>
    <!-- ... -->    
    </xad>
</config>

xmlstarlet can be downloaded from http://xmlstar.sourceforge.net/download.php

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • I would like to you use your approach here (thanks for sharing). However when running, I receive the following: Entity: line 23: parser error : attributes construct error ^ Entity: line 23: parser error : Couldn't find end of Start Tag value-of line 23 ^ 0 For the sake of completion: A typcial user is , not . My bad; I mistyped it. – m_s Aug 11 '14 at 20:04
  • That's from Glenn's command? If so, looks like `xmlstarlet` incorrectly interpolated into an XSL template. – ikegami Aug 11 '14 at 20:13
  • @m_s, if you're writing that xslt, you can't nest double quotes inside double quotes. Try single quotes: `` – glenn jackman Aug 11 '14 at 20:16
  • It now works, but unfortunately provides the wrong result as following: T::106603 + "blank". And when using _wc -l_ it is returning a 2. Any idea? – m_s Aug 11 '14 at 20:27
  • No. Show your work up in your question, or in a new question. Don't forget to show the input data, what you're actually seeing, and what you expect to see. – glenn jackman Aug 11 '14 at 20:33
  • Done now. See here in case: http://stackoverflow.com/questions/25252040/xmlstarlet-returning-a-wrong-result. – m_s Aug 11 '14 at 20:55
1

I prefer XML::LibXML. It's fast and robust.

You say you want the count all users, but then you specify a department id to use. I'm not sure which one you want, so I'll provide both.

To count all users:

my $num_users = 0;
for my $users ($doc->findnodes("/config/xad/department/users")) {
   ++$num_users;
}

To count the users in the specified deptartment:

for my $dept ($doc->findnodes("/config/xad/department[@id='$dept_id']")) {
   my $num_users = 0;
   for my $user ($dept->findnodes("users")) {
      ++$num_users;
   }
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Thanks so far. But I believe LibXML somehow how has to be referenced in the beginning and is supposed to exist beforehand, which is not the case. Neither I can download and install it due to missing privileges. – m_s Aug 11 '14 at 20:01
  • You don't need special privileges, and all the other XML modules need install too since Perl doesn't come with any. – ikegami Aug 11 '14 at 20:35