# xml nur bis auf eine bestimmte ebene parsen mit javax.xml...



## ruutaiokwu (17. Jan 2011)

hallo zusammen,

folgendes xml liegt mir vor:

[XML]<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xmlresponse>
    <trID>
        <clientTRID>fr_client_1111</clientTRID>
        <serverTRID></serverTRID>
    </trID>
    <command>ORDER</command>
    <timestamp>2011-01-17 12:12:41</timestamp>
    <messages>
        <message>
            <code>2000</code>
            <txt>Parameter syntax or value error</txt>
            <detail>ErrorDuplicateAastraOrderNr</detail>
        </message>
    </messages>
</xmlresponse>[/XML]

...ein element <xmlresponse> gibt es nur 1 mal, d.h. dies könnte als "root"-element angesehen werden.

dafür habe ich nun einen parser geschrieben:


```
package slstool.beans.parser;

import java.io.ByteArrayInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import slstool.Constants;
import slstool.beans.Xmlresponse;
import slstool.beans.interfaces.BeanMarkerInterface;
import slstool.beans.parser.enums.XmlresponseEnum;
import slstool.beans.parser.generic.GenericBeanParser;
import slstool.beans.parser.interfaces.BeanParserInterface;
import slstool.utils.MyStringUtil;

public class BeanParser_Xmlresponse extends GenericBeanParser implements BeanParserInterface
{
    public BeanParser_Xmlresponse()
    {
        super();
    }

    @Override
    public List<BeanMarkerInterface> parse()
    {
        final List<Xmlresponse> beanList = new ArrayList<Xmlresponse>();
        Xmlresponse xmlresponse = null;

        try
        {
            if (!((xml == null) || (xml.intern() == "")))
            {
                final XMLInputFactory clXMLInputFactory = XMLInputFactory.newInstance();

                final XMLStreamReader clParser = clXMLInputFactory.createXMLStreamReader(new ByteArrayInputStream(xml.getBytes()));

                String trID_val = null;
                String command_val = null;
                String timestamp_val = null;
                String messages_val = null;

                String lTag = null;

                int lCnt = 0;

                while (clParser.hasNext())
                {
                    final int lEvent = clParser.next();

                    switch (lEvent)
                    {
                        case XMLStreamConstants.START_ELEMENT:

                            final String clOutputTag = clParser.getLocalName();
                            // System.out.println("output -> " + clOutputTag);

                            for (final XmlresponseEnum lXmlresponseEnum : XmlresponseEnum.values())
                            {
                                if (clOutputTag.intern() == lXmlresponseEnum.toString().intern())
                                {
                                    lTag = clOutputTag;
                                    // System.out.println("lTag: " + lTag);
                                }
                            }

                            break;

                        case XMLStreamConstants.CHARACTERS:

                            if (clParser.isWhiteSpace() == false)
                            {
                                if (lTag != null)
                                {
                                    if (lTag.intern() == XmlresponseEnum.trID.toString().intern())
                                    {
                                        trID_val = clParser.getText();
                                        // System.out.println("trID_val: " + trID_val);
                                    }

                                    if (lTag.intern() == XmlresponseEnum.messages.toString().intern())
                                    {
                                        messages_val = clParser.getText();
                                        // System.out.println("messages_val: " + messages_val);
                                    }

                                    if (lTag.intern() == XmlresponseEnum.command.toString().intern())
                                    {
                                        command_val = clParser.getText();
                                        // System.out.println("command_val: " + command_val);
                                    }

                                    if (lTag.intern() == XmlresponseEnum.timestamp.toString().intern())
                                    {
                                        timestamp_val = clParser.getText();
                                        // System.out.println("timestamp_val: " + timestamp_val);
                                    }

                                    lCnt++;

                                    if (lCnt % XmlresponseEnum.values().length == 0)
                                    {
                                        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                                        final Date d = df.parse(timestamp_val);

                                        xmlresponse = Xmlresponse.createInstance(null, command_val, d, null);
                                        beanList.add(xmlresponse);
                                    }
                                }
                            }
                            break;

                        default:
                            break;
                    }
                }
            }
            else
            {
                throw new RuntimeException("Input is empty of null");
            }
        }
        catch (final Exception caException)
        {
            throw new RuntimeException(caException);
        }

        return new ArrayList<BeanMarkerInterface>(beanList);
    }

    @Override
    public void loadXML(String xml)
    {
        if (MyStringUtil.stringIsEmptyOrNull(xml))
        {
            throw new RuntimeException(Constants.Messages.XML_EMPTY_OR_NULL);
        }
        else
        {
            super.xml = xml;
        }
    }
}
```


...bei diesem besteht aber das problem, dass er "nested"-xml-elemente weiter parst, also weiter in die tiefe geht. das problem besteht beim feld *trTd *sowie *messages*: ich möchte aber, dass er bei diesem feldern nicht weiter nach xml parst, sondern den wert dahinter einfach ausliest, in dieser art:

*********************
*trID:* <clientTRID>fr_client_1111</clientTRID>
        <serverTRID></serverTRID>
