1

I have a table with a column containing data like this: array of n json elements

[
  {"ref":"3455","desc":"My Product 1","price":"4","quant":"90"},
  {"ref":"3455","desc":"My Product 2","price":"5","quant":"80"}
]

I need to parse/iterate each of JSON element. In the example I have 2. The result will be a custom string (actually XML string).

XML result expected:

<items>
  <item>
    <ref>3455</ref>
    <desc>My Product 1</desc>
    <price>4</price>
    <quant>90</quant>
  </item>
  <item>
    <ref>3455</ref>
    <desc>My Product 2</desc>
    <price>5</price>
    <quant>80</quant>
  </item>
</items>

What is the best way to achieve this?

thank you!

Dmitry
  • 6,716
  • 14
  • 37
  • 39
user3643038
  • 143
  • 12
  • Please **[EDIT]** your question and add the expected output based on your sample data. [**Formatted text**](http://stackoverflow.com/help/formatting) please, [**no screen shots**](http://meta.stackoverflow.com/questions/285551/why-may-i-not-upload-images-of-code-on-so-when-asking-a-question/285557#285557). –  Nov 08 '17 at 12:31
  • There is no dedicated tools in Postgres to convert json to xml. I think such a conversion may be really easy in a client app. Search for a solution in your favorite language, e.g. [Convert JSON to XML in Python](https://stackoverflow.com/q/8988775/1995738) – klin Nov 08 '17 at 14:15

1 Answers1

1

In my solution I presume that objects in your JSON array have the same structure. So we create an SQL type for this objects:

DROP TYPE IF EXISTS item_type;
CREATE TYPE item_type 
  AS ("ref" int, "desc" VARCHAR(500), price FLOAT, quant INTEGER);
--ref and desc are SQL key words 
--so you need to specify that they actually are column names

The demo table looks like this:

CREATE TABLE items
(
    id SERIAL NOT NULL
        CONSTRAINT items_pkey
            PRIMARY KEY,
    content jsonb DEFAULT '[]'::jsonb NOT NULL
);

The query:

SELECT xmlelement(name items, (--create the root element "items"
  SELECT xmlagg(--aggregate "item" elements
      xmlelement(NAME item, --create "item" elements
                 xmlforest(t."ref", t."desc", t.price, t.quant)--create "item" element content
      )
  )
  FROM
    (
      SELECT (jsonb_populate_recordset(NULL :: item_type, items.content)).*--create records ot of JSON array
      FROM items
      WHERE items.id = 1 --you can remove where if you want all rows
    ) AS t
))

Explanation:
From inside out; (1) create SQL records of the type we created earlier (the item_type) out of the JSON array using jsonb_populate_recordset, (2) create the content of the <item> nodes using xmlforest, (3) create the <item> element itself using xmlelement, (4) aggregate <item> elements using xmlagg, create the root element <items> using xmlelement.

SQLFiddle - it runs but it looks like SQLFiddle have problems outputting XML results so I cast the result to TEXT.

Dmitry
  • 6,716
  • 14
  • 37
  • 39