Re: Parsing xml?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Parsing xml?

Peter Sharp-2
Still in need of tweaking, but the basics are done for a rudimentary
generic XML SAX parser. The results when run against a few varieties of
xml doc I found follow.

[psharp@fedora GenericXMLParser]$ cat ./sample.xml;java TestKeyParser
./sample.xml
<users>
     <user id="100">
         <firstName>John</firstName>
         <lastName>Doe</lastName>
     </user>
     <user id="101">
         <firstName>Jane</firstName>
         <lastName>Doe</lastName>
     </user>
     <user id="102">
         <firstName>HowToDo</firstName>
         <lastName>InNetRexx</lastName>
     </user>
</users>
[users, user.id=100, firstName=John, lastName=Doe, user.id=101,
firstName=Jane, lastName=Doe, user.id=102, firstName=HowToDo,
lastName=InNetRexx]
[psharp@fedora GenericXMLParser]$ cat ./MyProps.xml;java TestKeyParser
./MyProps.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd ">
<properties>
     <comment>application.properties</comment>
     <entry key="input.dir">c:/temp/input</entry>
     <entry key="spring.batch.job.enabled">false</entry>
     <entry key="spring.main.banner-mode">off</entry>
</properties>
[properties, comment=application.properties, entry.key=input.dir,
entry=c:/temp/input, entry.key=spring.batch.job.enabled, entry=false,
entry.key=spring.main.banner-mode, entry=off]
[psharp@fedora GenericXMLParser]$ cat ./append.xml;java TestKeyParser
./append.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd ">
<project name="MyProject" basedir=".">
   <description>
     demonstration of ant jsr223 netrexx scripting
   </description>

   <property name="divider" value="81" />
   <script language="netrexx" manager="javax">
     say "100/"divider '= ' 100/divider
   </script>
</project>
[project.name=MyProject, project.basedir=., description=demonstration of
ant jsr223 netrexx scripting, property.name=divider, property.value=81,
script.language=netrexx, script.manager=javax, script=say "100/"divider
'= ' 100/divider]
[psharp@fedora GenericXMLParser]$

I switched the InputSource in the sample SAXXMLParser from File to
String. Since the ultimate goal is to parse MQFTE logger messages (xml),
converting to a generic String source was logical.

 >> FileToStr.nrx:

--file\FileToStr.nrx

import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException

class FileToStr public

     Properties private
     lines = String

   method loadFile(fileName=String)
     -- read whole file
     is = BufferedReader(FileReader(fileName))
     line=is.readLine()                             -- read first line
     if line \= null then
       this.lines = line.trim()
     line=is.readLine()
     loop while line \= null
       this.lines = lines||line.trim()
       line=is.readLine()
     end
     is.close()

   method getFile returns String
       return lines

 >> Mainline TestKeyParser.nrx:

--package com.howtodoinnrx.xml.sax

import java.util.ArrayList

class TestKeyParser public


   method main(args=String[]) static signals FileNotFoundException
     --xmlFile=File(args[0])
     lines=fileToStr()
     lines.loadFile(args[0])
     parser=KeysXmlParser()
     --keys=parser.parseXml(FileInputStream(xmlFile))
     keys=parser.parseXml(lines.getFile())
     say keys

 >> Keys.xml:

--package com.howtodoinnrx.xml.sax

class Key public


   properties private
     keyName=String
     keyAttr=String
     keyValue=String

   method getKeyName returns String
     return keyName

   method setKeyName(keyName_arg=String)
     this.keyName=keyName_arg

   method getKeyAttr returns String
     return keyAttr

   method setKeyAttr(keyAttr_arg=String)
     this.keyAttr=keyAttr_arg

   method getKeyValue returns String
     return keyValue

   method setKeyValue(keyValue_arg=String)
     this.keyValue=keyValue_arg

   method toString returns String
       if this.keyAttr == "" then
         if this.keyValue == "" then
             return this.keyName
         else
         return this.keyName"="this.keyValue
     else
       return this.keyName"."this.keyAttr"="this.keyValue

 >> KeysXMLParser.xml:

--package com.howtodoinnrx.xml.sax

import java.util.ArrayList
import javax.xml.parsers
import org.xml.sax.InputSource
import org.xml.sax.SAXException
import org.xml.sax.XMLReader
import org.xml.sax.helpers.XMLReaderFactory

class KeysXmlParser public


   --method parseXml(in=InputStream) returns ArrayList
   method parseXml(in=String) returns ArrayList
     keys=ArrayList()
     do
       true=Int 1
       handler=KeyParserHandler()
       --parser=XMLReaderFactory.createXMLReader()
       saxpf=SAXParserFactory.newInstance()
       saxpf.setNamespaceAware(true)
       parser=saxpf.newSAXParser().getXMLReader()
       parser.setContentHandler(handler)
       source=InputSource(StringReader(in))
       handler.setXML(in)
       parser.parse(source)
       keys=handler.getKeys()
      catch e=SAXException
       e.printStackTrace()
      catch ex=IOException
       ex.printStackTrace()
      finally
     end
     return keys

 >> and the meat is in KeysParserHandler.xml:

