Question
Andy Stobirski · Nov 23

Not all XML child items are loaded into a class list when using XML.Reader correlate

Hi all

I'm new to ObjectScript and I've been experimenting the correlate method of %XML.Reader to convert an XML file I've loaded into its corresponding class. But, I have found that I am not getting all the child items of an element in a List contained within the converted class, only the last item.

The XML file content is as follows:

<Results>
  <PersonIDs>
    <PersonID>1000000</PersonID>
    <PersonID>1000001</PersonID>
    <PersonID>1000005</PersonID>
  </PersonIDs> 
</Results>

I have two classes: the parent SearchResultsMessage contains a List Of the child class PersonID, as shown below. This code is simplified and has had various non-relevant bits removed.

Class GMMHTIE.ParisConnect.WebClient.Messages.Response.PersonSearchResultsMessage Extends (%Persistent, %XML.Adaptor)
{
   Property PersonIDs As list Of PersonID(XMLNAME = "PersonIDs", XMLPROJECTION = "ELEMENT"); 
}

Class PersonID Extends (%Persistent, %XML.Adaptor)
{ 
    Property PersonID As %String(XMLNAME = "PersonID", XMLPROJECTION = "ELEMENT");
}

So, when I use correlate I have a class instance for SearchResultsMessage and I can confirm that it is picking up other properties correctly (which are not shown), but the property PersonIDs only contains one item, the last 1000005.

This is the code I'm using, which is abridged for brevity:

Set reader = ##class(%XML.Reader).%New()
  Set sc=reader.OpenString(Set reader = ##class(%XML.Reader).%New()
  Set sc=reader.OpenString(pInput)
 
  Do reader.Correlate("Results","PersonSearchResultsMessage") 
  While reader.Next(.convertedMessage,.sc) {
// success
!,"Count(): "_convertedMessage.PersonIDs.Count() 
        // A value of one is returned, expecting 3
   }

Can anyone help - what am I missing?

Cheers

Andy

Product version: IRIS 2020.1
$ZV: IRIS for Windows (x86-64) 2020.1 (Build 215U) Mon Mar 30 2020 20:14:33 EDT
00
1 0 6 124
Log in or sign up to continue

When you're projecting a list of a class to XML, you usually have a parent element for each of those objects, then a separate element for each of it's properties. So I think what you'd need to do would be something more like:

<Results>
    <PersonIDs>
        <PersonID>
            <PersonID>1000000</PersonID>
        </PersonID>
        <PersonID>  
            <PersonID>1000001</PersonID>
        </PersonID>  
        <PersonID>  
            <PersonID>1000005</PersonID>
        </PersonID>  
    </PersonIDs> 
</Results>

So that the outer PersonID element indicates your PersonID object, and the PersonID inside of that is the PersonID property of that object.

Hi David,

That's interesting, however, the XML file I am receiving is outputted from a web API and so I can't change it.

Thanks for taking the time to reply, though.

Andy

In that case, does it meet your needs to make it a list of %String instead of making a separate class?

I'll give it a try - how would I do that, I'm still new to objectscript at the moment.

Making the following change

Property PersonIDs As list Of %String(XMLNAME = "PersonIDs", XMLPROJECTION = "ELEMENT");

Results in an error of:

ERROR #6232: Datatype validation failed for tag, PersonIDs (ending at line 9 character 15), with value:
1

Try it like this:

Class User.ResultsMessage Extends (%Persistent, %XML.Adaptor)
{

Property PersonIDs As list Of %String(XMLITEMNAME = "PersonID", XMLNAME = "PersonIDs", XMLPROJECTION = "WRAPPED");

XData Data
{
<Results>
  <PersonIDs>
    <PersonID>1000000</PersonID>
    <PersonID>1000001</PersonID>
    <PersonID>1000005</PersonID>
  </PersonIDs> 
</Results>
}

/// do ##class(User.ResultsMessage).Test()
ClassMethod Test()
{
	Set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "Data").Data
	Set reader = ##class(%XML.Reader).%New()
	Set sc=reader.OpenStream(text)

	Do reader.Correlate("Results","User.ResultsMessage") 
	While reader.Next(.msg,.sc) {
		Write !,"Count(): "_msg.PersonIDs.Count(),!
	}
	Write:$$$ISERR(sc) $System.Status.GetErrorText(sc)
}
}

Docs.

Thank you so much, that's perfect!