Xidel: Parse attributes into new object

554 views Asked by At

Given is a verbose GC log from any Java virtual machine (could be any xml, so not tagging with java):

<?xml version="1.0" ?>

<verbosegc version="versioninformation">

<af type="nursery" id="49383" timestamp="Jan 01 01:34:54 2015" intervalms="33.821">
  <tenured freebytes="769243504" totalbytes="1610416128" percent="47" >
    <soa freebytes="198858272" totalbytes="805208064" percent="24" />
    <loa freebytes="570385232" totalbytes="805208064" percent="70" />
  </tenured>
  <gc></gc>
  <tenured freebytes="768800232" totalbytes="1610416128" percent="47" >
    <soa freebytes="198415" totalbytes="805208064" percent="24" />
    <loa freebytes="570385232" totalbytes="805208064" percent="70" />
  </tenured>
</af>

<af type="nursery" id="49384" timestamp="Jan 01 01:35:54 2015" intervalms="40.877">
  <tenured freebytes="768800232" totalbytes="1610416128" percent="47" >
    <soa freebytes="198415" totalbytes="805208064" percent="24" />
    <loa freebytes="570385232" totalbytes="805208064" percent="70" />
  </tenured>
  <gc></gc>
  <tenured freebytes="768320928" totalbytes="1610416128" percent="47" >
    <soa freebytes="197935696" totalbytes="805208064" percent="24" />
    <loa freebytes="570385232" totalbytes="805208064" percent="70" />
  </tenured>
</af>

So, I'd like to create a new object, which gets repeated for each garbage collection cycle with the timestamp and the used bytes (total minus free). The calculation works just fine, but the output does not. This is what I excpect to get:

[
  {
    "timestamp": "Jan 01 01:34:54 2015",
    "used": 8.41172624E8
  },
  {
    "timestamp": "Jan 01 01:35:54 2015",
    "used": 8.41615896E8
  },
]

I tried this command line, which sadly creates a null timestamp and a long list of heap information:

xidel --input-format=xml   -e "//af/tenured[1]/(heap:={used:=(@totalbytes - @freebytes):timestamp:=@timestamp})" gc.log --output-format=json-wrapped

The output looks like this:

[
  {
    "timestamp": [null],
    "used": [8.41172624E8, 8.41615896E8]
  }
]

Obviously not what I excpected.

2

There are 2 answers

1
BeniBela On BEST ANSWER

You can actually write the entire JSON structure in the extract expression and do not need output-format:

xidel --input-format=xml   -e "[ //af/tenured[1]/{'used':(@totalbytes - @freebytes),'timestamp':../@timestamp} ]" gc.log 
0
Benjamin Marwell On

The correct idea was not to assign the object to a variable (heap:={}) and to use json notation directly in xpath. And third, timestamp is a level above tenured, so I placed ../ in front.

So this one works:

xidel --input-format=xml   -e "//af/tenured[1]/('used':(@totalbytes - @freebytes),'timestamp':../@timestamp)" gc.log --output-format=json-wrapped

Output:

[
    [
        {
            "timestamp": "Jan 01 01:34:54 2015",
            "used": 841172624.0
        },
        {
            "timestamp": "Jan 01 01:35:54 2015",
            "used": 841615896.0
        },
    ]
]

It gives an extra array, but I can live with that. At least it's a stable output and parsable.