Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

Parsing xml string from a text field

Avatar

Level 2

I'm calling a webservice that returns a string in XML format as follow:

<TemplateList>

<Template>

  <ID>0</ID>

  <Category>

   <Name>Mine now</Name>

   <Product>

    <ID>0</ID>

    <Description>INSOLE HEEL CUP BLUE STAR JR. </Description>

    <HDMSProductId>227</HDMSProductId>

    <LawsonId>216156</LawsonId>

    <PopupMessage />

    <Price />

   </Product>

  </Category>

  <Category>

   <Name>Old New</Name>

   <Product>

    <ID>0</ID>

    <Description>TUBING PEDI-FOAM SLEEVE SMALL </Description>

    <HDMSProductId>224</HDMSProductId>

    <LawsonId>216152</LawsonId>

    <PopupMessage />

    <Price />

   </Product>

  </Category>

  <Category>

   <Name>Four Legs</Name>

   <Product>

    <ID>0</ID>

    <Description>TUBING PEDI-FOAM SLEEVE SMALL </Description>

    <HDMSProductId>224</HDMSProductId>

    <LawsonId>216152</LawsonId>

    <PopupMessage />

    <Price />

   </Product>

  </Category>

  <Category>

   <Name>Mind</Name>

   <Product>

...etc.

   </Product>

  </Category>

</Template>

</TemplateList>

I'm trying to drill down to retrieve data from this string. What is the best way to do this in LC Designer form?

I tried to bind the result to a textbox and use applyXPath but it's tricky when there are more than 1 product to iterate through. Suggestions & Examples are greatly appreciated!

1 Accepted Solution

Avatar

Correct answer by
Level 10

Hi,

How are you calling the webservice.  If you are using a data connection then you would normally bind a field to the result (even if that field was hidden).  If you are using NET.SOAP then by default you will get a JavaScript object back.

But to answer your question you could use E4X

 

var responseString = "<TemplateList><Template><ID>0</ID><Category><Name>Mine now</Name><Product><ID>0</ID><Description>INSOLE HEEL CUP BLUE STAR JR. </Description><HDMSProductId>227</HDMSProductId><LawsonId>216156</LawsonId><PopupMessage /><Price /></Product></Category><Category><Name>Old New</Name><Product><ID>0</ID><Description>TUBING PEDI-FOAM SLEEVE SMALL </Description><HDMSProductId>224</HDMSProductId><LawsonId>216152</LawsonId><PopupMessage /><Price /></Product></Category><Category><Name>Four Legs</Name><Product><ID>0</ID><Description>TUBING PEDI-FOAM SLEEVE SMALL </Description><HDMSProductId>224</HDMSProductId><LawsonId>216152</LawsonId><PopupMessage /><Price /></Product></Category></Template></TemplateList>";

var responseXML = new XML(responseString);

for each (var category in responseXML.Template.Category)

{

console.println(category.Name + "  " + category.Product.Description);

}

Regards

Bruce

View solution in original post

8 Replies

Avatar

Correct answer by
Level 10

Hi,

How are you calling the webservice.  If you are using a data connection then you would normally bind a field to the result (even if that field was hidden).  If you are using NET.SOAP then by default you will get a JavaScript object back.

But to answer your question you could use E4X

 

var responseString = "<TemplateList><Template><ID>0</ID><Category><Name>Mine now</Name><Product><ID>0</ID><Description>INSOLE HEEL CUP BLUE STAR JR. </Description><HDMSProductId>227</HDMSProductId><LawsonId>216156</LawsonId><PopupMessage /><Price /></Product></Category><Category><Name>Old New</Name><Product><ID>0</ID><Description>TUBING PEDI-FOAM SLEEVE SMALL </Description><HDMSProductId>224</HDMSProductId><LawsonId>216152</LawsonId><PopupMessage /><Price /></Product></Category><Category><Name>Four Legs</Name><Product><ID>0</ID><Description>TUBING PEDI-FOAM SLEEVE SMALL </Description><HDMSProductId>224</HDMSProductId><LawsonId>216152</LawsonId><PopupMessage /><Price /></Product></Category></Template></TemplateList>";

var responseXML = new XML(responseString);

for each (var category in responseXML.Template.Category)

{

console.println(category.Name + "  " + category.Product.Description);

}

Regards

Bruce

Avatar

Level 2

Hello Bruce:

Thanks for the suggestion. I'm able to get to the content that I need using double loop for cases that have more than one Product in a Category. Now I'm trying to add the content in a dynamic table with the following code. However, the data populated in is all empty. Please advise. Did I miss a syntax else where?

for each (var category in responseXML.Template.Category)

      for each (var product in category.Product)

           Table._Repeat.addInstance();

           xfa.resolveNode("Table.Repeat[" + i + "].Description").rawValue = product.Description

           xfa.resolveNode("Table.Repeat[" + i + "].LawsonID").rawValue = product.LawsonId;

           xfa.resolveNode("Table.Repeat[" + i + "].Price").rawValue = product.Price;

           i++;

