Search code examples
tcltdom

tDOM not parsing the XML


I have this XML sample template from a command line output,

<config xmlns="http://tail-f.com/ns/config/1.0">
  <random xmlns="http://random.com/ns/random/config">
    <junk-id>1</junk-id>
    <junk-ip-address>1.2.2.3</junk-ip-address>
    <junk-state>success</junk-state>
    <junk-rcvd>158558</junk-rcvd>
    <junk-sent>158520</junk-sent>
    <foobar>
      <id1>1</id1>
      <id2>1</id2>
    </foobar>
  </random>
</config>

I need to extract the value of junk-state from this XML.

I made a .tcl script to run on this with a variable and using single quotes just for testing purposes as below,

Below are contents of my script. I just tried looping around the nodes, but with no success.

set XML "<config xmlns='http://tail-f.com/ns/config/1.0'>
      <random xmlns='http://random.com/ns/random/config'>
        <junk-id>1</junk-id>
        <junk-ip-address>1.2.2.3</junk-ip-address>
        <junk-state>success</junk-state>
        <junk-rcvd>158558</junk-rcvd>
        <junk-sent>158520</junk-sent>
        <foobar>
          <id1>1</id1>
          <id2>1</id2>
        </foobar>
      </random>
    </config>"


set doc [dom parse $XML]
set root [$doc documentElement]
set mynode [$root selectNodes "/config/random" ]

 foreach node $mynode{
    set temp1 [$node text]
    echo "temp1 - $temp1"
 }

The above script produces no output,

Also tried a direct xpath expression as below and print text

set node [$root selectNodes /config/random/junk-state/text()]
puts [$node nodeValue]
puts [$node data

and this produces an error

invalid command name ""
    while executing
"$node nodeValue"
    invoked from within
"puts [$node nodeValue]"
    (file "temp.tcl" line 41)

What am I doing wrong here. Like to know how use/modify my xpath expression, since I find that neater.

$ tclsh
% puts $tcl_version
8.5
% package require tdom
0.8.3

Solution

  • The problems are due to the XML namespaces (xmlns attributes in the config and random elements). You must use the -namespace option of selectNodes operation:

    package require tdom
    set XML {<config xmlns="http://tail-f.com/ns/config/1.0">
          <random xmlns="http://random.com/ns/random/config">
            <junk-id>1</junk-id>
            <junk-ip-address>1.2.2.3</junk-ip-address>
            <junk-state>success</junk-state>
            <junk-rcvd>158558</junk-rcvd>
            <junk-sent>158520</junk-sent>
            <foobar>
              <id1>1</id1>
              <id2>1</id2>
            </foobar>
          </random>
        </config>}
    
    
    set doc [dom parse $XML]
    set root [$doc documentElement]
    set node [$root selectNodes -namespace {x http://random.com/ns/random/config} x:random/x:junk-state ]
    puts [$node text]
    

    EDIT: If you want the namespace of the <random> element to be retrieved from the XML automatically you can do it as follows (assuming that <random> is the only child of the root element):

    set doc [dom parse $XML]
    set root [$doc documentElement]
    set random [$root childNode]
    set ns [$random namespace]
    set node [$random selectNodes -namespace [list x $ns] x:junk-state]
    puts [$node text]