Subscribe for automatic updates: RSS icon RSS

Login icon Sign in for full access | Help icon Help
Advanced search

Pages: [1]
  Reply  |  Print  
Author Topic: properly handle complex Xml data  (Read 13778 times)
francesco f.
Posts: 16


« on: September 13, 2022, 11:59:07 pm »

Hi Everyone,
we got a new client that work with complex xml file generated from sap, so we need to load them and in turn create our xml.
It's the first time we work in xml with genero and we would like to know what's the best suitable option available right now that can provide flexibility and at the same time be relatively easy to use.

we looked into xml.DomDocument and xml.Serializer and both seems to offer cool features.
we also throw a cursory glance to https://github.com/FourjsGenero to find some snippets to start from but so far found none.

Can someone offer some help please just to put us on the right track?
Just to know if there are some real life examples to look from some online repositories

So far we tested successfully the validator  at https://4js.com/online_documentation/fjs-fgl-manual-html/index.html#fgl-topics/c_gws_XML_DomDocument_class_016.html

We would really appreciate

Francesco

Reuben B.
Four Js
Posts: 1116


« Reply #1 on: September 15, 2022, 05:58:01 am »

My advice would be if not familiar with XML to use resources such as what you can find at w3schools https://www.w3schools.com/xml/ and note what they have about DOM https://www.w3schools.com/xml/xml_dom.asp and XPath https://www.w3schools.com/xml/xml_xpath.asp

There are two xml libraries in Genero.

The smaller om package http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_Class_om.html has been in Genero since its inception.  Its purpose was to provide a means for developers to interact with the AUI Tree http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_DynamicUI_006.html .  At beginning of Genero there were no methods to show/hide fields, you did this by yourself manipulating the AUI Tree (XML) as an example such as  https://github.com/FourjsGenero/fgl_auitree/blob/master/auitree.4gl#L64, or creating a form, an XML document https://github.com/FourjsGenero/fgl_zoom/blob/master/fgl_zoom.4gl#L1270   The om package is effectively a cut-down xml library as it is just what we felt back in 2000 what was necessary to manipulate the XML AUI Tree.

The fully fledged XML package http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_XML_Library_001.html was added to Genero in the 2.10 release  in 2007 and has full XML functionality.

You will probably find early adopters of Genero met their XML needs and learnt XML by using the om package rather than the xml package, until they found there was something they needed that was only in the XML package e.g.namespaces, complex XPath, working with different types of node, serialization, xslt etc and then it was a case of applying their om skills to xml  http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_OM_to_XML_001.html

Otherwise the XML topic is quite broad and you may get a better response if asking a more specific question around what you are trying to do.  Wether thats reading an XML document into 4gl variable, or traversing to find and change a particular value in the XML, or creating XML document from a 4gl variable etc. OR perhaps your question might be around some of these examples  https://www.w3schools.com/xml/dom_examples.asp and your question might be what is Genero equivalent?

Reuben







 






Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
francesco f.
Posts: 16


« Reply #2 on: September 15, 2022, 11:04:12 am »

Hi Reuben,
thanks for your reply.

I just was looking for some genero example to follow but in the end it seems no too complicated as it seemed at first impression.
I'm using the fully fledged xml package.
Basically  i need to flatten the files and the two methods i'm using the most are a selectByXPath to traverse the dom and arrive where i need and then a series of getElementsByTagName for the tag needed from that node and it seems to work.
I Made a two arguments func to which i pass the xpath and the tokenizeble tags.













Roland W.
Posts: 22


« Reply #3 on: September 19, 2022, 02:19:40 pm »

Hello Francesco,

