increment a variable only when a conditional is true?

Wednesday, 19 February 2020 · 8 messages · last reply 20 Feb 2020
T
thufir19 Feb 2020 17:01 #
How can I increment the x variable only when numerical is false? (I've been reading how xquery isn't iterative...) current output:
<xml>
   <person id="1" x="0" numerical="false">people</person>
   <person id="2" x="0" numerical="false">joe</person>
   <person id="3" x="0" numerical="true">phone1</person>
   <person id="4" x="0" numerical="true">phone2</person>
   <person id="5" x="0" numerical="true">phone3</person>
   <person id="6" x="0" numerical="false">sue</person>
   <person id="7" x="0" numerical="true">cell4</person>
   <person id="8" x="0" numerical="true">home5</person>
   <person id="9" x="0" numerical="false">alice</person>
   <person id="10" x="0" numerical="true">atrib6</person>
   <person id="11" x="0" numerical="true">x7</person>
   <person id="12" x="0" numerical="true">y9</person>
   <person id="13" x="0" numerical="true">z10</person>
</xml>
desired output:
<xml>
   <person id="1" x="1" numerical="false">people</person>
   <person id="2" x="2" numerical="false">joe</person>
   <person id="3" x="2" numerical="true">phone1</person>
   <person id="4" x="2" numerical="true">phone2</person>
...
</xml>
Maybe with a second xquery? Here's the first: xquery version "3.0";
<xml>

{
variable $x:=0;

for $line in db:open("foo.txt")//text()
count $id
return    if (matches($line, "[0-9]"))
          then <person id='{$id}' x='{$x}' numerical="true">{$line}</person>
          else <person id='{$id}' x='{$x}'
numerical="false">{$line}</person>
}
</xml>

where I'm trying to use attributes because I'm not sure how to
conditionally nest tags.  But, this is interesting.  Not quite sure on
syntax to set and then conditionally increment $x, however.
thanks, Thufir
T
thufir19 Feb 2020 17:33 #
How do I decrement y? Pardon, output for a simpler example:
<xy x="1" y="98"/>
<xy x="2" y="98"/>
<xy x="3" y="98"/>
<xy x="4" y="98"/>
<xy x="5" y="98"/>
<xy x="6" y="98"/>
<xy x="7" y="98"/>
<xy x="8" y="98"/>
<xy x="9" y="98"/>
the FLWOR:
xquery version "3.0";
let $y := 99
for $x in (1 to 9)
  let $y := $y - 1
return <xy x='{$x}' y='{$y}' />
is it not possible to decrement $y without using some external scripting function? That seems odd. thanks, Thufir
BD
Bridger Dyson-Smith19 Feb 2020 17:55 #
Hi Thufir - Maybe something like this will help?
xquery version "3.1";

let $y := 99