*command:* ORDER
*timestamp:* Mon Jan 17 00:12:41 CET 2011
*messages:* <message>
            <code>2000</code>
            <txt>Parameter syntax or value error</txt>
            <detail>ErrorDuplicateAastraOrderNr</detail>
        </message>


weiss jemand von euch wie das am einfachsten geht?

danke & freundliche grüsse,
jan


----------



## Wildcard (17. Jan 2011)

Ich denke nicht das es irgendeinen Parser gibt der so arbeiten kann, schließlich ist das ein äusserst exotischer Fall.
Vermutlich wirst du deinen eigenen Parser schreiben müssen.


----------



## ruutaiokwu (18. Jan 2011)

hallo Wildcard,

besten dank für deine antwort. ein äusserst exotischer fall meinst du? warum? schlussendlich möchte ich die komplette xml-struktur als bean respäsentieren, und möchte dabei z.b. das feld trId als bean 1:1 mappen, sprich bean im bean:

die ganze struktur wird als bean "Xmlresponse" zusammengefasst, der trID-teil wird dabei ein eigenes bean, welches aber wiederum die der "Xmlresponse" mit setTrID(trID) geschrieben sowie mit getTrID() geholt werden kann. gleiches mit dem feld "messages", das sollte dann eine list in der art List<Message> (-> Xmlresponse.setMessages(List<Message>) & Xmlresponse.getMessages()) werden...

codegeneratoren mag ich gar nicht, darum das ganze... weisst du möglicherweise, wie es mit anderen xml-libraries aussieht? gibt ja einige für java soviel ich weiss...


gruss, jan


----------



## Wildcard (18. Jan 2011)

> codegeneratoren mag ich gar nicht


Überwinde deine Furcht vor Generatoren und greif zu XML Binding, denn so überführt man eine XML in eine Objektstruktur.
Ich bevorzuge EMF, aber für einfache Sachen tut es auch Jaxb.


----------



## Noctarius (19. Jan 2011)

Keine Ahnung ob das ungefähr dem entspricht, was du dir vorgestellt hast:

```
public class Message {
  private final int code;
  private final String txt;
  private final String detail;

  public Message(final int code, final String txt, final String detail) {
    this.code = code;
    this.txt = txt;
    this.detail = detail;
  }

  public int getCode() { return code; }

  public String getTxt() { return txt; }

  public String getDetail() { return detail; }

}

public class XmlResponse {
  private final String command;
  private final Date timestamp;
  private Message message;

  public XmlResponse(final String command, final Date timestamp) {
    this.command = command;
    this.timestamp = timestamp;
  }

  public String getCommand() { return command; }

  public Date getTimestamp() { return timestamp; }

  public void setMessage(Message message) { this.message = message; }

  public Message getMessage() { return message; }

}

public class ResponseHolder() {
  private XmlResponse xmlResponse;

  public void setXmlResponse(XmlResponse xmlResponse) { this.xmlResponse = xmlResponse; }

  public XmlResponse getXmlResponse() { return xmlResponse; }

}

public class XmlResponseParser {
  private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  @TagParser( { @Tag("xmlresponse") } )
  public void parseXmlResponse(
            @Child("command") @TextBody String command,
            @Child("timestamp") @TextBody String timestamp,
            @ContextObject ReponseHolder responseHolder) throws LyciaParsingException {

    try {
      Date date = SDF.parse(timestamp);

      responseHolder.setXmlResponse(new XmlResponse(command, date));

    } catch (ParseException e) {
      throw new LyciaParsingException(e);
    }
  }

  @TagParser( { @Tag("message") } )
  public void parseMessage(
            @Child("code") @TextBody String code,
            @Child("txt") @TextBody String txt,
            @Child("detail") @TextBody String detail,
            @ContextObject ReponseHolder responseHolder) {

    XmlResponse xmlResponse = responseHolder.getXmlResponse();

    if (xmlResponse == null)
      throw new IllegalStateException("XmlResponse cannot be null");

    int c = Integer.parseInt(code);

    xmlResponse.setMessage(new Message(c, txt, detail));
  }

}

public class ParserMain {

  public static void main(String[] args) throws Exception {
    FluentBuilder<ResponseHolder> builder = FluentBuilder.prepare();
    ResponseHolder responseHolder = new ResponseHolder();

    LyciaParser<ResponseHolder> parser = builder
            .configure(FluentBuilder.validateSchema(false),
                FluentBuilder.contextObject(responseHolder))
            .parser(FluentBuilder.pojoParser(new XmlResponseParser()))
            .build();

    parser.parse(getXmlString());

    XmlResponse xmlResponse = responseHolder.getXmlResponse();
    ...
  }

}
```


----------



## ruutaiokwu (29. Jan 2011)

hallo Noctarius,

besten dank für deinen beitrag. wie es scheint, verwendest du das lycia-framework. (dein projekt, oder?)

werde mir das, wenn ich das nächste xml zu parsen habe, anschauen. (mein problem hat sich mittlerweilen gelöst, codegen verwendet...)

danke & gruss,
jan


----------