I'm not sure what your XML file looks like but I've made good experiences with the following approach for flatteing a BMECat file (https://help.sap.com/docs/ARIBA_NETWORK_SUPPLIERS/c8ad7036e6104bfaa33ec523991a6727/65b815e1ae724ce38d02b0fb9faefc7d.html?locale=en-US) to a dynamic array.
Code
  1. type dt_boolean  boolean,
  2.      dt_count    integer,
  3.      dt_datetime string,
  4.      dt_datetype date,
  5.      dt_duration string,
  6.      dt_float    float,
  7.      dt_integer  integer,
  8.      dt_lang     char(3),
  9.      dt_string   string,
  10.  
  11.      t_new_catalog record
  12.                     attr_prev_version           dt_integer,
  13.                     feature_system              t_feature_system,
  14.                     classification_system       dynamic array of t_classification_system,
  15.                     catalog_group_system        t_catalog_group_system,
  16.                     formulas                    t_formulas,
  17.                     ipp_definitions             t_ipp_definitions,
  18.                     product                     dynamic array of t_product,
  19.                     product_to_cataloggroup_map dynamic array of t_product_to_cataloggroup_map,
  20.                     article                     dynamic array of t_article,
  21.                     article_to_cataloggroup_map dynamic array of t_article_to_cataloggroup_map
  22.                    end record,
  23.      t_update_products record
  24.                         attr_prev_version           dt_integer,
  25.                         formulas                    t_formulas,
  26.                         product                     dynamic array of t_product,
  27.                         product_to_cataloggroup_map dynamic array of t_product_to_cataloggroup_map,n
  28.                         article                     dynamic array of t_article,
  29.                         article_to_cataloggroup_map dynamic array of t_article_to_cataloggroup_map
  30.                        end record,
  31.      t_update_prices record
  32.                       attr_prev_version dt_integer,
  33.                       formulas          t_formulas,
  34.                       product           dynamic array of t_product,
  35.                       article           dynamic array of t_article
  36.                      end record
  37.  
  38. type t_bmecat record   # root element
  39.                attr_version    dt_string,
  40.                header          t_header,
  41.                new_catalog     t_new_catalog,
  42.                update_products t_update_products,
  43.                update_prices   t_update_prices
  44.               end record
  45.  
  46. define l_xml    xml.domdocument,
  47.        l_bmecat t_bmecat
  48.  
  49. if ((l_xml := xml.domdocument.create()) is not null)
  50. then try
  51.       call l_xml.load("/path/to/xml-file.xml")
  52.      catch
  53.       if (l_xml.geterrorscount() > 0)
  54.       then for i = 1 to l_xml.geterrorscount()
  55.             error sfmt("error %1: %2", i, l_xml.geterrordescription(i))
  56.            end for
  57.       else error fmt("error while loading XML file %1", l_filename)
  58.       end if
  59.      end try
  60.      message "parsing BMECat-data..."
  61.      call parse_bmecat(l_xml) returning l_bmecat.*
  62. end if
  63. ...
  64.  
  65. public function parse_bmecat (l_xml xml.domdocument)
  66.  returns (t_bmecat)
  67.  
  68. define l_bmecat t_bmecat,
  69.        l_node   xml.domnode
  70.  
  71. initialize l_bmecat to null
  72. if (l_xml.getdocumentnodescount() > 0)
  73. then if ((l_node := l_xml.getfirstdocumentnode()) is not null)
  74.      then while (l_node.getnodetype() <> "ELEMENT_NODE")
  75.            let l_node = l_node.getnextsibling()
  76.           end while
  77.           if (l_node is not null)
  78.           then if (l_node.getlocalname() == "BMECAT")
  79.                then if l_node.hasattribute("version")
  80.                     then let l_bmecat.attr_version = l_node.getattribute("version")
  81.                          let l_node = l_node.getfirstchild()
  82.                          while (l_node is not null)
  83.                           case l_node.getlocalname()
  84.                            when "HEADER"
  85.                             call parse_header(l_node) returning l_bmecat.header.*
  86.                            when "T_NEW_CATALOG"
  87.                             call parse_t_new_catalog(l_node) returning l_bmecat.new_catalog.*
  88.                            when "T_UPDATE_PRODUCTS"
  89.                             call parse_t_update_products(l_node) returning l_bmecat.update_products.*
  90.                            when "T_UPDATE_PRICES"
  91.                             call parse_t_update_prices(l_node) returning l_bmecat.update_prices.*
  92.                            when "#comment"
  93.                            when "#text"
  94.                            otherwise
  95.                             message sfmt("unknown Element %1", l_node.getlocalname())
  96.                           end case
  97.                           let l_node = l_node.getnextsibling()
  98.                          end while
  99.                     else error "BMECAT Attribute version missing!"
  100.                     end if
  101.                else error "no valid BMECat file!"
  102.                end if
  103.           end if
  104.      else error "no valid BMECat file!"
  105.      end if
  106. else error "not valid BMECat file!"
  107. end if
  108. return l_bmecat.*
  109. end function
  110.  

The type t_bmecat is formed recursively from the subelements and is not described here because the full definition is too long. The routines for parsing the individual sub-elements have essentially the same structure as the function above and only need to be adapted with regard to the elements used.
Each function will traverse one element from top to bottom and read the contents into the corresponding entry within the array. I'm not sure if this is the best, easiest, most elegant or most performant way but it works quite good.

Maybe this small code snippet will help you further.

Good luck and kind regards
Roland
francesco f.
Posts: 16


« Reply #4 on: September 20, 2022, 03:19:23 pm »

Hi Roland,
thanks for your time.

That's the kind of example i was looking for: practical and clear.
At the beginning i was baffled because they send a lot of useless tags (ie 136kb of data for one useful record of product list, can you imagine?) so i had to traverse the dom to reach the points of interest and grab the few tags i needed,  so i realized a func with two argument: a selectbyxpath and a series of selectbytagname within loop to grab some of the header tags and some of the rows tags.

I bet it's not the most elegant and efficient solution but as long as it does its job i don't care :-)))
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines