How to sum distinct values in RTF (BI Publisher) - reporting

Transaction ID |Amount| Date
1 |200 | 20/04/2020
1 |200 | 21/04/2020
2 |300 | 22/04/2020
3 |400 | 23/04/2020
1 |200 | 21/04/2020
4 |200 | 17/04/2020
2 |300 | 22/04/2020
How to I sum the amount where transaction ID is unique? Need this for both a subtotal and a grand total on a RTF file BI Publisher. Tried this but failed but returns empty value.

Here is a method that uses the for-each-group function, and a running total variable.
<?for-each:record_set?>
<?xdoxslt:set_variable($_XDOCTX,'running_amount',0)?>
<?for-each-group:record;transaction_id?>
<?xdoxslt:set_variable($_XDOCTX,'running_amount', xdoxslt:get_variable($_XDOCTX,'running_amount')+amount)?>
<?end for each group?>
<?end for each?>
Non-Unique Sum:<?sum(record/amount)?>
Unique Sum<?xdoxslt:get_variable($_XDOCTX,'running_amount')?>
<?end for each?>
Sample Data
<record_set>
<record>
<transaction_id>1</transaction_id>
<amount>200</amount>
</record>
<record>
<transaction_id>1</transaction_id>
<amount>200</amount>
</record>
<record>
<transaction_id>2</transaction_id>
<amount>300</amount>
</record>
<record>
<transaction_id>3</transaction_id>
<amount>400</amount>
</record>
<record>
<transaction_id>1</transaction_id>
<amount>200</amount>
</record>
<record>
<transaction_id>4</transaction_id>
<amount>200</amount>
</record>
<record>
<transaction_id>2</transaction_id>
<amount>300</amount>
</record>
</record_set>

Related

Convert Number date to a String Date Field in Fluentd For Storing into Elasticsearch