for $x in (1 to 9)
count $iterator
let $decrease := $y - $iterator
return(
  comment { "iterator = " ||  $iterator },
  comment { "decrease = " || $decrease },
  <xy x='{ $x }' y='{ $decrease }'/>
)
I'm basically ripping Walmsley's book off for this example -- see pages ~135-7 (examples P-6,7). The count clause makes this work. Best, Bridger PS Remember, the first step in avoiding a *trap* is knowing of its existence. :)
Quoted text · thufir · 32 lines
On Wed, Feb 19, 2020 at 10:33 AM thufir <hawat.thufir at gmail.com> wrote: > How do I decrement y? > > Pardon, output for a simpler example: > > <xy x="1" y="98"/> > <xy x="2" y="98"/> > <xy x="3" y="98"/> > <xy x="4" y="98"/> > <xy x="5" y="98"/> > <xy x="6" y="98"/> > <xy x="7" y="98"/> > <xy x="8" y="98"/> > <xy x="9" y="98"/> > > the FLWOR: > > xquery version "3.0"; > let $y := 99 > for $x in (1 to 9) > let $y := $y - 1 > return <xy x='{$x}' y='{$y}' /> > > > is it not possible to decrement $y without using some external scripting > function? That seems odd. > > > thanks, > > Thufir >
T
thufir19 Feb 2020 18:25 #
Hi Bridger, Yes, this may very well. I'll dive into it later today or tomorrow. The difficulty for me will be to decrement only if a conditional. But, that may very well suffice. If so, it will give the data some structure through attributes. Then, I can use those attributes. Thanks, Thufi
Quoted text · Bridger Dyson-Smith · 64 lines
On 2020-02-19 7:57 a.m., Bridger Dyson-Smith wrote: > Hi Thufir - > > Maybe something like this will help? > > ``` > xquery version "3.1"; > > let $y := 99 > > for $x in (1 to 9) > count $iterator > let $decrease := $y - $iterator > return( > comment { "iterator = " || $iterator }, > comment { "decrease = " || $decrease }, > <xy x='{ $x }' y='{ $decrease }'/> > ) > ``` > > I'm basically ripping Walmsley's book off for this example -- see pages > ~135-7 (examples P-6,7). The `count` clause makes this work. > > Best, > Bridger > > PS Remember, the first step in avoiding a *trap* is knowing of its > existence. :) > > On Wed, Feb 19, 2020 at 10:33 AM thufir <hawat.thufir at gmail.com > <mailto:hawat.thufir at gmail.com>> wrote: > > How do I decrement y? > > Pardon, output for a simpler example: > > <xy x="1" y="98"/> > <xy x="2" y="98"/> > <xy x="3" y="98"/> > <xy x="4" y="98"/> > <xy x="5" y="98"/> > <xy x="6" y="98"/> > <xy x="7" y="98"/> > <xy x="8" y="98"/> > <xy x="9" y="98"/> > > the FLWOR: > > xquery version "3.0"; > let $y := 99 > for $x in (1 to 9) > let $y := $y - 1 > return <xy x='{$x}' y='{$y}' /> > > > is it not possible to decrement $y without using some external > scripting > function? That seems odd. > > > thanks, > > Thufir >
MS
Majewski, Steven Dennis (sdm7g)in reply to thufir, 19 Feb 2020, 17:0119 Feb 2020 22:05 #
Quoted text · thufir · 3 lines
> On Feb 19, 2020, at 10:01 AM, thufir <hawat.thufir at gmail.com> wrote: > > where I'm trying to use attributes because I'm not sure how to conditionally nest tags. But, this is interesting. Not quite sure on syntax to set and then conditionally increment $x, however.
Does “conditionally nest tags” mean that you want to make the person[@numerical=“true”] elements children of the immediately previous person[@numerical=“false”] elements ? If that is the case you can use “group by” — Steve M.
T
thufir20 Feb 2020 03:29 #
Hi Steve, yes, it certainly does. At this point, I'd settle for adding an attribute like "recordID", but that's exactly it. I'll take a closer look at "group by" a bit later, thanks for the pointer. See also: https://stackoverflow.com/q/60237739/262852 thanks, Thufir
Quoted text · Steven Dennis (sdm7g) · 20 lines
On 2020-02-19 1:05 p.m., Majewski, Steven Dennis (sdm7g) wrote: > > >> On Feb 19, 2020, at 10:01 AM, thufir <hawat.thufir at gmail.com >> <mailto:hawat.thufir at gmail.com>> wrote: >> >> where I'm trying to use attributes because I'm not sure how to >> conditionally nest tags. But, this is interesting. Not quite sure on >> syntax to set and then conditionally increment $x, however. > > Does “conditionally nest tags” mean that you want to make the > person[@numerical=“true”] elements children of the immediately previous > person[@numerical=“false”] elements ? > > If that is the case you can use “group by” > > > — Steve M. > >
MS
Majewski, Steven Dennis (sdm7g)20 Feb 2020 03:55 #
The reason I asked was: although XQuery looks more procedural than XSLT, it’s still basically a functional and declarative language, and thinking about incrementing or decrementing variables is probably the wrong way to think about solving your problem in XQuery. Variables bind names to values over a particular scope, and they aren’t updatable variables that you can increment or decrement. If what you want in English is roughly: For person element where numerical = true , group by the preceding-sibling where numerical = false That maps fairly simply into XQuery syntax:
declare variable $XML := <xml>
 <person id="1" x="0" numerical="false">people</person>
 <person id="2" x="0" numerical="false">joe</person>
 <person id="3" x="0" numerical="true">phone1</person>
 <person id="4" x="0" numerical="true">phone2</person>
 <person id="5" x="0" numerical="true">phone3</person>
 <person id="6" x="0" numerical="false">sue</person>
 <person id="7" x="0" numerical="true">cell4</person>
 <person id="8" x="0" numerical="true">home5</person>
 <person id="9" x="0" numerical="false">alice</person>
 <person id="10" x="0" numerical="true">atrib6</person>
 <person id="11" x="0" numerical="true">x7</person>
 <person id="12" x="0" numerical="true">y9</person>
 <person id="13" x="0" numerical="true">z10</person>
</xml> ;

