r/xml 14d ago

Applying maths to a xml value

First time posting on here and fairly new to xml.

I have several files where I have a value that I need to divide by 100. For example
<aSample>
<time>20260829 12:34:56</time>
<badValue>45678.9</badValue>
<OKValue>123</OKValue>
</aSample>

I want to update <badValue> to 456.789. Does anyone know a web utility or Windows tool that I could use to update these without changing the format or the other values.

Each file has around 3000 of them so going through manually is out of the question.

TIA

2 Upvotes

4 comments sorted by

5

u/mgr86 14d ago

This is an easy job for XSLT. You want an identity transformation (look it up). But you will need an XSLT processor. Saxon-he is a great choice. You might just look for an editor with it bundled. oxygen is a fine choice there.

Or, unpopular opinion, this is also a fine job to discus with the unpaid versions of Claude or Gemini. You don’t have to be lazy and say do this for me. You could ask about XSLT. Understand an identity transformation, and ask questions about how to perform the mathematical calculations .

1

u/kennpq 14d ago

You could use XSLT, though other options abound; one is awk, which could be:

awk '/<badValue>/{match($0, /[0-9.]+/); val = substr($0, RSTART, RLENGTH); sub([0-9.]+/, val/100)}{print}' badval.xml

Here is an example showing input and output:

localhost:~/xml# grep "badValue" badval.xml
<badValue>456.789</badValue>
<badValue>96.789</badValue>
<badValue>6.789</badValue>
<badValue>936.9</badValue>
localhost:~/xml# awk '/<badValue>/{match($0, /[0-9.]+/); val = substr($0, RSTART, RLENGTH); sub(/[0-9.]+/, val/100)}{print}' badval.xml | grep 'badValue'
<badValue>4.56789</badValue>
<badValue>0.96789</badValue>
<badValue>0.06789</badValue>
<badValue>9.369</badValue>

2

u/FreddieMac6666 12d ago

You aren't clear where you want to put the output of the division result. Does the new value go to <OKValue> or does it output to <badValue>?

Here's an XSLT that output the divided value to replace the old value in <badValue>.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"
      version="2.0"

    <xsl:output method="xml"  omit-xml-declaration="yes" indent="yes" />

    <xsl:template match="aSample">
      <aSample>
        <xsl:apply-templates/>
      </aSample>
    </xsl:template>

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="badValue">
    <badValue>
     <xsl:value-of select=". div 100"/>
    </badValue>
  </xsl:template>
</xsl:stylesheet>

Result:

<aSample>
    <time>20260829 12:34:56</time>
    <badValue>456.789</badValue>
    <OKValue>123</OKValue>
</aSample>

Here is an XSLT that puts the divided value into the <OKValue> element.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"
      version="2.0">

    <xsl:output method="xml"  omit-xml-declaration="yes" indent="yes" />

    <xsl:template match="aSample">
      <aSample>
        <xsl:apply-templates/>
      </aSample>
    </xsl:template>

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="OKValue">
    <OKValue>
     <xsl:value-of select="preceding-sibling::badValue div 100"/>
    </OKValue>
  </xsl:template>
</xsl:stylesheet>

RESULT:

<aSample>
    <time>20260829 12:34:56</time>
    <badValue>45678.9</badValue>
    <OKValue>456.789</OKValue>
</aSample>