Tiesitkö että flow’ssa voi tehdä XML-muotoiseen tekstiin kyselyjä XPath:illa? Ja koska JSON-sisällön voi muuntaa XML-muotoon, voi XPathia hyödyntää käytännössä myös JSON-sisältöjen kanssa.
Miksi ihmeessä haluaisin tehdä mitään millään XPathilla?
Esimerkiksi jos
- Haluat poimia JSON/XML sanomasta tietoa tavalla, joka ei ole flow’ssa muuten mahdollista
- Haluat poimia JSON/XML sanomasta tietoa tavalla, jota ei voi tehdä flow’ssa ilman Apply to each -silmukkaa (=hidasta)
- Haluat parantaa flow’n suorituskykyä ja sen on mahdollista XPathilla (Paul Muranan blogista löytyy hyvä esimerkki tällaisesta tilanteesta).
Tutustutaan tähän ihmeelliseen XPathiin esimerkin avulla. Ratkaistaan sama ongelma flow’lla ensin kahdella perinteisellä tavalla ja lopuksi XPathia hyödyntäen.
Esimerkki – Tiimin jäsenet
Haemme flow’lla järjestelmästä X organisaation tiimihierarkian. Se palautuu hieman erikoisessa muodossa, jossa on tiimin jäsen (teammember) ja tiimikymppi (teamlead) pareja.
[
{
"teamattribute": {
"teamlead": "Otto@forwardforever.com",
"teammember": "Timo@forwardforever.com"
}
},
{
"teamattribute": {
"teamlead": "Otto@forwardforever.com",
"teammember": "Ilkka@forwardforever.com"
}
},
{
"teamattribute": {
"teamlead": "Heidi@forwardforever.com",
"teammember": "Jouko@forwardforever.com"
}
},
{
"teamattribute": {
"teamlead": "Heidi@forwardforever.com",
"teammember": "Lasse@forwardforever.com"
}
}
]
Haluamme muodostaa pilkulla erotetun listan, joka sisältää Oton tiimin jäsenet. Miten tämän onnistuu?
Lähtödata on esimerkissämme valmiina muuttujassa (teamJSON).

Perinteinen ratkaisu
Suurin osa meistä lähestyisi ongelmaa todennäköisesti näin.
Luodaan muuttuja (TeamMembers), johon kerätään tiimin jäsenet.

Aloitetaan suodattamalla JSON:ista ne objektit, joissa tiimikymppinä toimii Otto.

Ehto on hieman tavallista monimutkaisempi, sillä teamlead-attribuutti on teamattribute-attribuutin sisällä.
item()?['teamattribute']?['teamlead']
Suodatamme siis tällä:

Suodatuksen jälkeen JSON sisältää ainoastaan tietueet, joissa teamleadina on Otto.

Käydään Apply to each -toiminnon avulla tulosjoukko läpi ja lisätään kukin tiiminjäsen (plus pilkku) muuttujaan.

Näin meillä on muuttujassa tiimin jäsenet pilkulla erotettuina. Pitää vain muistaa poistaa merkkijonon lopusta se viimeinen turha pilkku.

Mutta…
Kuuden tiimiläisen läpikäynti kestää 4 sekuntia. Mitä jos tiimejä on monta ja kaikissa on kymmeniä jäseniä? Tämähän on hidasta.
Lisäksi silmukka muodostaa nopeasti läjäpäin Power Platform -pyyntöjä.
Onnistuisiko tämä ilman?
Ratkaisu ilman silmukkaa (Apply to each)
Aloitetaan aivan kuten äskenkin, suodattamalla JSON näyttämään vain Oton tiimiläiset.

Mutta nyt muodostetaan tulosjoukosta valinta-toiminnolla (select) taulukko, jossa on listattu vain tiimin jäsenet (teammember).

Näin.

Olemme jo lähellä!
Haluamme lopputuloksena merkkijonon, jossa sähköpostiosoitteet ovat pilkulla erotettuina.
Muunnetan tulosjoukko merkkijonoksi (string) ja korvataan ylimääräiset merkit tyhjällä merkillä.
replace(replace(replace(string(body('Select_-_Only_teammember')),'[',''),']',''),'"','')

Valmis!

Suorituskyky on aivan toista luokkaa kuin silmukkaa käyttämällä.