for $P in $XML/person
where $P[@numerical="true"]
let $PREV := $P/preceding-sibling::person[@numerical="false"][1]
group by $PREV
return <person name="{$PREV}" >  { $P } </person>
Yields:
<person name="joe">
  <person id="3" x="0" numerical="true">phone1</person>
  <person id="4" x="0" numerical="true">phone2</person>
  <person id="5" x="0" numerical="true">phone3</person>
</person>
<person name="sue">
  <person id="7" x="0" numerical="true">cell4</person>
  <person id="8" x="0" numerical="true">home5</person>
</person>
<person name="alice">
  <person id="10" x="0" numerical="true">atrib6</person>
  <person id="11" x="0" numerical="true">x7</person>
  <person id="12" x="0" numerical="true">y9</person>
  <person id="13" x="0" numerical="true">z10</person>
</person>
Once the grouping is working, you can work on tweaking the output format to exactly what you want. I tried to work towards something like what I THOUGHT you might want. I had a bit of trouble understanding that $PREV in the return expression is an atomic string value and not a node, and that the other variables in return expression are multiple valued ( thus the ‘[1]’s ), but I ended up with this:
<people> {
for $P in $XML/person
where $P[@numerical="true"]
let $PREV := $P/preceding-sibling::person[@numerical="false"][1]
let $X := count($P[1]/preceding-sibling::person[@numerical="false"])
group by $PREV
return <person name="{$PREV}"
x="{$X[1] - 1 }"
id="{$P[1]/preceding-sibling::person[@numerical="false"][1]/@id}"
Quoted text · thufir · 1 line
> { for $I in $P return <number>{$I/@id, attribute x {$X[1]-1}, string($I)}</number> } </person>
} </people> Which yields:
<people>
  <person name="joe" x="1" id="2">
    <number id="3" x="1">phone1</number>
    <number id="4" x="1">phone2</number>
    <number id="5" x="1">phone3</number>
  </person>
  <person name="sue" x="2" id="6">
    <number id="7" x="2">cell4</number>
    <number id="8" x="2">home5</number>
  </person>
  <person name="alice" x="3" id="9">
    <number id="10" x="3">atrib6</number>
    <number id="11" x="3">x7</number>
    <number id="12" x="3">y9</number>
    <number id="13" x="3">z10</number>
  </person>