I'm new to fluentd and using it to ingest data to elasticsearch. I have a field called request_time which has value : 110820120501 as a number of the format [ddmmyyHHMMSS]. How can I convert this as a date field.
This is what I've written but it doesn't work. Any help is appreciated.
Example request_time value : 100820015642
<filter>
#type record_transformer
enable_ruby true
<record>
request_time ${ require 'date'; DateTime.strptime('request_time', '%d%m%y%H%M%S')}
</record>
</filter>
I have tried the below as well:
<filter>
#type record_transformer
enable_ruby true
<record>
time ${require 'date'; DateTime.parse('request_time').strftime('%d%m%y%H%M%S')}
</record>
</filter>
How can I store request_time as a date field coverted to a value as eg. "request_time": "2020-08-11T11:24:23.000+0100" ?
Pleas try the below snippet. I have given milli second precision, but feel free to cut it down to your need.
<filter>
#type record_transformer
enable_ruby true
<record>
date ${Time.at(record['request_time'].to_i/1000, record['request_time'].to_i%1000*1000).utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ')}
</record>
</filter>

XSLT first occurence of element based on duplicate value

The given XML:
<records>
<record>
<country>Germany</country>
<value>123</value>
</record>
<record>
<country>Germany</country>
<value>62</value>
</record>
<record>
<country>Germany</country>
<value>033</value>
</record>
<record>
<country>Armenia</country>
<value>444</value>
</record>
<record>
<country>Armenia</country>
<value>212</value>
</record>
<record>
<country>Armenia</country>
<value>864</value>
</record>
</records>
How do I get an output, which respectively chooses every first occurrence of <record> by the value of <country>.
So the desired output should look like:
<records>
<record>
<country>Germany</country>
<value>123</value>
</record>
<record>
<country>Armenia</country>
<value>444</value>
</record>
</records>
UPDATE: Solved my Problem with given XSL
<xsl:key name="country" match="record" use="value" />
<xsl:template match="records">
<xsl:apply-templates select="record[1]" />
</xsl:template>
<xsl:template match="record">
<xsl:for-each select="key('country', value)">
<country><xsl:value-of select="country"/></country>
<value><xsl:value-of select="value"/></value>
</xsl:for-each>
</xsl:template>

Xpath function to loop through repeating nodes

What XPath function works to loop through repeating XML nodes.
This is my Source XML:
<?xml version="1.0" encoding="UTF-8"?>
<Record>
<Type>V</Type>
<Address>
<Qual>A</Qual>
<ID>A1</ID>
</Address>
<Address>
<Qual>A</Qual>
<ID>B2</ID>
</Address>
<Address>
<Qual>C</Qual>
<ID>C2</ID>
</Address>
<Category>
<EL>PO</EL>
</Category>
<Category>
<EL>DP</EL>
</Category>
</Record>
I don't want to process the data if Qualf=A & ID = B2, Category =DP & Type =V
My Xpath does not work due to repeating nodes..
(concat(Xpath./Type,Xpath./Record/Address/Qual,Xpath./Record/Address/ID,Xpath./Record/Category/EL) != "VAB2DP"
so I tried
choose((concat(Xpath./Type,Xpath./Record/Address/Qual,Xpath./Record/Address/ID,Xpath./Record/Category/EL) != "VAB2DP"),'true','false'
It still does not work.

XPath results based on two nodes

I have XML that has a lot of duplicated values. I'd like to select all the rows with a specific section ("sec") and section tag ("sec_tag"), but I can't seem to get the XPath correct.
Here's a small snippet of the XML:
<root>
<record>
<sec>5</sec>
<sec_tag>919</sec_tag>
<nested_tag>
<info>Info</info>
<types>
<type>1</type>
<type>2</type>
<type>3</type>
</types>
</nested_tag>
<flags>00000000</flags>
</record>
<record>
<sec>5</sec>
<sec_tag>930</sec_tag>
<nested_tag>
<info>Info</info>
<types>
<type>1</type>
<type>2</type>
<type>3</type>
</types>
</nested_tag>
<flags>00000000</flags>
</record>
<record>
<sec>7</sec>
<sec_tag>919</sec_tag>
<nested_tag>
<info>Info</info>
<types>
<type>1</type>
<type>2</type>
<type>3</type>
</types>
</nested_tag>
<flags>00000000</flags>
</record>
</root>
I want the node that has <sec>5</sec> and <sec_tag>919</sec_tag>.
I tried something like this:
//sec[text(), "5"] and //sec_tag[text(), "919"]
Obviously that's not the correct syntax there, I just need to find the correct XPath expression.
You can use the following XPath expression to return record elements having child sec equals 5 and sec_tag equals 919 :
//record[sec = 5 and sec_tag = 919]

Replacing xml tags in BASH

I have a large collection of xml documents with a wide array of different tags in them. I need to change all tags of the form <foo> and turn them into tags of the form <field name="foo"> in a way that will also ignore the attributes of a given tag. That is, a tag of the form <foo id="bar"> should also be changed to the tag <field name="foo">.
In order for this transformation to work, I also need to distinguish between <foo> and </foo>, as </foo> must go to </field>.
I have played around with sed in a bash script, but to no avail.
Although sed is not ideal for this task (see comments; further reading: regular, context-free grammar and xml), it can be pressed into service. Try this one-liner:
sed -e 's/<\([^>\/\ ]*\)[^>]*>/<field name=\"\1\">/g' -e 's/<field name=\"\">/<\/field>/g' file
First it will replace all end tags with </field>, then replace every open tag first words with <field name="firstStoredWord">
This solution prints everything on the standard output. If you want to replace it in file directly when processing, try
sed -i -e 's/<\([^>\/\ ]*\)[^>]*>/<field name=\"\1\">/g' -e 's/<field name=\"\">/<\/field>/g' file
That makes from
<html>
<person>
but <person name="bob"> and <person name="tom"> would both become
</person>
this
<field name="html">
<field name="person">
but <field name="person"> and <field name="person"> would both become
</field>
Sed is the wrong tool for the job - a simple XSL Transform can do this much more reliably:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo">
<field name="foo">
<xsl:apply-templates/>
</field>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that unlike sed, it can handle short empty elements, newlines within tags (e.g. as produced by some tools), and just about anything that's well-formed XML. Here's my test file:
<?xml version="1.0"?>
<doc>
<section>
<foo>Plain foo, simple content</foo>
</section>
<foo attr="0">Foo with attr, with content
<bar/>
<foo attr="shorttag"/>
</foo>
<foo
attr="1"
>multiline</foo
>
<![CDATA[We mustn't transform <foo> in here!]]>
</doc>
which is transformed by the above (using xsltproc 16970175.xslt 16970175.xml) to:
<?xml version="1.0"?>
<doc>
<section>
<field name="foo">Plain foo, simple content</field>
</section>
<field name="foo">Foo with attr, with content
<bar/>
<field name="foo"/>
</field>
<field name="foo">multiline</field>
We mustn't transform <foo> in here!
</doc>

Resources