Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: ZAJDAN 25. 08. 2023, 12:04:30

Název: XSL podmíněný foreach
Přispěvatel: ZAJDAN 25. 08. 2023, 12:04:30
Ahoj....
potřebuji v XSLT 1.0
vybrat řádky, které nemají předcházející dvojče se stejnou hodnotou v daném elementu.
https://xsltfiddle.liberty-development.net/6r5EJSU/2 (https://xsltfiddle.liberty-development.net/6r5EJSU/2)

Mělo by to vybrat dva řádky, ale vybere se jen jeden.
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 25. 08. 2023, 13:13:04
V XSLT se pokud možno nepoužívá for-each, ale použije se apply-templates.

Porovnání ItemCode=ItemCode je zjevně nesmysl, XPath procesor nemůže vědět, že tím jednou myslíte ItemCode z kontextu před spuštěním XPath výrazu a podruhé ItemCode v rámci XPath výrazu.

Udělal bych to tak, že si vytvoříte šablonu na ResultSet/Row, v té si uložíte do proměnné hodnotu ItemCode, a pak zavoláte další šablonu, ve které budete mít tu vaši podmínku – a hodnotu předchozího záznamu budete porovnávat s tím, co máte uložené v proměnné. Přičemž ještě přidejte podmínku, že vás zajímá jenom první z předchozích záznamů (tj. za Row přidejte [1]) – tak, jak to máte teď, by se ta podmínka vyhodnotila, pokud by v kterémkoli z předchozích záznamů byla vámi hledaná hodnota.
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 25. 08. 2023, 14:15:36
... a pak zavoláte další šablonu, ve které budete mít tu vaši podmínku – a hodnotu předchozího záznamu budete porovnávat s tím, co máte uložené v proměnné. Přičemž ještě přidejte podmínku, že vás zajímá jenom první z předchozích záznamů (tj. za Row přidejte [1]) – tak, jak to máte teď, by se ta podmínka vyhodnotila, pokud by v kterémkoli z předchozích záznamů byla vámi hledaná hodnota.
Vytvořil jsem tedy tu první šablonu. S tou druhou šablonou již netuším jak přesně to myslíte. Pomohl by jste mi prosím přímo v tom příkladu?
https://xsltfiddle.liberty-development.net/6r5EJSU/3

děkuji
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 25. 08. 2023, 14:26:56
už jse se posunul, ale musím si s tím více pohrát:
https://xsltfiddle.liberty-development.net/6r5EJSU/4 (https://xsltfiddle.liberty-development.net/6r5EJSU/4)
chápu Vás správně, že nebude for-each vůbec potřeba a všechno se udělá pomocí šablon a podmínek v selectu?
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 25. 08. 2023, 19:12:48
XSLTfiddle mi teď hlásí 503… Ale to XSLT by snad mohlo vypadat takhle nějak:

