users@jaxb.java.net

Re: cyclic parsing

From: Wolfgang Laun <wolfgang.laun_at_gmail.com>
Date: Tue, 27 Sep 2011 18:19:54 +0200

There's no need for recursive calls of the Unmarshaller, and you
should not try to get chunks of XML as a String value.

Run this through xjc:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
            version="2.0">

<xs:element name="result" type="valueType"/>

<xs:complexType name="paramType">
  <xs:sequence>
    <xs:element name="param_id" type="xs:string"/>
    <xs:element name="value" type="valueType"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="valueType" mixed="1">
  <xs:sequence>
    <xs:element name="param" type="paramType"
                minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

</xs:schema>

and use the resulting classes:

    private void printParams( String indent, ValueType value ){
        for( Object xobj: value.getContent() ){
            if(xobj instanceof JAXBElement ){
                JAXBElement<?> jobj = (JAXBElement)xobj;
                String tag = jobj.getName().getLocalPart();
                if( "param".equals( tag ) ){
                    ParamType param = (ParamType)jobj.getValue();
                    System.out.println( indent + "id: " + param.getParamId() );
                    printParams( indent + " ", param.getValue() );
                } else {
                    throw new IllegalStateException( "???" + tag );
                }
            } else if(xobj instanceof String ){
                String sobj = (String)xobj;
                if( ! sobj.matches( "\\s*" ) ){
                    System.out.println( indent + "value: " + sobj );
                }
            } else {
                System.out.println( indent + xobj + " " + xobj.getClass() );
            }
        }
    }

    void unmarshal() throws Exception {
        JAXBContext jc = JAXBContext.newInstance( PACKAGE );
        Unmarshaller m = jc.createUnmarshaller();
        JAXBElement<ValueType> obj = null;
        try {
            obj = (JAXBElement<ValueType>)m.unmarshal( new File( XMLIN ) );
        } catch( Exception e ){
            e.printStackTrace();
        }
        ValueType val = (ValueType)obj.getValue();
        printParams( "", val );
    }

Please do not complain if you don't like the way unmarshalling has to
be done. This is due to the reuse of the <value> element for a single
scalar value and a list of <param> elements. This requires mixed, and
then you have to handle the cocktail. (IMHO, another design flaw by
you-know-who.)

-W



On 27 September 2011 16:23, alexis <alzrck_at_gmail.com> wrote:
> Just for testing i did this
> added a <result> tag on top and a </result> on bottom, it makes validators
> show no errors. and i wrote some basic code
>
> public class Test {
> private static org.apache.log4j.Logger log = Logger.getLogger(Test.class);
> public static void main(String[] args) {
> String a =
> "<result><param><param_id>24</param_id><value><param><param_id>1</param_id><value>3</value></param><param><param_id>6</param_id><value>7</value></param><param><param_id>7</param_id><value>7</value></param><param><param_id>8</param_id><value>10000</value></param><param><param_id>9</param_id><value>1544</value></param><param><param_id>15</param_id><value>2</value></param></value></param><param><param_id>22</param_id><value><param><param_id>1</param_id><value>1</value></param><param><param_id>3</param_id><value>3</value></param><param><param_id>5</param_id><value>1</value></param><param><param_id>6</param_id><value>1</value></param><param><param_id>9</param_id><value><param><param_id>2</param_id><value>17</value></param><param><param_id>9</param_id><value>2727</value></param><param><param_id>10</param_id><value>2727</value></param></value></param></value></param><param><param_id>25</param_id><value><param><param_id>1</param_id><value>4</value></param><param><param_id>6</param_id><value>7</value></param><param><param_id>7</param_id><value>7</value></param><param><param_id>8</param_id><value>10000</value></param><param><param_id>9</param_id><value>1544</value></param></value></param><param><param_id>23</param_id><value><param><param_id>1</param_id><value>2</value></param><param><param_id>3</param_id><value>4</value></param><param><param_id>5</param_id><value>1</value></param><param><param_id>6</param_id><value>1</value></param><param><param_id>9</param_id><value><param><param_id>2</param_id><value>17</value></param><param><param_id>9</param_id><value>2427</value></param><param><param_id>10</param_id><value>2427</value></param></value></param></value></param></result>";
>
> try {
> Result res = new Result();
> List<comp> comp = new ArrayList<comp>();
> comp co = new comp();
> co.setParam_id("id1");
> co.setValue("value1");
> comp.add(co);
> res.setParam(comp);
>
> ByteArrayOutputStream xmlOut = new ByteArrayOutputStream();
> JAXBContext context = JAXBContext.newInstance(Result.class);
> Marshaller m = context.createMarshaller();
> m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
> m.marshal(res, xmlOut);
> System.out.println(xmlOut.toString());
> } catch (Exception e) {
> System.out.println(e.getMessage());
> }
>
>
> try
> {
> ByteArrayInputStream input = new ByteArrayInputStream(a.getBytes());
> JAXBContext context = JAXBContext.newInstance(Result.class);
> Unmarshaller um = context.createUnmarshaller();
> Result cf = (Result) um.unmarshal(input);
> log.info("");
> }
> catch (Exception e)
> {
> System.out.println(e);
> }
> log.info("Hello World ... read a book");
> }
>
> @XmlAccessorType(XmlAccessType.FIELD)
> public static class comp
> {
> private String param_id;
> private String value;
> public String getParam_id() {
> return param_id;
> }
> public void setParam_id(String param_id) {
> this.param_id = param_id;
> }
> public String getValue() {
> return value;
> }
> public void setValue(String value) {
> this.value = value;
> }
> }
> @XmlRootElement
> @XmlAccessorType(XmlAccessType.FIELD)
> public static class Result
> {
> private List<comp> param;
> public List<comp> getParam() {
> return param;
> }
> public void setParam(List<comp> param) {
> this.param = param;
> }
> }
>
> when i run this i get 5 elements (looking on the unmarshall part) on the
> list inside the cf object.   My question is, why at the first element of the
> List inside cf, that has this part  <param_id>24</param_id>  inside, value
> remains empty, and not with the string
> "<param><param_id>1</param_id><value>3</value></param><param><param_id>6</param_id><value>7</value></param><param><param_id>7</param_id><value>7</value></param><param><param_id>8</param_id><value>10000</value></param><param><param_id>9</param_id><value>1544</value></param><param><param_id>15</param_id><value>2</value></param>"
>
> Because if it were the case i can match , i dont know "^<param>" in the
> string and call a new unmarshaller until i get everything i need.
>
> It's easy to see running this example and setting a breakpoint on this line
> log.info(""); below  Result cf = (Result) um.unmarshal(input); debug it and
> checking the contents of cf object
>
>
> On Sep 27, 2011, at 6:16 AM, Wolfgang Laun wrote:
>
> You can use some XML validator to throw it back into their teeth ;-)
> This sort of gross deviation is detected even when you don't provide an XML
> schema.
>
> Of ourse, you can simply enclose the reeived text in some additional
> element. But what about the XML header?
>
> -W
>
>
>