</people>
Also more functional to think of use count or position expressions instead of incrementing or decrementing variables. I’m hitting the Walmsley book myself now to try to understand those issues with group by / return that were puzzling to me. — Steve M.
Quoted text · thufir · 20 lines
> On Feb 19, 2020, at 8:28 PM, thufir <hawat.thufir at gmail.com> wrote: > > Hi Steve, > > yes, it certainly does. At this point, I'd settle for adding an attribute like "recordID", but that's exactly it. I'll take a closer look at "group by" a bit later, thanks for the pointer. See also: > > https://stackoverflow.com/q/60237739/262852 > > > thanks, > > Thufir > > On 2020-02-19 1:05 p.m., Majewski, Steven Dennis (sdm7g) wrote: >>> On Feb 19, 2020, at 10:01 AM, thufir <hawat.thufir at gmail.com <mailto:hawat.thufir at gmail.com>> wrote: >>> >>> where I'm trying to use attributes because I'm not sure how to conditionally nest tags. But, this is interesting. Not quite sure on syntax to set and then conditionally increment $x, however. >> Does “conditionally nest tags” mean that you want to make the person[@numerical=“true”] elements children of the immediately previous person[@numerical=“false”] elements ? >> If that is the case you can use “group by” >> — Steve M.
T
thufir20 Feb 2020 09:06 #
Yes, that's pretty much it: https://stackoverflow.com/q/60237739/262852 I'm a bit curious what happened to the "people" group, but I'll test and adapt. Did "people" get dropped because it has no following siblings to group with? thanks, Thufir
Quoted text · Steven Dennis (sdm7g) · 136 lines
On 2020-02-19 6:55 p.m., Majewski, Steven Dennis (sdm7g) wrote: > The reason I asked was: although XQuery looks more procedural than XSLT, > it’s still basically a functional and declarative language, and thinking > about incrementing or decrementing variables is probably the wrong way > to think about solving your problem in XQuery. > Variables bind names to values over a particular scope, and they aren’t > updatable variables that you can increment or decrement. > > If what you want in English is roughly: > For person element where numerical = true , group by the > preceding-sibling where numerical = false > > That maps fairly simply into XQuery syntax: > > declare variable $XML := <xml> > <person id="1" x="0" numerical="false">people</person> > <person id="2" x="0" numerical="false">joe</person> > <person id="3" x="0" numerical="true">phone1</person> > <person id="4" x="0" numerical="true">phone2</person> > <person id="5" x="0" numerical="true">phone3</person> > <person id="6" x="0" numerical="false">sue</person> > <person id="7" x="0" numerical="true">cell4</person> > <person id="8" x="0" numerical="true">home5</person> > <person id="9" x="0" numerical="false">alice</person> > <person id="10" x="0" numerical="true">atrib6</person> > <person id="11" x="0" numerical="true">x7</person> > <person id="12" x="0" numerical="true">y9</person> > <person id="13" x="0" numerical="true">z10</person> > </xml> ; > > for $P in $XML/person > where $P[@numerical="true"] > let $PREV := $P/preceding-sibling::person[@numerical="false"][1] > group by $PREV > return <person name="{$PREV}" > { $P } </person> > > Yields: > > > <person name="joe"> > <person id="3" x="0" numerical="true">phone1</person> > <person id="4" x="0" numerical="true">phone2</person> > <person id="5" x="0" numerical="true">phone3</person> > </person> > <person name="sue"> > <person id="7" x="0" numerical="true">cell4</person> > <person id="8" x="0" numerical="true">home5</person> > </person> > <person name="alice"> > <person id="10" x="0" numerical="true">atrib6</person> > <person id="11" x="0" numerical="true">x7</person> > <person id="12" x="0" numerical="true">y9</person> > <person id="13" x="0" numerical="true">z10</person> > </person> > > Once the grouping is working, you can work on tweaking the output format > to exactly what you want. I tried to work towards something like what I > THOUGHT you might want. > I had a bit of trouble understanding that $PREV in the return expression > is an atomic string value and not a node, and that the other variables > in return expression are multiple valued ( thus the ‘[1]’s ), but I > ended up with this: > > > <people> { > for $P in $XML/person > where $P[@numerical="true"] > let $PREV := $P/preceding-sibling::person[@numerical="false"][1] > let $X := count($P[1]/preceding-sibling::person[@numerical="false"]) > group by $PREV > return <person name="{$PREV}" > x="{$X[1] - 1 }" > id="{$P[1]/preceding-sibling::person[@numerical="false"][1]/@id}" >> { for $I in $P return <number>{$I/@id, attribute x {$X[1]-1}, string($I)}</number> } </person> > } </people> > > Which yields: > > <people> > <person name="joe" x="1" id="2"> > <number id="3" x="1">phone1</number> > <number id="4" x="1">phone2</number> > <number id="5" x="1">phone3</number> > </person> > <person name="sue" x="2" id="6"> > <number id="7" x="2">cell4</number> > <number id="8" x="2">home5</number> > </person> > <person name="alice" x="3" id="9"> > <number id="10" x="3">atrib6</number> > <number id="11" x="3">x7</number> > <number id="12" x="3">y9</number> > <number id="13" x="3">z10</number> > </person> > </people> > > > Also more functional to think of use count or position expressions > instead of incrementing or decrementing variables. > > I’m hitting the Walmsley book myself now to try to understand those > issues with group by / return that were puzzling to me. > > > — Steve M. > > >> On Feb 19, 2020, at 8:28 PM, thufir <hawat.thufir at gmail.com >> <mailto:hawat.thufir at gmail.com>> wrote: >> >> Hi Steve, >> >> yes, it certainly does. At this point, I'd settle for adding an >> attribute like "recordID", but that's exactly it. I'll take a closer >> look at "group by" a bit later, thanks for the pointer. See also: >> >> https://stackoverflow.com/q/60237739/262852 >> >> >> thanks, >> >> Thufir >> >> On 2020-02-19 1:05 p.m., Majewski, Steven Dennis (sdm7g) wrote: >>>> On Feb 19, 2020, at 10:01 AM, thufir <hawat.thufir at gmail.com >>>> <mailto:hawat.thufir at gmail.com>> wrote: >>>> >>>> where I'm trying to use attributes because I'm not sure how to >>>> conditionally nest tags. But, this is interesting. Not quite sure >>>> on syntax to set and then conditionally increment $x, however. >>> Does “conditionally nest tags” mean that you want to make the >>> person[@numerical=“true”] elements children of the immediately >>> previous person[@numerical=“false”] elements ? >>> If that is the case you can use “group by” >>> — Steve M. >

⚡Generated with XQuery