Avatar

Level 2

Looks like I can get to the data like this:

for each (var category in responseXML.Template.Category)

     for each (var product in category.Product)

         var description = product.Description;

        xfa.resolveNode("Table.Repeat["+i+"].Description").rawValue = description.toString();

        var lawsonID = product.LawsonId;

         xfa.resolveNode("Table.Repeat["+i+"].LawsonID").rawValue = lawsonID.toString();

        var price = product.Price;

        xfa.resolveNode("Table.Repeat["+i+"].Price").rawValue = price.toString();

        i++;

Thanks for your help!

Avatar

Level 10

Hi,

I am not sure how you are adding the rows to your table, it looks like this forum has played around with your code, have some braces been removed?

Anyway, another way would be;


for each (var category in responseXML.Template.Category)


{


for each (var product in category.Product)


{


var newRow = Table1._Repeat.addInstance();     


newRow.Description.rawValue = product.Description.toString();     


newRow.LawsonID.rawValue = product.LawsonId.toString();     


newRow.Price.rawValue = product.Price.toString();


}


}


Regards

Bruce

Avatar

Level 2

Hi Bruce:

I appreciate your follow up! This code looks a lot cleaner!!! (yeah, some how my brackets were taken out when I copy/paste the code in here).

I have a couple more questions relate to table manipulation, if you don't mind. Otherwise, I can start a new post.

It looks like there is an extra row got inserted into the table. I tried to use Table1.Repeat.instanceManager.setInstances(1) prior to the for loop and it cleared out the data from selection to selection, but the extra row still on there. Any suggestion?

759590_pastedImage_1.png

Another question I have has to do with bringing all the Category, Description, ID, Price for all items that has Qty>0 and populate on the 2nd page for summary & calculation. The tricky part is not bringing them all down, but only the one that actually has Qty>0. If I'm writing an event on Qty exit, what is the best way for me to access the other items associate with this Qty?

The logic I have in mind for this is to have a hidden column that generates a sequence of number 1-2-3-4-5...as new row is added. Then on exist of Qty if >0, add a new row to the table on 2nd page with rawValue of all data on nth row of the Qty. Any other thoughts?

Avatar

Level 10

Hi,

You should be able to use Table1.Repeat.instanceManager.setInstances(0), as long as you set the Min Count to zero on the Binding tab of the Object palette for you repeating row.

I would generate the summary table in it's calculate event, so the code would look something like;


form1.#subform[0].Table2::calculate - (JavaScript, client)


Table2._Repeat.setInstances(0);


var rows = Table1.resolveNodes("Repeat[*]");


for (var i = 0; i < rows.length; i++)


{


    var row = rows.item(i);


    if (row.Qty.rawValue > 0)


    {


        var category;


        for (var j = i - 1; j >= 0; j--)


        {


            if (!rows.item(j).Category.isNull)


            {


                category = rows.item(j).Category.rawValue;


                break;


            }


        }


        var newRow = Table2._Repeat.addInstance();


        newRow.Category = category;


        var newRow = Table2._Repeat.addInstance();


        newRow.Description.rawValue = row.Description.rawValue;


        newRow.LawsonID.rawValue = row.LawsonID.rawValue;


        newRow.Qty.rawValue = row.Qty.rawValue;


    }


}


My sample to check this code can be downloaded here, https://sites.google.com/site/livecycledesignercookbooks/home/SummaryTable.pdf?attredirects=0&d=1

Using the calculate event to regenerate the whole table means you don't have to try and link the rows from one table to the other.  This is probably more expensive in processing time but I've not found it unresponsive.

Regards

Bruce

Avatar

Level 2

Thanks Bruce! You're so thorough. Thanks for the advice. The code works, but it just doesn't work very well with whatever the setting I'm having right now on the form. I don't know if it has to do with ES4 or not, but Min Count is set to 1 as a default. When I change it to 0, the table doesn't repeat. Thus, it can't populate the data. You set the Min Count on the Repeat row right, not the main Table? I tried various options but doesn't work. I had to use Table1.Repeat.instanceManager.setInstances(1) because the table wouldn't populate when I use Table1.Repeat.instanceManager.setInstances(0) with Min Count set to 0 or 1. Because of the extra row, the code doesn't seem to run until Qty>0 occurs on the first extra row. If I put in Qty>0 anywhere else on the next rows, nothing happens.

759993_pastedImage_1.png

759892_pastedImage_0.png

Avatar

Level 2

I don't know if this is the right way of doing it, but I found a way that work. I ended up manipulating the first empty row by calling the RemoveInstance(0) at the end, outside of the for loop, after I iterate through and added all the data into the table. That seems to work. Once again, thanks for all your inputs! You've done wonders!