Search code examples
xmlxpathxquerybasex

Splitting a sequence and incrementing using Xquery


I have an xml like below , am trying to convert the xml in to csv

<module>
    <content>
        <catalouge SC="25" item="200">
            <Number id="250" RefIds="xyz20000">
                <Character condValue="PRE">
                    <count Number="1" Name="Sree" changeMark="1">FOR A/C 0013, 0047, 0063</count>
                </Character>
                <Character condValue="EMB">
                    <count Number="154" Name="Sree" changeMark="1">FOR A/C 0005-0010, 0021, 0025, 0033</count>
                </Character>
            </Number>
        </catalouge>
        <catalouge SC="180" item="200" >
            <Number id="780" RefIds="xyz20000">
                <Character condValue="EMB">
                    <count Number="1" Name="AB">FOR A/C 0006-0011</count>
                </Character>
                <Character condValue="EMB">
                    <count Number="154" Name="Sree" changeMark="1">FOR A/C 0013</count>
                </Character>
            </Number>
        </catalouge>
        <catalouge SC="567" item="240">
            <Number id="666" Value="123" RefIds="xyz20000">
                <Character condValue="EMB">
                    <count Number="2" Name="SB">FOR A/C 0008-0013</count>
                </Character>
                <Character condValue="PRE">
                    <count Number="1" Name="cherry" changeMark="1">FOR A/C 0018, 0047, 0063</count>
                </Character>
            </Number>
        </catalouge>
        <catalouge SC="8" item="280">
            <Number id="1994" Value="1234" RefIds="xyz20000" >
                <Character condValue="POST">
                    <count Number="3" Name="Sree" changeMark="1">FOR A/C 0006, 0047, 0063, 0090, 0143, 0172</count>
                </Character>
            </Number>
        </catalouge>
    </content>
</module>

My xquery is as below

for  $p in doc("dar.xml")//module/content/catalouge
            let $SC := $p/string(@SC)
            let $item := $p/string(@item)
            let $isns := $p/Number
            for $isn in $isns
              let $id := $isn/string(@id)
              let $Ref := $isn/string(@RefIds)              
              let $chr := (for $x in $isn return string-join($x//Character//@condValue,", "))
              let $chr_status := contains($chr, 'EMB')
              **let $count :=  $isn/Character/data(count)
              let $count_status :=  contains($chr, '0006')**
              let $Num :=  $isn/Character/count/string(@Number)
              let $sep :=";"
return (if($chr_status and $count_status) 
    then ()
  else(concat($SC,$sep,$item,$sep,$id,$sep,$Ref)) 
)

I'm performing an and operation here if both status are true it should print nothing if it is false it should print some value. My Output should as below:

567;240;666;xyz20000
8;280;1994;xyz20000

But here my issue is, the data which is present in count tag , has a sequence of values , How can I increment the range tokenize those and search for 0006 which returns a boolean value

<count Number="154" Name="Sree" changeMark="1">FOR A/C 0005-0012, 0021, 0025, 0033</count>

FOR A/C 0005-0012, 0021, 0025, 0033 which actually mean 0005 to 0012--> I have sequence 0005,0006,0007,0008,0009,0010,0011,0012,0021, 0025, 0033

Any ideas would be greatly appreciated, Thanks!


Solution

  • This seems to be similar to your previous question, you can use tokenize and the to operator after removing the FOR A/C prefix:

    //count 
    ! 
    (. 
    || ': ' 
    || (((
         substring-after(., 'FOR A/C ') ! 
         tokenize(., ', ') ! 
         (let $tokens := tokenize(., '-')!xs:integer(.) 
          return 
              (
                  if ($tokens[2]) 
                  then ($tokens[1] to $tokens[2]) 
                  else $tokens[1])
              ) 
        ! format-integer(., '0001')) = '0006')))
    

    https://xqueryfiddle.liberty-development.net/94hwpi2/2 gives

    FOR A/C 0013, 0047, 0063: false
    FOR A/C 0005-0010, 0021, 0025, 0033: true
    FOR A/C 0006-0011: true
    FOR A/C 0013: false
    FOR A/C 0008-0013: false
    FOR A/C 0018, 0047, 0063: false
    FOR A/C 0006, 0047, 0063, 0090, 0143, 0172: true