Kód: [Vybrat]
<xsl:stylesheet version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  exclude-result-prefixes="#all" expand-text="yes">

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="ResultSet/Row" priority="10">
    <xsl:variable name="ItemCode" select="ItemCode" />
    <xsl:apply-templates select=".[not(preceding-sibling::Row[1][ItemCode=$ItemCode])]" />
  </xsl:template>
  <xsl:template match="ResultSet/Row" priority="5">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Kopíruje to požadované řádky do výstupu, vy s nimi asi místo copy budete chtít udělat něco jiného.
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 25. 08. 2023, 19:39:30
...
Kopíruje to požadované řádky do výstupu, vy s nimi asi místo copy budete chtít udělat něco jiného.
moc děkuji
zkouším, ale nevypíše to žádný řádek:
https://xsltfiddle.liberty-development.net/6r5EJSU/5 (https://xsltfiddle.liberty-development.net/6r5EJSU/5)
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 25. 08. 2023, 19:51:24
Jo, protože priority takhle nefunguje a next-match v XSLT 1.0 není. Tak takhle? https://xsltfiddle.liberty-development.net/6r5EJSU/6
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 26. 08. 2023, 10:05:28
Jo, protože priority takhle nefunguje a next-match v XSLT 1.0 není. Tak takhle? https://xsltfiddle.liberty-development.net/6r5EJSU/6
Pane Jirsák moc děkuji za ukázku. Doplnil jsem do xpath select podmínky dle mé potřeby. Teď ale narážím na problém, že mi nepůjdou dosazovat indexi jako to lze například ve for-each pomocí position()
Existuje v šabloně způsob jak na to?
https://xsltfiddle.liberty-development.net/6r5EJSU/7 (https://xsltfiddle.liberty-development.net/6r5EJSU/7)
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 26. 08. 2023, 10:24:35
position() se počítá z aktuálního kontextu, tedy u šablony ze všech uzlů, které odpovídají selectu šablony. Předpokládám, že tam chcete pozici z té původní množiny – pak je potřeba ji získat hned v první šabloně a do té druhé šablony si ji poslat pomocí parametru: https://xsltfiddle.liberty-development.net/6r5EJSU/8
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 26. 08. 2023, 11:03:11
...Předpokládám, že tam chcete pozici z té původní množiny...
Špatně jsem to napsal, potřeboval bych vypsat indexy z té selektované množiny. V tom příkladu to jsou 4 řádky.
Každopádně to co jste použil se mi také bude hodit.
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 26. 08. 2023, 13:01:07
Nenapadá mne, jak to s prostředky XSLT 1.0 udělat jinak, než druhým průchodem přes ty výsledné záznamy: https://xsltfiddle.liberty-development.net/6r5EJSU/10
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 28. 08. 2023, 13:16:43
Nenapadá mne, jak to s prostředky XSLT 1.0 udělat jinak, než druhým průchodem přes ty výsledné záznamy: https://xsltfiddle.liberty-development.net/6r5EJSU/10
wooow...jste opravdu machr! moc moc děkuji
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 29. 08. 2023, 10:10:53
Nenapadá mne, jak to s prostředky XSLT 1.0 udělat jinak, než druhým průchodem přes ty výsledné záznamy: https://xsltfiddle.liberty-development.net/6r5EJSU/10
Dobrý den pane Jirsák,
pokouším se tu pozici z podmíněného selectu uloženou do proměnné index porovnávat zda je(lichá, sudá) s hodnotou v elementu, který generuju v jiné šabloně, ale právě v této jiné šabloně už ta proměnná není přístupná.
Napadá Vás jak by toho šlo dosáhnout?
https://xsltfiddle.liberty-development.net/6r5EJSU/17 (https://xsltfiddle.liberty-development.net/6r5EJSU/17)
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 29. 08. 2023, 11:56:47
Tak se mi to povedlo. Musel jsem do šablony 2 přidat generování elementu který porovnávám v cyklu.
https://xsltfiddle.liberty-development.net/6r5EJSU/19 (https://xsltfiddle.liberty-development.net/6r5EJSU/19)
Název: Re:XSL podmíněný foreach
Přispěvatel: fos4 29. 08. 2023, 12:22:39
Porovnání ItemCode=ItemCode je zjevně nesmysl, XPath procesor nemůže vědět, že tím jednou myslíte ItemCode z kontextu před spuštěním XPath výrazu a podruhé ItemCode v rámci XPath výrazu.

Doplním, že pro tyto případy lze použít funkci current(), která kontext určí přesně. Takže podmínka pak jde použít nějak takto:

ItemCode=current()/ItemCode

Používám běžne pro for-each, kdy chci rozlišit zda hodnota se vztahuje na data uvnitř for-eachu, nebo vně.
Název: Re:XSL podmíněný foreach
Přispěvatel: fos4 29. 08. 2023, 12:34:29
Příklad s "if", sedí to?

https://xsltfiddle.liberty-development.net/6r5EJSU/20

Kód: [Vybrat]
<xsl:for-each select="ResultSet/Row">
  <xsl:if test="not(preceding-sibling::Row[current()/ItemCode=ItemCode])">
    <xsl:copy-of select="." />
  </xsl:if>
</xsl:for-each>
Název: Re:XSL podmíněný foreach
Přispěvatel: fos4 29. 08. 2023, 13:36:08
Nebo přímo ve for-each:

https://xsltfiddle.liberty-development.net/6r5EJSU/21

Kód: [Vybrat]
<xsl:for-each select="ResultSet/Row[not(preceding-sibling::Row/ItemCode=ItemCode)]">
  <xsl:copy-of select="." />
</xsl:for-each>
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 29. 08. 2023, 13:44:10
Nebo přímo ve for-each:
https://xsltfiddle.liberty-development.net/6r5EJSU/21
.... 
super...pracovat s for-each je pro mě jednoduší
práce se šablonami je velice zajímavá, ale přiznám se...moc je nechápu i když se snažím.
Díky panu Jirsákovi jsem konečně překročil práh a konečně s nimi udělal první krůček.
Pokusím se docílit výsledku oběma způsoby (for-each, template)
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 29. 08. 2023, 14:15:59
pomocí toho IF current() to funguje, ale problém bude získat výsledné indexi(řádky splňující podmínku)
a stejně tak z for-each
Název: Re:XSL podmíněný foreach
Přispěvatel: fos4 29. 08. 2023, 14:27:59
Počkat.. vy chcete udělat jen group by Row/ItemCode a následně projete všechny ItemCode? postupně?
Název: Re:XSL podmíněný foreach
Přispěvatel: ZAJDAN 29. 08. 2023, 14:38:14
Počkat.. vy chcete udělat jen group by Row/ItemCode a následně projete všechny ItemCode? postupně?

position() počítá indexi ze vstupu na kterém se cykluje já ale potřebuju počítat indexi na výstupu, který vznikne na základě splněných podmínek
https://xsltfiddle.liberty-development.net/6r5EJSU/23 (https://xsltfiddle.liberty-development.net/6r5EJSU/23)
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 29. 08. 2023, 14:50:11
Doplním, že pro tyto případy lze použít funkci current(), která kontext určí přesně.
No jo, jenže ta je zase dostupná až od XPath 2.0, tedy XSLT 2.0. XSLT 2.0 přineslo oproti XSLT 1.0 právě spoustu věcí, které umožňují složitější zpracování dat v jednom průchodu. Když je omezení na použití XSLT 1.0, je to jak mít jednu ruku za zády.

super...pracovat s for-each je pro mě jednoduší
Pro vás ano, ale XSLT procesoru tím podrážíte nohy, protože pak nemůže kód moc optimalizovat. apply-templates je deklarativní, říkáte tím co se má udělat a je na XSLT procesoru, jak to udělá. for-each je imperativní, říkáte jak se to má udělat a XSLT procesoru nezbývá nic jiného, než to udělat tak, jak jste předepsal – i když by to třeba šlo jinak lépe. Je to stejné jako u SQL. Ale je pravda, že u XSLT 1.0 procesoru to s optimalizacemi asi nebude žádná sláva.
Název: Re:XSL podmíněný foreach
Přispěvatel: fos4 29. 08. 2023, 14:53:25
current() má i XSLT 1.

Jinak lze celý výstup zabalit do proměnné a pak projet for-eachem. Nevím jak to má Saxon, tam se zdá to funguje by-default, jinak použít node-set()

https://xsltfiddle.liberty-development.net/6r5EJSU/24

Na rychlost ohledně for-each VS apply-templates se musím podívat, jak to vychází..apply templates právě moc nepoužíváme (ale máme malé XMLka), někde by se to mohlo hodit...
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 29. 08. 2023, 14:55:28
Tak se mi to povedlo. Musel jsem do šablony 2 přidat generování elementu který porovnávám v cyklu.
https://xsltfiddle.liberty-development.net/6r5EJSU/19 (https://xsltfiddle.liberty-development.net/6r5EJSU/19)

V šabloně kopírující atributy máte navíc mode="index", ale žádnou šablonu s módem index tam nemáte.

Kód: [Vybrat]
<xsl:apply-templates select="@*" mode="index"/>
Nicméně na elementu Packaging stejně žádné atributy nemáte, takže to kopírování atributů je tam zbytečné. Dal jsem to tam jen pro úplnost, nevěděl jsem, zda tam nějaké atributy nebudete mít.
Název: Re:XSL podmíněný foreach
Přispěvatel: Filip Jirsák 29. 08. 2023, 15:07:56
current() má i XSLT 1.
A jo – vycházel jsem z dokumentace Saxonu, a neuvědomil jsem si, že ten už má jen režim kompatibility s XSLT 1.0 a v dokumentaci uvádí podporu až od XSLT 2.0.