1

Trying to get the value of an element to a tcl variable sample stats.xml file

<account>
    <name>abc</name>
    <number>1224.3414</number>
</account>

In the above case trying to extract only one element value either name or number

set value
regexp "<$number>(.*?)</number>" stats.xml value
string
  • 13
  • 5

2 Answers2

2

It's usually best to go directly to a DOM-handling utility such as tdom:

package require tdom
set f [open stats.xml]
set xml [read $f]
set doc [dom parse $xml]
$doc selectNodes {string(//number)}

The last line returns the value 1224.3414.

Documentation: tdom (package)

Peter Lewerin
  • 13,140
  • 1
  • 24
  • 27
  • is it possible to do this without tdom? – string Mar 16 '18 at 18:01
  • Sure. It's just a bit harder to write, probably slower, and more likely to result in errors. – Peter Lewerin Mar 16 '18 at 18:04
  • If you insist on doing it without tdom, see my answer. But you really should use tdom (or similar) – Andrew Stein Mar 16 '18 at 19:37
  • if tdom as binary extension is not viable for you, you might test TclXML https://sourceforge.net/projects/tclxml/ which has a tcl-only version of a xml-parser. Speed might be a problem, depending on data size – joheid Apr 24 '18 at 12:09
2

As @Peter says, it is best to use tdom. Trying to parse xml with regexp's will lead to a world of pain. (see Why is it such a bad idea to parse XML with regex?)

That said, if you insist on doing it, then these are the changes you need to your script.

First you need to get the contents of the file into a variable. You are using the regexp on the file's name.

% set fp [open stats.xml]
file5
% set contents [read $fp]
<account>
    <name>abc</name>
    <number>1224.3414</number>
</account>
% close $fp

You also have an error in your pattern (the $ sign in front of number). In addition value will have the entire match. You will need an extra variable (v below), to get just the first match, that is the number. So do the following:

% regexp "<number>(.*?)</number>" $contents value v
1
% puts $v
1224.3414
Andrew Stein
  • 12,880
  • 5
  • 35
  • 43