2 Replies Latest reply: May 23, 2013 12:19 AM by vv*338251*hu RSS

    Parent-Child Unbound Transformation from Linear Structure

    vv*338251*hu
      Hi ,

      We need to convert the linear people structure into Parent-Child relation with unbounded depth using XQuery. To give in detail, we have the XML schema as

      <?xml version="1.0" encoding="UTF-8"?>
      <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/ParentChild" xmlns:tns="http://www.example.org/ParentChild" elementFormDefault="qualified">

      <complexType name="People">
      <sequence>
      <element name="id" type="string" />
      <element name="name" type="string" />
      <element name="age" type="string" />
      <element name="parentId" type="string" minOccurs="0" />
      </sequence>
      </complexType>

      <complexType name="Peoples">
      <sequence>
      <element name="people" type="tns:People" maxOccurs="unbounded"></element>
      </sequence>
      </complexType>
      <element name="Peoples" type="tns:Peoples"></element>
      <element name="People" type="tns:People"></element>

      <complexType name="Parent">
      <sequence>
      <element name="id" type="string" />
      <element name="name" type="string" />
      <element name="age" type="string" />
      <element name="child" type="tns:Parent" minOccurs="0" maxOccurs="unbounded" />
      </sequence>
      </complexType>

      <complexType name="Parents">
      <sequence>
      <element name="Parent" type="tns:Parent" maxOccurs="unbounded" ></element>
      </sequence>
      </complexType>

      <element name="Parents" type="tns:Parents"></element>
      <element name="Parent" type="tns:Parent"></element>

      </schema>

      The input structure can appear as
      <?xml version="1.0"?>
      <ns0:Peoples xmlns:ns0="http://www.example.org/ParentChild">
      <ns0:people>
      <ns0:id>1</ns0:id>
      <ns0:name>x</ns0:name>
      <ns0:age>11</ns0:age>
      <ns0:parentId>2</ns0:parentId>
      </ns0:people>
      <ns0:people>
      <ns0:id>2</ns0:id>
      <ns0:name>y</ns0:name>
      <ns0:age>11</ns0:age>
      <ns0:parentId>3</ns0:parentId>
      </ns0:people>
      <ns0:people>
      <ns0:id>3</ns0:id>
      <ns0:name>z</ns0:name>
      <ns0:age>11</ns0:age>
      </ns0:people>
      <ns0:people>
      <ns0:id>5</ns0:id>
      <ns0:name>a</ns0:name>
      <ns0:age>11</ns0:age>
      </ns0:people>
      </ns0:Peoples>

      The response should be like below
      <?xml version="1.0"?>
      <ns0:Parents xmlns:ns0="http://www.example.org/ParentChild">
      <ns0:Parent>
      <ns0:id>3</ns0:id>
      <ns0:name>z</ns0:name>
      <ns0:age>11</ns0:age>
      <ns0:child>
      <ns0:id>2</ns0:id>
      <ns0:name>y</ns0:name>
      <ns0:age>11</ns0:age>
      <ns0:child>
      <ns0:id>1</ns0:id>
      <ns0:name>x</ns0:name>
      <ns0:age>11</ns0:age>
      </ns0:child>
      </ns0:child>
      </ns0:Parent>
      <ns0:Parent>
      <ns0:id>5</ns0:id>
      <ns0:name>a</ns0:name>
      <ns0:age>11</ns0:age>
      </ns0:Parent>
      </ns0:Parents>

      We tried with below XQuery, but it is not resulting as expected.

      (:: pragma bea:global-element-parameter parameter="$peoples" element="ns0:Peoples" location="ParentChild.xsd" ::)
      (:: pragma bea:global-element-return element="ns0:Parents" location="ParentChild.xsd" ::)

      declare namespace ns0 = "http://www.example.org/ParentChild";
      declare namespace xf = "http://tempuri.org/RecursiveParentChild/ParentChild/";

      declare function xf:ParentChild($peoples as element(ns0:Peoples))
      as element(ns0:Parents) {
      <ns0:Parents>
      {
      let $results := <a>{
           for $people1 in $peoples/ns0:people where (not (exists ($people1/*:parentId)))
           return
           <ns0:Parent>
                                    <ns0:id>{ data($people1/ns0:id) }</ns0:id>
                          <ns0:name>{ data($people1/ns0:name) }</ns0:name>
                          <ns0:age>{ data($people1/ns0:age) }</ns0:age>
                               </ns0:Parent>
                     }
                     </a>
                     
                     let $result1 :=
                     for $people1 in $peoples/ns0:people where (exists ($people1/*:parentId))
                     return
                          if (data($people1/ns0:parentId) = data($results/ns0:id)) then
                               <ns0:child>
                                    $people1/*
                               </ns0:child>
                          else()
                     
                     return $result1      
      }
      </ns0:Parents>
      };

      declare variable $peoples as element(ns0:Peoples) external;

      xf:ParentChild($peoples)

      Anyone tried similar kind of XQuery?. THere is a possibility that the child node can appear before the parent node, how we can handle that as well?

      Any help on this is appreciated

      Regards
      Venkata Madhu
        • 1. Re: Parent-Child Unbound Transformation from Linear Structure
          odie_63
          You need a recursive function in this situation :
          declare namespace ns0 = "http://www.example.org/ParentChild";
          declare namespace xf = "http://tempuri.org/RecursiveParentChild/ParentChild/";
          declare variable $peoples as element(ns0:Peoples) external;
          
          declare function xf:getChildren($p as element(ns0:people)) as element(ns0:child)*
          {
            
            for $c in $peoples/ns0:people[ns0:parentId=$p/ns0:id]
            return <ns0:child>
                  <ns0:id>{ data($p/ns0:id) }</ns0:id>
                  <ns0:name>{ data($c/ns0:name) }</ns0:name>
                  <ns0:age>{ data($p/ns0:age) }</ns0:age>
                  { xf:getChildren($c) }
                   </ns0:child>
          };
          
          <ns0:Parents>
          {
            for $p in $peoples/ns0:people[not(ns0:parentId)]
            return <ns0:Parent>
                  <ns0:id>{ data($p/ns0:id) }</ns0:id>
                  <ns0:name>{ data($p/ns0:name) }</ns0:name>
                  <ns0:age>{ data($p/ns0:age) }</ns0:age>
                  { xf:getChildren($p) }
                   </ns0:Parent>
          }
          </ns0:Parents>
          • 2. Re: Parent-Child Unbound Transformation from Linear Structure
            vv*338251*hu
            It is working as expected, thanks. Still can we modify to have only one single for loop?