Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug or feature? XML reply with 1 entry behaves differently with n entries #21

Open
andreasba opened this issue Jan 18, 2016 · 6 comments

Comments

@andreasba
Copy link

Good morning,

I am not sure whether this is a bug or a feature or if I am using Parser in a wrong way.

Take the following XML:

<?xml version="1.0"?>
<GetFeedSubmissionListResponse xmlns="http://mws.amazonaws.com/doc/2009-01-01/">
  <GetFeedSubmissionListResult>
    <HasNext>false</HasNext>
    <FeedSubmissionInfo>
      <FeedProcessingStatus>_IN_PROGRESS_</FeedProcessingStatus>
      <FeedType>_POST_FBA_INBOUND_CARTON_CONTENTS_</FeedType>
      <FeedSubmissionId>40737016817</FeedSubmissionId>
      <StartedProcessingDate>2016-01-17T21:13:27+00:00</StartedProcessingDate>
      <SubmittedDate>2016-01-17T21:12:53+00:00</SubmittedDate>
    </FeedSubmissionInfo>
    <FeedSubmissionInfo>
      <FeedProcessingStatus>_DONE_</FeedProcessingStatus>
      <FeedType>_POST_FBA_INBOUND_CARTON_CONTENTS_</FeedType>
      <FeedSubmissionId>40736016817</FeedSubmissionId>
      <StartedProcessingDate>2016-01-17T21:12:38+00:00</StartedProcessingDate>
      <SubmittedDate>2016-01-17T21:12:06+00:00</SubmittedDate>
      <CompletedProcessingDate>2016-01-17T21:13:13+00:00</CompletedProcessingDate>
    </FeedSubmissionInfo>
    <FeedSubmissionInfo>
      <FeedProcessingStatus>_DONE_</FeedProcessingStatus>
      <FeedType>_POST_FBA_INBOUND_CARTON_CONTENTS_</FeedType>
      <FeedSubmissionId>40735016817</FeedSubmissionId>
      <StartedProcessingDate>2016-01-17T21:07:07+00:00</StartedProcessingDate>
      <SubmittedDate>2016-01-17T21:07:01+00:00</SubmittedDate>
      <CompletedProcessingDate>2016-01-17T21:07:53+00:00</CompletedProcessingDate>
    </FeedSubmissionInfo>
    <FeedSubmissionInfo>
      <FeedProcessingStatus>_DONE_</FeedProcessingStatus>
      <FeedType>_POST_FBA_INBOUND_CARTON_CONTENTS_</FeedType>
      <FeedSubmissionId>40734016817</FeedSubmissionId>
      <StartedProcessingDate>2016-01-17T19:04:13+00:00</StartedProcessingDate>
      <SubmittedDate>2016-01-17T19:03:55+00:00</SubmittedDate>
      <CompletedProcessingDate>2016-01-17T19:04:54+00:00</CompletedProcessingDate>
    </FeedSubmissionInfo>
  </GetFeedSubmissionListResult>
  <ResponseMetadata>
    <RequestId>608dc493-ca8a-4b4d-99a5-7775269e2ac6</RequestId>
  </ResponseMetadata>
</GetFeedSubmissionListResponse>

If I parse this using

$responseItems = $requestStatus->parsedResponse['GetFeedSubmissionListResult']['FeedSubmissionInfo'];

my $responseItems contain an array of four items from $responseItems[0] to $responseItems[3] where I can access all attributes like FeedSubmissionId for example like $responseItems[1]['FeedSubmissionId'] - perfect.

However, if the XML response only has ONE FeedSubmissionInfo item, like this:

<?xml version="1.0"?>
<GetFeedSubmissionListResponse xmlns="http://mws.amazonaws.com/doc/2009-01-01/">
  <GetFeedSubmissionListResult>
    <HasNext>false</HasNext>
    <FeedSubmissionInfo>
      <FeedProcessingStatus>_IN_PROGRESS_</FeedProcessingStatus>
      <FeedType>_POST_FBA_INBOUND_CARTON_CONTENTS_</FeedType>
      <FeedSubmissionId>40737016817</FeedSubmissionId>
      <StartedProcessingDate>2016-01-17T21:13:27+00:00</StartedProcessingDate>
      <SubmittedDate>2016-01-17T21:12:53+00:00</SubmittedDate>
    </FeedSubmissionInfo>
  </GetFeedSubmissionListResult>
  <ResponseMetadata>
    <RequestId>608dc493-ca8a-4b4d-99a5-7775269e2ac6</RequestId>
  </ResponseMetadata>
</GetFeedSubmissionListResponse>

Then $responseItems[0]['FeedSubmissionId'] throws an illegal offset error, since the parser (of course?) parsed the response not like $responseItems[0]['FeedSubmissionId'] but like this: $responseItems['FeedSubmissionId'].

Now I am wondering if this is a bug or works as designed?

And what would be the workaround? Convert the whole xml to a collection and then work with that?

Thanks
Andreas

@danhunsaker
Copy link
Contributor

The parser has no way of telling whether a value is meant to be an array unless it has multiple elements with the same names in the XML document. The workaround (if you haven't found it already) is to cast the value to an array when you retrieve it:

$responseItems = (array) $requestStatus->parsedResponse['GetFeedSubmissionListResult']['FeedSubmissionInfo'];

@wallacio
Copy link

wallacio commented May 7, 2018

I haven't found a sensible solution to this. Casting to an array is pointless if there is more than one element in the child node, because it already is itself an array.

@andreasba - I know your post was a long time ago but did you find a workaround?

@Gummibeer
Copy link

The only workaround I could think about is testing it yourself:

$responseItems = $requestStatus->parsedResponse['GetFeedSubmissionListResult']['FeedSubmissionInfo'];
if(!isset($responseItems[0])) {
    $responseItems[0] = $responseItems;
}

@wallacio
Copy link

wallacio commented May 7, 2018

Here is my workaround. Not sure how safe this is, but it's working for the cases I've tested.

    /**
     * Helper function. The XML Parser doesn't handle cases where there 
     * can be one or more elements of the same name in the structure.
     * In the case of a single element, it returns an array of child keys and in the case of multiple elements, it returns an indexed array of arrays of child keys.
     * This function forces an indexed array of arrays of child keys, even if there's only one element.
     * 
     * @param mixed $nodes The parent element containing one or more elements of the same name
     * @param string $key The name of the child element
     * @return mixed 
     */
    private static function forceIndexedArray($nodes, $key)
    {
        if(!isset($nodes[$key][0])) {
            return array($key => array(0 => $nodes[$key]));
        } 
        
        return $nodes;
        
    }

For the example in the OP, call it like:

$listResults = static::forceIndexedArray($requestStatus->parsedResponse['GetFeedSubmissionListResult'], 'FeedSubmissionInfo');

You can then (fairly) safely...

foreach ( $listResults['FeedSubmissionInfo'] as $submissionInfo) {
    ...
}

@andreasba
Copy link
Author

@wallacio - the workarounds above are pretty similar to mine :)

@Gummibeer
Copy link

@andreasba I would bet that there isn't another option. :/
And I have to agree with @danhunsaker that there is no way for the package to know if it has to be a wrapped array or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants