proc xml2list xml { regsub -all {>\s*<} [string trim $xml " \n\t<>"] "\} \{" xml set xml [string map {> "\} \{#text \{" < "\}\} \{"} $xml] set res "" ;# string to collect the result set stack {} ;# track open tags set rest {} foreach item "{$xml}" { switch -regexp -- $item { ^# {append res "{[lrange $item 0 end]} " ; #text item} ^/ { regexp {/(.+)} $item -> tagname ;# end tag set expected [lindex $stack end] set stack [lrange $stack 0 end-1] append res "\}\} " } /$ { # singleton - start and end in one <> group regexp {([^ ]+)( (.+))?/$} $item -> tagname - rest set rest [lrange [string map {= " "} $rest] 0 end] append res "{$tagname [list $rest] {}} " } default { set tagname [lindex $item 0] ;# start tag set rest [lrange [string map {= " "} $item] 1 end] lappend stack $tagname append res "\{$tagname [list $rest] \{" } } } string map {"\} \}" "\}\}"} [lindex $res 0] ;#" } proc deent str { regsub -all {&\#x(.+?);} $str {\\u\1} str subst -nocommands -novar $str } #----------------------- Testing the whole thing: set xml { } foreach i [lindex [xml2list $xml] 2] { if {[lindex $i 0] eq "Student"} { foreach {att val} [lindex $i 1] { if {$att eq "Name"} {puts [deent $val]} } } }