Join us for an expert-led overview of the tools and concepts you'll need to pass exam PL-300. The first session starts on June 11th. See you there!
Get registeredPower BI is turning 10! Let’s celebrate together with dataviz contests, interactive sessions, and giveaways. Register now.
Hi!
I have developed a customer connector for a web service and would like to improve error handling. For that reason I am now handling the different failure HTTP statuses that could occur. I know that the service responds with a simple HTML page in case of an error. I would like to extract the title of that page and present it to the user (e.g. authentication issues).
The problem I have is that the parsing of the HTML response is not possible. I get the error "The name 'Html.Table' does not exist in the current context":
Here is my code:
shared TestSession = (server) =>
let
AuthResp = Web.Contents(server,
[RelativePath="/qcbin/authentication-point/authenticate",
ManualStatusHandling = {400,401,403,404,429,500,502,503}]
),
responseCode = Value.Metadata(AuthResp)[Response.Status],
ErrorMessage = Html.Table(AuthResp, {{"Message", "title"}})
in
if responseCode = 200 then "All good" else ErrorMessage;
Anyone who knows why the Function Html.Table is not available in this context?
EDIT: I can add that there is no way to build logic around the HTTP status code. The service has some weird implementation which returns additional information in the status code field:
HTTP/1.1 401 Failed to authenticate user "xxx", verify your user name and password.
Date: Wed, 30 Sep 2020 07:22:22 GMT
The value of 'Response.Status' is empty and I guess it's because of that additional information in the status field that prevents the SDK to extract the correct status value.
Thanks and best regards, Denis
Solved! Go to Solution.
I looked into the power bi code (ILSpy is great 🙂 and figured out that Html.Tables is a built in function, not a Power Query function exactly. It uses AngleSharp.net under the covers to do the css selectors ect. basically the heavy lifting of the html manipulation / searching.
The following was useful for me, and could be extended to do all the html.table function - it's pretty hacky but got the job done 🙂
MyHtml.Table = (html as text, selectorRecord as any, optional three as any) as any =>
let
columnHeader = selectorRecord{0}{0},
selectorList = List.Transform(Text.Split(selectorRecord{0}{1}, ">"), each Text.Trim(_)),
eachSelect = List.Accumulate(selectorList, html, (htmlstring, c) =>
let
selector = if Text.Contains(c, ":") then Text.BeforeDelimiter(c, ":") else c,
hasColonSelector = Text.Contains(c, ":"),
startTag = "<" & selector,
endTag = "</" & selector
in
if (List.Last(selectorList) = c) then
List.Transform(List.RemoveFirstN(Text.Split(htmlstring, startTag), 1), each Text.BeforeDelimiter(Text.AfterDelimiter(_, ">"), endTag))
else
if Text.Contains(htmlstring, startTag) then
Text.AfterDelimiter(
if hasColonSelector then
if Text.Contains(c, ":nth-of-type") then
if Text.Contains(c, ":not") then
let
// hacky
nthOfTypeNumber = try Number.FromText(Text.BetweenDelimiters(Text.Replace(c, ":not(", ""), "(", ")")) otherwise 0,
notValue = Text.BetweenDelimiters(htmlstring, startTag, endTag, if Number.IsNaN(nthOfTypeNumber) then 0 else nthOfTypeNumber - 1),
thisValue = Text.Combine( Text.Split(Text.Replace(htmlstring, notValue, ""), startTag) )
in
startTag & thisValue
else
let
nthOfTypeNumber = try Number.FromText(Text.BetweenDelimiters(c, "(", ")")) otherwise 0,
notValue = Text.BetweenDelimiters(htmlstring, startTag, endTag, if Number.IsNaN(nthOfTypeNumber) then 0 else nthOfTypeNumber - 1)
in
startTag & notValue
else
Text.BetweenDelimiters(htmlstring, startTag, endTag)
else
Text.AfterDelimiter(Text.BeforeDelimiter(htmlstring, endTag), startTag)
, ">")
else
htmlstring
)
in
#table({columnHeader}, List.Transform(eachSelect, each
let
htmlReplacements = {
{ "<br />", Character.FromNumber(13) },
{ " ", " " }
},
value = List.Accumulate(htmlReplacements, _, (s, c) => Text.Trim(Text.Replace(s, c{0}, c{1})))
in
{ value }
));
Did you find out wht 'Html.Table' does not exist?
Hi!
No, I did not find out why and could go on without that code.
BR
I looked into the power bi code (ILSpy is great 🙂 and figured out that Html.Tables is a built in function, not a Power Query function exactly. It uses AngleSharp.net under the covers to do the css selectors ect. basically the heavy lifting of the html manipulation / searching.
The following was useful for me, and could be extended to do all the html.table function - it's pretty hacky but got the job done 🙂
MyHtml.Table = (html as text, selectorRecord as any, optional three as any) as any =>
let
columnHeader = selectorRecord{0}{0},
selectorList = List.Transform(Text.Split(selectorRecord{0}{1}, ">"), each Text.Trim(_)),
eachSelect = List.Accumulate(selectorList, html, (htmlstring, c) =>
let
selector = if Text.Contains(c, ":") then Text.BeforeDelimiter(c, ":") else c,
hasColonSelector = Text.Contains(c, ":"),
startTag = "<" & selector,
endTag = "</" & selector
in
if (List.Last(selectorList) = c) then
List.Transform(List.RemoveFirstN(Text.Split(htmlstring, startTag), 1), each Text.BeforeDelimiter(Text.AfterDelimiter(_, ">"), endTag))
else
if Text.Contains(htmlstring, startTag) then
Text.AfterDelimiter(
if hasColonSelector then
if Text.Contains(c, ":nth-of-type") then
if Text.Contains(c, ":not") then
let
// hacky
nthOfTypeNumber = try Number.FromText(Text.BetweenDelimiters(Text.Replace(c, ":not(", ""), "(", ")")) otherwise 0,
notValue = Text.BetweenDelimiters(htmlstring, startTag, endTag, if Number.IsNaN(nthOfTypeNumber) then 0 else nthOfTypeNumber - 1),
thisValue = Text.Combine( Text.Split(Text.Replace(htmlstring, notValue, ""), startTag) )
in
startTag & thisValue
else
let
nthOfTypeNumber = try Number.FromText(Text.BetweenDelimiters(c, "(", ")")) otherwise 0,
notValue = Text.BetweenDelimiters(htmlstring, startTag, endTag, if Number.IsNaN(nthOfTypeNumber) then 0 else nthOfTypeNumber - 1)
in
startTag & notValue
else
Text.BetweenDelimiters(htmlstring, startTag, endTag)
else
Text.AfterDelimiter(Text.BeforeDelimiter(htmlstring, endTag), startTag)
, ">")
else
htmlstring
)
in
#table({columnHeader}, List.Transform(eachSelect, each
let
htmlReplacements = {
{ "<br />", Character.FromNumber(13) },
{ " ", " " }
},
value = List.Accumulate(htmlReplacements, _, (s, c) => Text.Trim(Text.Replace(s, c{0}, c{1})))
in
{ value }
));
Awesome! Thanks for the insights! 😀
This is your chance to engage directly with the engineering team behind Fabric and Power BI. Share your experiences and shape the future.
Check out the June 2025 Power BI update to learn about new features.
User | Count |
---|---|
3 | |
3 | |
3 | |
2 | |
2 |