Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
jmillsjmills
Helper III
Helper III

Parsing JSON String within Custom Function

Hi,

 

I'm trying to parse a JSON string that currently sits in a column (shown in the screenshot). I've tried either with the record just as a text string ([Column1Copy]), or also with the JSON already parsed ([Column1])..

 

rightmove.PNG

 

My custom function in M code is as follows, but I always get errors. Hopefully you can see what I'm trying to do. I should be able to invoke this custom function with [Column1] as the JSON input/variable. This JSON string should get sent into the function, which then parses it/manipulates it accordingly.  

 

I don't care whether I parse the JSON string before the function (i.e. using [Column1]) or within the function (i.e. using the unparsed data in [Column1 - Copy]), I just want it to work!! I need to be able to send the JSON string into my custom function by invoking it via the column. Does that make sense? I've also included below an example of a JSON string, in case it's useful.

 

Thanks!!

 

let
#"Table" = (symbol) as table =>
let
#"Parsed JSON" = Record.ToTable(Json.Document(symbol)),
#"Expanded Column2" = Table.ExpandRecordColumn(#"Parsed JSON", "Column1", {"language", "textAngle", "orientation", "regions"}, {"language", "textAngle", "orientation", "regions"}),
regions = #"Expanded Column2"{0}[regions],
#"Converted to Table" = Table.FromList(regions, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
in
#"Converted to Table"
in
#"Table"

 

 

 

JSON:

 

{"language":"en","textangle":0.0,"orientation":"up","regions":[{"boundingbox":"6,4,848,1007","lines":[{"boundingbox":"350,4,160,19","words":[{"boundingbox":"350,4,89,19","text":"ground"},{"boundingbox":"449,4,61,19","text":"floor"}]},{"boundingbox":"289,32,281,15","words":[{"boundingbox":"289,32,52,15","text":"approx."},{"boundingbox":"352,32,30,12","text":"51.0"},{"boundingbox":"386,35,21,12","text":"sq."},{"boundingbox":"413,33,47,11","text":"metres"},{"boundingbox":"465,32,44,15","text":"(548.9"},{"boundingbox":"514,35,20,12","text":"sq."},{"boundingbox":"539,32,31,15","text":"feet)"}]},{"boundingbox":"574,227,80,14","words":[{"boundingbox":"574,227,80,14","text":"bedroom"}]},{"boundingbox":"176,296,66,18","words":[{"boundingbox":"176,296,66,18","text":"lounge"}]},{"boundingbox":"520,465,69,18","words":[{"boundingbox":"520,465,69,18","text":"hallway"}]},{"boundingbox":"443,645,86,15","words":[{"boundingbox":"443,645,86,15","text":"bathroom"}]},{"boundingbox":"149,656,67,15","words":[{"boundingbox":"149,656,67,15","text":"kitchen"}]},{"boundingbox":"748,764,78,15","words":[{"boundingbox":"748,764,78,15","text":"entrance"}]},{"boundingbox":"782,786,32,18","words":[{"boundingbox":"782,786,32,18","text":"bby"}]},{"boundingbox":"188,943,483,20","words":[{"boundingbox":"188,943,46,16","text":"total"},{"boundingbox":"242,946,46,13","text":"area:"},{"boundingbox":"296,946,68,17","text":"approx."},{"boundingbox":"378,943,40,16","text":"51.0"},{"boundingbox":"425,946,27,17","text":"sq."},{"boundingbox":"460,944,62,15","text":"metres"},{"boundingbox":"530,943,58,20","text":"(548.9"},{"boundingbox":"595,946,26,17","text":"sq."},{"boundingbox":"629,943,42,20","text":"feet)"}]},{"boundingbox":"6,975,848,17","words":[{"boundingbox":"6,975,32,13","text":"this"},{"boundingbox":"44,975,31,17","text":"plan"},{"boundingbox":"82,975,12,13","text":"is"},{"boundingbox":"99,975,21,13","text":"for"},{"boundingbox":"125,975,85,13","text":"information"},{"boundingbox":"217,978,69,14","text":"purposes"},{"boundingbox":"292,975,31,17","text":"only"},{"boundingbox":"329,975,27,13","text":"and"},{"boundingbox":"363,975,11,13","text":"is"},{"boundingbox":"381,976,23,12","text":"not"},{"boundingbox":"409,975,76,13","text":"warranted"},{"boundingbox":"491,978,17,10","text":"as"},{"boundingbox":"514,978,18,10","text":"an"},{"boundingbox":"538,975,62,13","text":"identical"},{"boundingbox":"607,975,46,17","text":"image"},{"boundingbox":"659,976,14,12","text":"to"},{"boundingbox":"678,975,23,13","text":"the"},{"boundingbox":"707,975,63,17","text":"property"},{"boundingbox":"775,975,79,13","text":"concerned"}]},{"boundingbox":"320,995,221,16","words":[{"boundingbox":"320,995,32,13","text":"plan"},{"boundingbox":"359,995,69,16","text":"produced"},{"boundingbox":"435,995,40,16","text":"using"},{"boundingbox":"482,995,59,16","text":"planup_"}]}]}]}

 

1 ACCEPTED SOLUTION
PhilipTreacy
Super User
Super User

Hi @jmillsjmills 

 

Your ManipulationQuery is expecting the JSON as a Record, but it's receiving text.  So try wrapping the JSON text in Json.Document() before passing it to the function

ManipulationQuery(Json.Document([JsonText]))

 

Regards

 

Phil



Did I answer your question? Then please mark my post as the solution.
If I helped you, click on the Thumbs Up to give Kudos.


Blog :: YouTube Channel :: Connect on Linkedin


Proud to be a Super User!


View solution in original post

6 REPLIES 6
PhilipTreacy
Super User
Super User

Hi @jmillsjmills 

 

Your ManipulationQuery is expecting the JSON as a Record, but it's receiving text.  So try wrapping the JSON text in Json.Document() before passing it to the function

ManipulationQuery(Json.Document([JsonText]))

 

Regards

 

Phil



Did I answer your question? Then please mark my post as the solution.
If I helped you, click on the Thumbs Up to give Kudos.


Blog :: YouTube Channel :: Connect on Linkedin


Proud to be a Super User!


This is perfect Philip! Thanks so much. Exactly what I needed

jmillsjmills
Helper III
Helper III

Thanks very much but when I run this function and invoke it with the ([Column1]) that contains the already-parsed data, I'm getting an error this error:

 

rightmoveerror3.PNGrightmoveerror2.PNG

 

Similarly when invoke the function using the the [Column1Copy] (containing the raw JSON as a text string), I get this error:

rightmoveerror1.PNGrightmoveerror4.PNG

Hi @jmillsjmills 

 

You don't really need a custom function for this.  It actually complicates things more than needed because you have to parse out the JSON record, then return columns that have to be added back to the original table from which you called the function.

 

You'd be better off just doing the expansion/parsing in the source table:

 

Before

json1.png

 

After

json2.png

 

Regards

 

Phil



Did I answer your question? Then please mark my post as the solution.
If I helped you, click on the Thumbs Up to give Kudos.


Blog :: YouTube Channel :: Connect on Linkedin


Proud to be a Super User!


Hi again Philip,

 

Thanks so much for your help with this - I really appreciate it! Unfortunately I do have to do it separately within a function as the manipulation requires some expanding onto new rows, and grouping etc, within that particular JSON. I need to be able to manipulate the JSON data from each individual row in isolation. If all the rows of JSON data are expanded in the same aggregate table, some of the filtering (for example) will then go wrong.

 

As per your previous message, I'm providing the file along with a json file you can reference. You'll see the file you sent me now contains four more items:

  • Table (contains the JSON data in rows as a text string)
  • generic (JSON file attached, to how the manipulation works directly on a normal JSON file)
  • Manipulation - the query set directly , but that I would like to make into a custom function that can be invoked on the column called "JsonText" in Table
  • ManipulationQuery - my attempt at turning the above query into a function, such that there is a variable that can be invoked (and that should be invokable with [JsonText] in Table

 

Link to Power BI File 

Link to JSON for Manipulation Query 

 

Sorry if that isn't too clear, but hopefully it's a lot easier to have a set file to work with! 

 

rightmove5.PNG 

PhilipTreacy
Super User
Super User

Hi @jmillsjmills 

 

Download example PBIX file

 

Try this function

 

(JSON as table) =>
    let
    #"Expanded regions" = Table.ExpandListColumn(JSON, "regions"),
    #"Expanded regions1" = Table.ExpandRecordColumn(#"Expanded regions", "regions", {"boundingbox", "lines"}, {"regions.boundingbox", "regions.lines"}),
    #"Expanded regions.lines" = Table.ExpandListColumn(#"Expanded regions1", "regions.lines"),
    #"Expanded regions.lines1" = Table.ExpandRecordColumn(#"Expanded regions.lines", "regions.lines", {"boundingbox", "words"}, {"regions.lines.boundingbox", "regions.lines.words"}),
    #"Changed Type" = Table.TransformColumnTypes(#"Expanded regions.lines1",{{"language", type text}, {"textangle", Int64.Type}, {"orientation", type text}, {"regions.boundingbox", Int64.Type}, {"regions.lines.boundingbox", Int64.Type}, {"regions.lines.words", type any}}),
    #"Expanded regions.lines.words" = Table.ExpandListColumn(#"Changed Type", "regions.lines.words"),
    #"Expanded regions.lines.words1" = Table.ExpandRecordColumn(#"Expanded regions.lines.words", "regions.lines.words", {"boundingbox", "text"}, {"boundingbox", "text"})
in
    #"Expanded regions.lines.words1"

 

 

In my example file you can see that I'm calling this function to create a Custom Column which contains the table output from the function.  Expanding that table gives you the parsed JSON.

parsed-json.png

 

Regards

 

Phil



Did I answer your question? Then please mark my post as the solution.
If I helped you, click on the Thumbs Up to give Kudos.


Blog :: YouTube Channel :: Connect on Linkedin


Proud to be a Super User!


Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.

Top Solution Authors
Top Kudoed Authors