0

I have a weird case that I need help with: I have a XML document that I wish to take to JSON using DW, which is easy, but I also wish to take some attributes and paste some parts of the original XML content as their values, to avoid interface issues down my work pipeline.

More specifically, I wish to take all of the elements of a specific tag that conform a list of that type of elements and return the same list in XML as a string. An example scenario would look like this:

Input

<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>

  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
</bookstore>

Output

{"book": "<book category=\"cooking\"><title lang=\"en\">EverydayItalian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book><book category=\"children\"><title lang=\"en\">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book>"}

This is how far I arrived to a close solution. Report_Data and Report_Entry are just wrapping the information in this case. I expect to receive various Report_Entry elements so this is still a draft.

%dw 2.0
import * from dw::core::Types
import mergeWith from dw::core::Objects
input payload xml
output application/json

var literalKeys = (namesOf(payload.Report_Data.Report_Entry) distinctBy ((item, index) -> item)) filter ((item) -> not isObjectType(typeOf(payload.Report_Data.Report_Entry[item])))

var objectKeys = (namesOf(payload.Report_Data.Report_Entry) distinctBy ((item, index) -> item)) filter ((item) -> isObjectType(typeOf(payload.Report_Data.Report_Entry[item])))

var allObjects = payload.Report_Data.Report_Entry filterObject((value, key, index) -> objectKeys reduce ((item, accumulator = false) -> (key ~= item) or accumulator))

var justTheScalars = payload.Report_Data.Report_Entry filterObject((value, key, index) -> not (objectKeys reduce ((item, accumulator = false) -> (key ~= item) or accumulator)))

var groupedAllObjects = allObjects groupBy (item, index) -> index

---

justTheScalars mergeWith (groupedAllObjects)

I got to a the point were I can

  1. Determine which keys correspond to objects and which to literals
  2. Divide all objects and all scalars inside from my input
  3. Group the objects together according to their class and returned the merge object

But I still miss the part where I can somehow take the input and paste is as a string or transform it somehow into a string to avoid information loss as much as I can.

Please take into account this case is a particular one for the usage of DW, as I have no information about what will come inside the different Report_Entrys, that's why I'm working with a combination of functions to obtain dynamically the keys and values.

rpazos98
  • 3
  • 1

2 Answers2

0

It is simpler just to let DataWeave know that you want to write each book as an XML string.

%dw 2.0
output application/json
---
payload.bookstore  mapObject {
    book: write({($$): $}, "application/xml",{writeDeclaration:false})
}

Output:

{
  "book": "<book category=\"cooking\">\n  <title lang=\"en\">Everyday Italian</title>\n  <author>Giada De Laurentiis</author>\n  <year>2005</year>\n  <price>30.00</price>\n</book>",
  "book": "<book category=\"children\">\n  <title lang=\"en\">Harry Potter</title>\n  <author>J K. Rowling</author>\n  <year>2005</year>\n  <price>29.99</price>\n</book>"
}

I updated the solution to emit attributes and avoid XML declaration.

aled
  • 21,330
  • 3
  • 27
  • 34
  • haha. I think we posted almost the exact same answer at essentially the same time – Michael Jones Mar 30 '21 at 14:56
  • Thank you! I will try to use this. Thank you @Michael too! – rpazos98 Mar 30 '21 at 15:03
  • FYI this output isn't valid JSON. You need an array of objects with the book key, or an array of strings. If you don't really care if its valid JSON thats moot of course. – Michael Jones Mar 30 '21 at 15:09
  • @MichaelJones jaja it took me a minute more to confirm the syntax for output properties. Do you mean the example output in the question is not valid XML because it has multiple roots? I think DataWeave is writing valid JSON in our answers. – aled Mar 31 '21 at 01:40
  • No I mean the output JSON with two book keys isn’t valid. It’s true dataweave will accept it but that’s because of the XML support. Put your output in a JSON validator. – Michael Jones Apr 01 '21 at 12:01
  • I understand duplicate keys are not invalid but not recommend: https://stackoverflow.com/a/23195243/721855. Should be easy to change, depending on what is the expected output. Not a DataWeave issue then. – aled Apr 01 '21 at 13:04
0

Sorry - I'm a bit confused. You're just trying to serialize the input into strings?

Input:

<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>

  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
</bookstore>

dataweave:

%dw 2.0
output application/json
---
payload.bookstore.*book map {
    "book": write({ book: $ }, 'application/xml', {writeDeclaration: false, indent: false})
}

Output:

[
  {
    "book": "<book><title lang=\"en\">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book>"
  },
  {
    "book": "<book><title lang=\"en\">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book>"
  }
]

Edit:

And if you just wanted an array of strings:

%dw 2.0
output application/json
---
payload.bookstore.*book map write({ book: $ }, 'application/xml', {writeDeclaration: false, indent: false})

output:

[
  "<book><title lang=\"en\">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book>",
  "<book><title lang=\"en\">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book>"
]
Michael Jones
  • 1,900
  • 5
  • 12