Ratkaisu XPathin avulla
Lähestytään samaa ongelmaa lopuksi hieman eri tavalla. XPathilla.
XPath:in avulla voi tehdä kaikenlaista kivaa XML-sisällölle. Eli ensimmäisenä muutamme JSON-sisältömme XML-muotoon.
Jotta tämä onnistuu, tulee JSON:ssa olla root-elementti. Lisätään sellainen.

Muokattu JSON näyttää seuraavalta.
{
"root": {
"values": [
{
"teamattribute": {
"teamlead": "Otto@forwardforever.com",
"teammember": "Timo@forwardforever.com"
}
},
{
"teamattribute": {
"teamlead": "Otto@forwardforever.com",
"teammember": "Ilkka@forwardforever.com"
}
}]
}
}
Tämän voimme muuttaa xml-funktiolla XML:ksi.
xml(outputs('Compose_-_Add_root'))

Jolloin lopputulos on tämännäköinen.
<root>
<values>
<teamattribute>
<teamlead>Otto@forwardforever.com
</teamlead>
<teammember>Timo@forwardforever.com
</teammember>
</teamattribute>
</values>
<values>
<teamattribute>
<teamlead>Otto@forwardforever.com
</teamlead>
<teammember>Ilkka@forwardforever.com
</teammember>
</teamattribute>
</values>
</root>
Haluamme poimia XML:n sisältä tiimin jäsenet, joiden tiimikymppinä on Otto. Miten tämä tehdään?
XPathilla.
Avataan http://xpather.com/. Kopioidaan vasempaan kenttään muodostamamme XML.

Nyt voimme kokeilla erilaisia XPath-komentoja. Esimerkiksi //teammember palauttaa kaikki tiimien jäsenet.

XPath saattaa tuntua aluksi vähintään sekavalta. Onneksi verkosta löytyy useita tutorialeja sen käytöstä. Esim W3schools:in.
Lyhyen harjoittelun jälkeen löytyy komento, joka palauttaa halutun tiimin jäsenet.
//teamattribute[teamlead="Otto@forwardforever.com"]/teammember

Suoritetaan sama XPath-komento flow’ssa.
xpath(outputs('Compose_-_Convert_to_XML'),'//teamattribute[teamlead="Otto@forwardforever.com"]/teammember')

Yllätys on kuitenkin melkoinen, kun toiminnon lopputulos näyttää tältä.

XPath-komento on kuitenkin tuottanut oikean tuloksen. Se pitää vain muuttaa luettavaan muotoon.
Tehdään tulosjoukkolle valinta (select), jossa muunnetaan rivit selkokieliseksi base64ToString-funktiolla.

Siellä ne ovat!

Loppu onkin sitten merkkijonokikkailua. Korvataan alku- ja lopputagit (<teammember> ja </teammember>) tyhjällä merkkijonolla.
replace(replace(base64ToString(item()?['$content']),'<teammember>',''),'</teammember>','')
Tämän jälkeen muutetaan tulos merkkijonoksi ja poistetaan loput ylimääräiset merkit (”, [, ]).
replace(replace(replace(string(body('Select')),'[',''),']',''),'"','')

Valmis!

Teimme flow’n osissa, jotta sen rakentuminen olisi helpompi hahmottaa. Käytännössä tarvitsemme ainoastaan kaksi toimintoa.
Valinta (select), jonka from-osiossa
- muodostamme muokatun JSON:in
- muutamme sen XML-muotoon
- teemme XPath kyselyn
xpath(xml(json(concat('{ "root": {"values": ', variables('teamJSON'), ' }}'))),'//teamattribute[teamlead="Otto@forwardforever.com"]/teammember')
Tämän jälkeen laadi-toiminnolla (compose) siistitään merkkijono lopulliseen muotoonsa.

Suorituskyky
Verrataan lopuksi näiden kolmen eri lähestymistavan suorituskykyä keskenään. Käytetään JSON:ia, jossa Oton tiimissä on 36 jäsentä.
Perinteisellä tavalla (silmukka) sähköpostilistan muodostaminen vie 16 sekuntia!

Tavat jossa ei käytetä silmukkaa, suoriutuvat samasta alle sekunnissa.

XPath:illa:

Power Platform pyyntöjä muodostuu vähiten XPath-toteutuksessa.
Yhteenveto
XPath on tietyissä tilanteissa erinomainen työkalu. Se on suorityskykyinen, mutta vastineeksi saa yleensä hieman vaikealukuisen toteutuksen. Riippuu aina tilanteesta, kumpi painaa vaakakupissa enemmän.
Mikään kansalaiskehittäjän perustyökalu se ei kyllä ole.