Import XML

rash

Member
Hello,
I am using progress webclient10.2A
Run the application in webclient and run the appropriate activity.
Then I am importing a ReadSoft XML file which is located at local PC(at desktop).
It's throwing me an error while importing.
Error reading XML file '/usr/wrk/tmp/_t015586'. (13035)
READ-XML encountered an error while parsing the XML Document: FATAL ERROR: file '/usr/wrk/tmp/_t015586', line '1', column '1', message 'Invalid document structure'. (13064)
 

Attachments

  • import.txt
    15.1 KB · Views: 35

Stefan

Well-Known Member
The XML file is being passed from WebClient to AppServer (how?), does not contain an encoding, and does contain extended characters (QUÉBEC).

So how are you passing the XML file from client to AppServer and what codepages are the client and AppServer using?
 

rash

Member
I have to read the attached XML file.
How I can do that?
 

Attachments

  • Invoice.txt
    12.6 KB · Views: 21

Stefan

Well-Known Member
I have to read the attached XML file.
How I can do that?
Lots of different ways are possible (COPY-LOB, LOAD, READ-XML). It depends on what you mean with read. But what does this have to do with the original question?
 

rash

Member
Actually I am new to XML so I thought the first two lines of XML creating problem.
That's why I wanted to read rest of the XML.
 

Stefan

Well-Known Member
I can import the XML without error:

Code:
DEF VAR hd AS HANDLE NO-UNDO.
CREATE X-DOCUMENT hd.
hd:LOAD( "FILE":U, "c:/temp/import.xml":U, FALSE ).

And also with SAX-READER:

Code:
DEF VAR hs AS HANDLE NO-UNDO.
CREATE SAX-READER hs.
hs:SET-INPUT-SOURCE ( "FILE":U, "c:/temp/import.xml":U ).

And also with COPY-LOB:

Code:
DEF VAR lcc AS LONGCHAR NO-UNDO.

COPY-LOB FROM FILE "c:/temp/import.xml" TO lcc.
 
Can we populate the imported data in a report?
If yes then how?

I was trying to populate the data like:
def
temp-table tt-invoice
field name as charfield identifier as char
field number as int.

def var vl_ok as log no-undo.


vl_ok =
TEMP-TABLE tt-invoice:READ-XML("FILE":U,vl_import-file,"EMPTY",?,?,?,?).

if vl_ok then
do:
for each tt-invoice:
disp tt-invoice.name tt-invoice.identifier tt-invoice-number.
end.
end.

can we populate the data like this?
 

Stefan

Well-Known Member
You can only use READ-XML on a temp-table if the temp-table matches the XML rather exactly. It is highly unlikely that normal XML data will match this. You can view the results of expected XML by using WRITE-XML on a populated temp-table.

The following example uses the SAX-READER to populate a temp-table based on the XML (see documentation for more info). Note that I have never worked with the SAX-READER before, but found it interesting to try, so it may contain silliness - for example needing to keep track of the absolute path within the XML doc seems a bit silly to me:

Code:
DEFINE TEMP-TABLE ttinvoice NO-UNDO
   FIELD cname       AS CHAR
   FIELD cidentifier AS CHAR
   FIELD inumber     AS INT
   .


DEF VAR p_hs        AS HANDLE      NO-UNDO.
DEF VAR p_cxpath    AS CHAR        NO-UNDO.


CREATE SAX-READER p_hs.
p_hs:SET-INPUT-SOURCE( "FILE":U, "c:/temp/import.xml":U ).
p_hs:SAX-PARSE().


FOR EACH ttinvoice:
   DISPLAY ttinvoice.cname ttinvoice.cidentifier ttinvoice.inumber.
END.




PROCEDURE startElement:
   DEFINE INPUT PARAMETER i_cnamespaceuri AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_clocalname    AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_cqname        AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_hattributes   AS HANDLE    NO-UNDO.


    p_cxpath = p_cxpath + "/" + i_clocalname.


   IF p_cxpath = "/Documents/Document/Invoice" THEN DO:
      CREATE ttinvoice.
   END.


END PROCEDURE.


PROCEDURE endElement:
   DEFINE INPUT PARAMETER i_cnamespaceuri AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_clocalname    AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_cqname        AS CHARACTER NO-UNDO.  


   IF p_cxpath = "/Documents/Document/Invoice" THEN DO:
      RELEASE ttinvoice.
   END.


    p_cxpath = SUBSTRING( p_cxpath, 1, R-INDEX( p_cxpath, "/":U ) - 1 ).


END PROCEDURE.


PROCEDURE characters:  
   DEFINE INPUT PARAMETER i_carray        AS LONGCHAR NO-UNDO.  
   DEFINE INPUT PARAMETER i_iarraylength  AS INTEGER  NO-UNDO.


   IF p_cxpath BEGINS "/Documents/Document/Invoice/Supplier/" THEN 
      CASE ENTRY( 6, p_cxpath, "/":U ):
         WHEN "Name":U     THEN ttinvoice.cname       =  i_carray.
         WHEN "Identifier" THEN ttinvoice.cidentifier =  i_carray.
         WHEN "Number"     THEN ttinvoice.inumber     =  INTEGER( i_carray ).
      END CASE.


END PROCEDURE.

You could also create a dynamic temp-table based on your XML file and populate this dynamically.
 

Stefan

Well-Known Member
So read them... If you cannot expand the example I have given you then you should not be programming.
 
I can read those fields as well.
But when I am calling an external procedure to implement the same logic it's throwing me the following error:

SAX parser error: SAX-PARSE-FIRST, Error parsing file: Could not determine base pathname of the file. (14586)
 

Stefan

Well-Known Member
I can read those fields as well.
But when I am calling an external procedure to implement the same logic it's throwing me the following error:

SAX parser error: SAX-PARSE-FIRST, Error parsing file: Could not determine base pathname of the file. (14586)

I do not know what you mean with an external procedure, but I see no reason why the behavior should be different. Search the progress knowledge base for the error, the second entry (DTD resolution) could cover your issue and explains what you should do.
 
CREATE​
SAX-READER hParser.
RUN sax.p PERSISTENTSET hHandler.
hParser:
HANDLER = hHandler.
hParser:
SET-INPUT-SOURCE("FILE", "c:\temp\import.xml").
hParser:SAX-PARSE( ) NO-ERROR.


then external procedure contains all the callbacks routines.

it's not working.

Can you help me?
 

Stefan

Well-Known Member
Why would you want to CREATE the SAX-READER in your .p? I would simply pass the file name to sax.p and let sax.p do all the handling?

With my initial example, the following 'client' code:

Code:
DEF VAR p_hs   AS HANDLE   NO-UNDO.
DEF VAR p_hp   AS HANDLE   NO-UNDO.
RUN c:/temp/sax.p PERSISTENT SET p_hp.
CREATE SAX-READER p_hs.
p_hs:HANDLER = p_hp.
p_hs:SET-INPUT-SOURCE( "FILE":U, "c:/temp/import.xml":U ).
p_hs:SAX-PARSE().
RUN showtt IN p_hp.

And the following 'server' code:

Code:
DEFINE TEMP-TABLE ttinvoice NO-UNDO
   FIELD cname       AS CHAR
   FIELD cidentifier AS CHAR
   FIELD inumber     AS INT
   .
DEF VAR p_cxpath    AS CHAR        NO-UNDO.
PROCEDURE startElement:
   DEFINE INPUT PARAMETER i_cnamespaceuri AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_clocalname    AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_cqname        AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_hattributes   AS HANDLE    NO-UNDO.
   p_cxpath = p_cxpath + "/" + i_clocalname.
   IF p_cxpath = "/Documents/Document/Invoice" THEN DO:
      CREATE ttinvoice.
   END.
END PROCEDURE.
PROCEDURE endElement:
   DEFINE INPUT PARAMETER i_cnamespaceuri AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_clocalname    AS CHARACTER NO-UNDO.  
   DEFINE INPUT PARAMETER i_cqname        AS CHARACTER NO-UNDO.  
   IF p_cxpath = "/Documents/Document/Invoice" THEN DO:
      RELEASE ttinvoice.
   END.
   p_cxpath = SUBSTRING( p_cxpath, 1, R-INDEX( p_cxpath, "/":U ) - 1 ).
END PROCEDURE.

PROCEDURE characters:  
   DEFINE INPUT PARAMETER i_carray        AS LONGCHAR NO-UNDO.  
   DEFINE INPUT PARAMETER i_iarraylength  AS INTEGER  NO-UNDO.

   IF p_cxpath BEGINS "/Documents/Document/Invoice/Supplier/" THEN 
      CASE ENTRY( 6, p_cxpath, "/":U ):
         WHEN "Name":U     THEN ttinvoice.cname       =  i_carray.
         WHEN "Identifier" THEN ttinvoice.cidentifier =  i_carray.
         WHEN "Number"     THEN ttinvoice.inumber     =  INTEGER( i_carray ).
      END CASE.

END PROCEDURE.
PROCEDURE showtt:
   FOR EACH ttinvoice:
      DISPLAY ttinvoice.cname ttinvoice.cidentifier ttinvoice.inumber.
   END.
END PROCEDURE.

It works fine. Note that you will not be able to really consider the server code as server code since it relies on a handles which cannot cross the client / AppServer boundary.
 
Thanks Stefan, Now I have understood the basic working with XML.

Now how to create a API dataset?
I have to assign the XML fields(which we have read) into API dataset.

or can we assign the required XML fields directly into API dataset instead of loading into a temp-table?
 

Stefan

Well-Known Member
Code:
DEFINE VARIABLE APIdataset AS HANDLE.

CREATE APIdataset.

Now go read the manuals or get some training.
 

Stefan

Well-Known Member
You are missing the basic concepts of what a dataset is. You really need to read up on this first. A dataset is simply a collection of temp-tables with some extra functionality thrown in. The size of the collection can be one, ie you can wrap one temp-table in a dataset to get dataset functionality on your temp-table.
 
Top