Loading ...
Sorry, an error occurred while loading the content.

Re: SOAP::SOM array of arrays

Expand Messages
  • teden
    Ok, I am beginning to get it. My code below is doing exactly what I asked it to - get the som tree for all A elements, then get the som tree for all B
    Message 1 of 6 , Oct 8, 2003
    • 0 Attachment
      Ok,

      I am beginning to get it. My code below is doing exactly what I asked
      it to - get the som tree for all A elements, then get the som tree
      for all B elements. What I want are all the B elements for a given A
      element. It seems I cannot do what it is I want to do. SOAP::SOM-
      >match, dataof and valueof trim the SOM tree to a subset specified in
      the path given as an argument. When processing the inner array, it
      seems I cannot match it to its parent element, a key requirement.
      When the documentation says that the SOAP::SOM
      methods "match", "dataof", and "valeuof" take a simple XPATH type
      syntax, I expected to be able to specify something like

      '//A[1]/B[1]'

      to get the first B element nested within the first A element. Alas, I
      cannot. Can this be a formal request for an enhancement? In the
      meantime, I either need to look at creating a custom deserializer,
      or - heaven forbid - another language.


      Frustrated,

      Thom Eden


      --- In soaplite@yahoogroups.com, "Thom Eden" <the@d...> wrote:
      > Folks,
      >
      > I am having an issue parsing a SOAP::SOM envelope. Basically, I
      have an array of arrays, e.g.
      >
      > <A>
      > <B>q</B>
      > <B>r</B>
      > </A>
      > <A>
      > <B>x</B>
      > <B>y</B>
      > </A>
      >
      > The code I am using looks something like this:
      >
      > if ($som->match(SOAP::SOM::envelope)) {
      > foreach my $A_Element($som->dataof('//A')) {
      > print "<A>\n";
      > foreach my $B_Element($som->dataof('//A/B')) {
      > print " <B>".$B_Element->value."</B>\n";
      > }
      > print "</A>\n";
      > }
      > } else {
      > print "! It's not SOAP::SOM !\n\n";
      > }
      >
      > which should print out the above, but instead I get
      >
      > <A>
      > <B>q</B>
      > <B>r</B>
      > <B>x</B>
      > <B>y</B>
      > </A>
      > <A>
      > <B>q</B>
      > <B>r</B>
      > <B>x</B>
      > <B>y</B>
      > </A>
      >
      > I need the inner loop to position itself relative to the parent
      element. How do you do this?
      >
      > Many thanks,
      >
      > Thom Eden
    • Duncan Cameron
      ... One way is to iterate through the children at each level, like this: my $xml = q r c stuff x c
      Message 2 of 6 , Oct 8, 2003
      • 0 Attachment
        At 13:21:00 on 2003-10-08 teden <the@...> wrote:

        >Ok,
        >
        >I am beginning to get it. My code below is doing exactly what I asked
        >it to - get the som tree for all A elements, then get the som tree
        >for all B elements. What I want are all the B elements for a given A
        >element. It seems I cannot do what it is I want to do. SOAP::SOM->
        >match, dataof and valueof trim the SOM tree to a subset specified in
        >the path given as an argument. When processing the inner array, it
        >seems I cannot match it to its parent element, a key requirement.
        >When the documentation says that the SOAP::SOM
        >methods "match", "dataof", and "valeuof" take a simple XPATH type
        >syntax, I expected to be able to specify something like
        >
        > '//A[1]/B[1]'
        >
        >to get the first B element nested within the first A element. Alas, I
        >cannot. Can this be a formal request for an enhancement? In the
        >meantime, I either need to look at creating a custom deserializer,
        >or - heaven forbid - another language.
        >
        One way is to iterate through the children at each level, like this:

        my $xml = <<'END';
        <root>
        <A>
        <B>q</B>
        <B>r</B>
        </A>
        <C>c stuff </C>
        <A>
        <B>x</B>
        <C>c stuff </C>
        <B>y</B>
        </A>
        </root>
        END

        my $som = SOAP::Deserializer->deserialize($xml);
        # Iterate through all child elements of <root>
        for ($i = 1; my $a = $som->dataof("/root/[$i]"); $i++) {
        next unless $a->name eq 'A';
        # Iterate through all child elements of the current <A> element
        for ($j = 1; my $b = $som->dataof("/root/[$i]/[$j]"); $j++) {
        next unless $b->name eq 'B';
        print $b->value, "\n";
        }
        }

        prints

        q
        r
        x
        y

        Regards
        Duncan
      • teden
        Duncan, Thanks, you pushed me through my Mental Block... Here is how I ended up doing it: #!/opt/perl5.6/bin/perl # Pragmas use strict; use warnings; # Perl
        Message 3 of 6 , Oct 9, 2003
        • 0 Attachment
          Duncan,

          Thanks, you pushed me through my Mental Block...

          Here is how I ended up doing it:

          #!/opt/perl5.6/bin/perl

          # Pragmas
          use strict;
          use warnings;

          # Perl Module imports
          use SOAP::Lite;

          my $xml = <<EOF;
          <person>
          <address>
          <addressType>Business</addressType>
          <addressLineList>
          <addressLine>100 Main St.</addressLine>
          <addressLine>Suite 32</addressLine>
          </addressLineList>
          </address>
          <address>
          <addressType>Home</addressType>
          <addressLineList>
          <addressLine>100 Jones Dr.</addressLine>
          <addressLine>Apt 1-Y</addressLine>
          </addressLineList>
          </address>
          </person>
          EOF

          my $som = SOAP::Deserializer->deserialize($xml);
          print "<person>", "\n";
          # Iterate through all child elements of <root>
          for (my $i = 1; my $a = $som->dataof("//person/[$i]"); $i++) {
          print " <", $a->name, ">", "\n";
          for (my $j = 1; my $b = $som->dataof("//person/[$i]/[$j]");
          $j++) {
          print " <", $b->name, ">";
          if ($b->name eq 'addressLineList') {
          print "\n";
          for (my $k = 1; my $c = $som->dataof
          ("//person/[$i]/[$j]/[$k]"); $k++) {
          print " <", $c->name, ">", $c-
          >value, "</", $c->name, ">", "\n";
          }
          } else {
          print $b->value, "</", $b->name, ">", "\n";
          next;
          }
          print " </", $b->name, ">", "\n";
          }
          print " </", $a->name, ">", "\n";
          }
          print "</person>", "\n";

          exit 0;


          Your pointer definitely pushed me in the right direction!

          I will echo the sentiment that it would be great if SOAP::SOM->match,
          dataof and valueof took a more robust set of XPath statements. I was
          prepared to do

          $som->match('//person/address[$i]/addressLineList/addressLine')

          so I can loop through those records, all the while knowing I was on
          the $i-th "address" record...

          Thom Eden
          --- In soaplite@yahoogroups.com, "Duncan Cameron"
          <duncan_cameron2002@y...> wrote:
          > At 13:21:00 on 2003-10-08 teden <the@d...> wrote:
          >
          > >Ok,
          > >
          > >I am beginning to get it. My code below is doing exactly what I
          asked
          > >it to - get the som tree for all A elements, then get the som tree
          > >for all B elements. What I want are all the B elements for a given
          A
          > >element. It seems I cannot do what it is I want to do. SOAP::SOM->
          > >match, dataof and valueof trim the SOM tree to a subset specified
          in
          > >the path given as an argument. When processing the inner array, it
          > >seems I cannot match it to its parent element, a key requirement.
          > >When the documentation says that the SOAP::SOM
          > >methods "match", "dataof", and "valeuof" take a simple XPATH type
          > >syntax, I expected to be able to specify something like
          > >
          > > '//A[1]/B[1]'
          > >
          > >to get the first B element nested within the first A element.
          Alas, I
          > >cannot. Can this be a formal request for an enhancement? In the
          > >meantime, I either need to look at creating a custom deserializer,
          > >or - heaven forbid - another language.
          > >
          > One way is to iterate through the children at each level, like this:
          >
          > my $xml = <<'END';
          > <root>
          > <A>
          > <B>q</B>
          > <B>r</B>
          > </A>
          > <C>c stuff </C>
          > <A>
          > <B>x</B>
          > <C>c stuff </C>
          > <B>y</B>
          > </A>
          > </root>
          > END
          >
          > my $som = SOAP::Deserializer->deserialize($xml);
          > # Iterate through all child elements of <root>
          > for ($i = 1; my $a = $som->dataof("/root/[$i]"); $i++) {
          > next unless $a->name eq 'A';
          > # Iterate through all child elements of the current <A> element
          > for ($j = 1; my $b = $som->dataof("/root/[$i]/[$j]"); $j++) {
          > next unless $b->name eq 'B';
          > print $b->value, "\n";
          > }
          > }
          >
          > prints
          >
          > q
          > r
          > x
          > y
          >
          > Regards
          > Duncan
        • Duncan Cameron
          ... Not pretty but it does what you need. ... If this approach gets too much, you can extract the SOAP envelope using - outputxml(1) and then use an XPath
          Message 4 of 6 , Oct 10, 2003
          • 0 Attachment
            At 14:57:00 on 2003-10-09 teden <the@...> wrote:

            >Duncan,
            >
            >Thanks, you pushed me through my Mental Block...
            >
            >Here is how I ended up doing it:
            >
            >#!/opt/perl5.6/bin/perl
            >
            ># Pragmas
            >use strict;
            >use warnings;
            >
            ># Perl Module imports
            >use SOAP::Lite;
            >
            >my $xml = <<EOF;
            ><person>
            > <address>
            > <addressType>Business</addressType>
            > <addressLineList>
            > <addressLine>100 Main St.</addressLine>
            > <addressLine>Suite 32</addressLine>
            > </addressLineList>
            > </address>
            > <address>
            > <addressType>Home</addressType>
            > <addressLineList>
            > <addressLine>100 Jones Dr.</addressLine>
            > <addressLine>Apt 1-Y</addressLine>
            > </addressLineList>
            > </address>
            ></person>
            >EOF
            >
            >my $som = SOAP::Deserializer->deserialize($xml);
            >print "<person>", "\n";
            ># Iterate through all child elements of <root>
            >for (my $i = 1; my $a = $som->dataof("//person/[$i]"); $i++) {
            > print " <", $a->name, ">", "\n";
            > for (my $j = 1; my $b = $som->dataof("//person/[$i]/[$j]");
            >$j++) {
            > print " <", $b->name, ">";
            > if ($b->name eq 'addressLineList') {
            > print "\n";
            > for (my $k = 1; my $c = $som->dataof
            >("//person/[$i]/[$j]/[$k]"); $k++) {
            > print " <", $c->name, ">", $c-
            >>value, "</", $c->name, ">", "\n";
            > }
            > } else {
            > print $b->value, "</", $b->name, ">", "\n";
            > next;
            > }
            > print " </", $b->name, ">", "\n";
            > }
            > print " </", $a->name, ">", "\n";
            >}
            >print "</person>", "\n";
            >
            >exit 0;
            >
            >
            Not pretty but it does what you need.

            >Your pointer definitely pushed me in the right direction!
            >
            >I will echo the sentiment that it would be great if SOAP::SOM->match,
            >dataof and valueof took a more robust set of XPath statements. I was
            >prepared to do
            >
            > $som->match('//person/address[$i]/addressLineList/addressLine')
            >
            >so I can loop through those records, all the while knowing I was on
            >the $i-th "address" record...
            >
            If this approach gets too much, you can extract the SOAP envelope using

            ->outputxml(1)

            and then use an XPath processor, such as XML::XPath or XML::LibXML,
            to find the nodes that you want.

            Regards
            Duncan
          Your message has been successfully submitted and would be delivered to recipients shortly.