--package com.howtodoinnrx.xml.sax

import java.util.ArrayList
import java.util.Stack
import org.xml.sax.Attributes
import org.xml.sax.SAXException
import org.xml.sax.helpers.DefaultHandler


class KeyParserHandler public extends DefaultHandler

   properties private
     keyList=ArrayList()
     attrList=ArrayList()
     elementStack=Stack()
     objectStack=Stack()
     xmlStr=Rexx()
     aL=Int
     xmlCurPos=Int


   method startDocument

   method endDocument

   method
startElement(uri=String,localName=String,qName=String,attrs=Attributes)
     this.aL=attrs.getLength()
     --aI=attrs.getIndex(qName)
     --say
"startElement:<qName>"qName"<uri>"uri"<localName>"localName"<Index>"aI"<Length>"aL
     -- advance pointer past qName
     advance('<'qName)
     this.attrList.clear()
     --say xmlStr xmlCurPos
     this.elementStack.push(qName)
     key_nrx=Key()
     key_nrx.setKeyName(qName)
     key_nrx.setKeyAttr(String "")
     key_nrx.setKeyValue(String "")
     if aL>0 then
     loop for aL
       attrEnd=xmlStr.pos('=',xmlCurPos)
       attrStart=xmlStr.verify(' ','N',xmlCurPos+1)
       --say "attr:" attrStart attrEnd
       attrName=String xmlStr.substr(attrStart,attrEnd-attrStart)
       advance(attrName'=')
       value=attrs.getValue(attrName)
       advance(value)
       --say "attr:<value>"attrName"="value
       --key_nrx.setKeyAttrName(value)
       key_attr=Key()
       key_attr.setKeyName(qName)
       key_attr.setKeyAttr(attrName)
       key_attr.setKeyValue(value)
       this.keyList.add(key_attr)
       --say key_attr
     end
     endElem=xmlStr.pos("><",xmlCurPos)
     verPos=xmlStr.verify(" >","N",xmlCurPos)
     --say "endElem="endElem xmlStr.substr(endElem-5,10) "verPos="verPos
xmlStr.substr(verPos-5,10) "curPos="xmlCurPos xmlStr.substr(xmlCurPos-5,10)
     if verPos>=endElem then do
       this.keyList.add(key_nrx)
       --say key_nrx
     end
     this.objectStack.push(key_nrx)

   method endElement(uri=String,localName=String,qName=String)
     --say "endElement:<uri>"uri"<localName>"localName"<qName>"qName
       this.elementStack.pop()
     this.objectStack.pop()
     advance("/")

   method characters(ch=char[],start=int,len=int)
     value=String(ch,start,len).trim()
     --say
"characters:<start>"start"<length>"len"<value>"value"<currElem>"currentElement()
     key_nrx=Key()
     key_nrx.setKeyName(currentElement())
     key_nrx.setKeyAttr(String "")
     if value.length()\==0 then
       key_nrx.setKeyValue(value)
     else
       key_nrx.setKeyValue(String "")
     this.keyList.add(key_nrx)
     --say key_nrx

   method currentElement private returns String
     return String this.elementStack.peek()

   method getKeys returns ArrayList
     return keyList

   method setXML(data=String)
       this.xmlStr=(Rexx data)
       this.xmlCurPos=0

   method advance(data=String)
       --was=xmlCurPos
this.xmlCurPos=xmlCurPos+xmlStr.substr(xmlCurPos+1).pos(data)+data.length()
       --say "advance" was xmlCurPos

_______________________________________________
Ibm-netrexx mailing list
[hidden email]
Online Archive : http://ibm-netrexx.215625.n3.nabble.com/

Reply | Threaded
Open this post in threaded view
|

Re: Parsing xml?

Peter Sharp-2
Note that converting the input to a string is also a key part of the
generic parser solution. This is because element attributes are only
retrievable by name which must be known. So I added the setXML method to
the handler as a means of exposing the XML source independently from the
SAX parser feed.

_______________________________________________
Ibm-netrexx mailing list
[hidden email]
Online Archive : http://ibm-netrexx.215625.n3.nabble.com/

Reply | Threaded
Open this post in threaded view
|

Re: Parsing xml?

Jason Martin
Nice to see you are moving on.

java2nrx will convert some java code for you to help you learn.

https://sourceforge.net/p/netrexx/code/ci/master/tree/tools/java2nrx/ 

The version I have has a few extra fixes but it has been so long I do
not remember what.

I created a tick against the javaparser project but it took years for
them to close it an their code is totally different now.

As you learn, more and more of the Java types can become Rexx types.



_______________________________________________
Ibm-netrexx mailing list
[hidden email]
Online Archive : http://ibm-netrexx.215625.n3.nabble.com/