Parsing XML to telegraf, possible select several children paths?

Hi, I have xml like this

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
	<err>0</err>
	<devname>Thermo</devname>
	<devsn>22940676</devsn>
	<time>2022-04-27T10:35:55+01:00</time>
	<timeunix>1651055755</timeunix>
	<synch>1</synch>
	<ch1>
		<name>Humidity</name>
		<unit>%RH</unit>
		<aval>34.2</aval>
		<alarm>0</alarm>
	</ch1>
	<ch2>
		<name>Temperature</name>
		<unit>°C</unit>
		<aval>20.9</aval>
		<alarm>0</alarm>
	</ch2>
	<ch3>
		<name>Channel 3</name>
		<unit></unit>
		<aval>n/a</aval>
		<alarm>0</alarm>
	</ch3>
	<ch4>
		<name>Channel 4</name>
		<unit></unit>
		<aval>n/a</aval>
		<alarm>0</alarm>
	</ch4>
	<ch5>
		<name>Channel 5</name>
		<unit></unit>
		<aval>n/a</aval>
		<alarm>0</alarm>
	</ch5>
</root>

and need select fields only from ch1 and ch2, normally I would use this expression:

/root/ch1/name | /root/ch2/name

But it seems this is not possible in the telegraph config. Currently I can select just ch1. Any advise ?

[[inputs.http]]
  interval = "60s"
  name_override = "thermometer"
  tagexclude = ["url", "host"]
  urls = ["http://192.168.1.8/values.xml"]
  data_format = "xml"  
  
  [[inputs.http.xml]]
#    timestamp = "root/timeunix"
    [inputs.http.xml.tags]
      devname = "string(/root/devname)"
    [inputs.http.xml.fields_int]
      alarm = "number(/root/ch1/alarm)"
    [inputs.http.xml.fields]
      sensor = "string(/root/ch1/name)"
	  value = "number(/root/ch1/aval)"
      unit = "string(/root/ch1/unit)"

Hello @CZvacko,
Have you seen this?

What happens when you try:

 [inputs.http.xml.fields]
      sensor = "string(/root/ch2/name)"
     value = "number(/root/ch2/aval)"
      unit = "string(/root/ch2/unit)"

?

Hi, yes I read that, that’s a nice example, but the child elements use the same name, but in my case the child element name is incremented by +1.

Before asking this question, I tried your suggestion (add such lines under original) and telegraf reject it with below message

[telegraf] Error running agent: Error loading config file C:\Program Files\InfluxData\telegraf.conf: Error parsing data: line 247: table inputs.http.xml.fields is in conflict with table in line 243

It sounds like you want to have one metric for root/ch1 and another metric for root/ch2. When you need a metric per xml node like this, you need to use the metric_selection setting of telegraf’s xml parser. telegraf/README.md at master · influxdata/telegraf · GitHub

Here’s an example I got working with your data. I’ve switched to a file input instead of http, but that’s not important.

[[inputs.file]]
  name_override = "thermometer"
  files = ["community-24806.xml"]
  data_format = "xml"  
 
  [[inputs.file.xml]]
    metric_selection = "/root/ch1|/root/ch2"
    # metric_selection = "/root/*[starts-with(name(),'ch')]" # or if you want all nodes starting with ch
    timestamp = "root/timeunix"
    [inputs.file.xml.tags]
      channel = "substring-after(name(), 'ch')"
      sensor = "name"
    [inputs.file.xml.fields_int]
      alarm = "number(alarm)"
    [inputs.file.xml.fields]
      # sensor = "string(name)" # this is now a tag
      value = "number(aval)"
      unit = "string(unit)"

It produces metrics that look like this

thermometer,channel=1,sensor=Humidity alarm=0i,value=34.2,unit="%RH" 1651266283000000000
thermometer,channel=2,sensor=Temperature alarm=0i,value=20.9,unit="°C" 1651266283000000000
3 Likes

Hi @reimda
Thanks for the support, I didn’t know xpath could be used.
Just a small problem, I still want to store the devname in the db, but now it seems that metric_selection has removed this information. How to solve it ?

Hi @reimda,
as workaround I was trying reconfig device and rename sensor name to include also devname.
But there is a string length limitation, so now I have no way to identify the device. :neutral_face:

Hey @CZvacko,

if you want to store devname as a tag in your example, just specify an absolute path (outside of the selected metric) by adding devname = "/root/devname" to your [inputs.file.xml.tags] section. Similar is possible for fields…

Does that help?

Hi @srebhan, yes, it works! Originaly I used devname = "string(/root/devname)" and after I was advised to use metric_selection, it stopped working. Then I played around with it in many ways, not sure why string() can’t be used for tag selection when it can be used for field selection. I can’t believe it’s that simple :grinning:

I think string() should neither work for field_selection nor for tag_selection as the selection needs to be a node. Anyway, for tags the target-type is clear (string), furthermore, the default-type in XML is string, so you should omit that anyway.

Anyhow, glad it helped. :wink: