2010-01-11 5 views
6

analysieren Ich habe ein XML-Dokument (erzeugt durch Adobe XFA-Formulare), die Daten enthält, wie folgt aus:XStream: Einstürzen XML-Hierarchie, wie ich

<Position> 
    <PositionBorder> 
     <Title/> 
     <StartDate/> 
     <EndDate/> 
    </PositionBorder> 
</Position> 

Da diese Datei an anderer Stelle definiert ist, ich bin nicht Ich kann das Format des XML, das ich bekomme, ändern.

In meinem Java-Code erstelle ich eine Position-Klasse, die die Titel, Start- und Enddaten enthält.

Mein Problem ist, wenn ich XStream verwenden, um die Datei zu analysieren, möchte es eine PositionBorder-Klasse, um den Titel und die Daten zu halten. Ich möchte die Grenze im Grunde ignorieren und alle Felder in die Position-Klasse platzieren.

Was ich wirklich gerne tun würde, ist etwas wie die convertAnother Methode, um das Kind des Positionselementes zu konvertieren. Ich habe genau das versucht und es scheitert, weil mein PositionConverter für den PositionBorder aufgerufen wird (wenn ich convertAnother aufruft).

Wer hat irgendwelche Hinweise, wie man mit dem Zusammenbruch der Struktur eines XML beim Parsen umgehen kann?

+0

do u haben Xstream verwenden xml zu analysieren? –

+0

Es ist keine Voraussetzung, aber ich habe viel vorhandenen Code investiert, also möchte ich jetzt lieber nicht ändern. – Steve

Antwort

4

Es ist nicht schrecklich schwierig, mit einem benutzerdefinierten Konverter zu tun. Dies ist ein wenig von einem langen Beispiel, aber ich hoffe, es ist einfach genug, um das Wesentliche zu bekommen, was Sie tun müssen:

import com.thoughtworks.xstream.XStream; 
import com.thoughtworks.xstream.annotations.XStreamAlias; 
import com.thoughtworks.xstream.converters.Converter; 
import com.thoughtworks.xstream.converters.MarshallingContext; 
import com.thoughtworks.xstream.converters.UnmarshallingContext; 
import com.thoughtworks.xstream.io.HierarchicalStreamReader; 
import com.thoughtworks.xstream.io.HierarchicalStreamWriter; 

public final class ConverterTest { 
    public static void main(String[] args) { 
     XStream xstream = new XStream(); 
     xstream.autodetectAnnotations(true); 
     xstream.registerConverter(new PositionConverter()); 

     final Position position = new Position(); 
     position.setTitle("The Title"); 
     position.setStartDate("The Start Date"); 
     position.setEndDate("The End Date"); 

     final String xml = xstream.toXML(position); 
     System.out.println("Generated XML:"); 
     System.out.println(xml); 

     final Position genPosition = (Position) xstream.fromXML(xml); 
     System.out.println("Generated Position:"); 
     System.out.println("\tTitle: " + genPosition.getTitle()); 
     System.out.println("\tStart Date: " + genPosition.getStartDate()); 
     System.out.println("\tEnd Date: " + genPosition.getEndDate()); 
    } 

    @XStreamAlias("Position") 
    private static class Position { 
     public String getEndDate() { 
      return endDate; 
     } 

     public void setEndDate(String endDate) { 
      this.endDate = endDate; 
     } 

     public String getStartDate() { 
      return startDate; 
     } 

     public void setStartDate(String startDate) { 
      this.startDate = startDate; 
     } 

     public String getTitle() { 
      return title; 
     } 

     public void setTitle(String title) { 
      this.title = title; 
     } 

     private String title; 
     private String startDate; 
     private String endDate; 
    } 

    private static class PositionConverter implements Converter { 
     public boolean canConvert(Class clazz) { 
      return Position.class == clazz; 
     } 

     public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
      Position position = (Position)value; 
      writer.startNode("PositionBorder"); 

      writer.startNode("Title"); 
      writer.setValue(position.getTitle()); 
      writer.endNode(); 

      writer.startNode("StartDate"); 
      writer.setValue(position.getStartDate()); 
      writer.endNode(); 

      writer.startNode("EndDate"); 
      writer.setValue(position.getEndDate()); 
      writer.endNode(); 

      writer.endNode(); 
     } 

     public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
      Position position = new Position(); 
      // move it to <PositionBorder> tag. 
      reader.moveDown(); 
      // now move it to <Title> tag. 
      reader.moveDown(); 
      String title = reader.getValue(); 
      position.setTitle(title); 
      reader.moveUp(); // moves back to <PositionBorder> 

      reader.moveDown(); // should move down to <StartDate> tag 
      String startDate = reader.getValue(); 
      position.setStartDate(startDate); 
      reader.moveUp(); // move back to <PositionBorder> 

      reader.moveDown(); // should move down to <EndDate> tag 
      String endDate = reader.getValue(); 
      position.setEndDate(endDate); 
      reader.moveUp(); // move back to <PositionBorder> 


      return position; 
     } 
    } 
} 

Versuchen Sie das mal laufen und sehen, was passiert. Sie müssen es natürlich an Ihre eigenen Typen anpassen - ich habe nur Strings für alle Position-Felder verwendet (und ich bin sicher, dass Ihre Position-Klasse auch nicht verschachtelt ist), aber von einem String konvertieren zu einem Datum (oder was auch immer) sollte eher trivial sein.

Eine Sache, Sie wollen im Auge behalten (und ich könnte nicht habe es völlig rechts in meinem Beispiel bekommen) Ihre reader.moveDown ist passend() und reader.moveUp() aufrufen. (Und wenn Sie ein Marshalling statt nur das Unmarshalling durchführen - was ich von Ihrer Frage nicht erwarte -, sollten Sie auch Ihre writer.startNode() - und writer.endNode() -Aufrufe anpassen) .) Es wird wahrscheinlich keine Probleme mit diesem Beispiel verursachen, aber ich bin mir sicher, dass es zu Problemen führen wird, wenn Sie etwas Größeres machen oder mehrere Dateien mit derselben XStream- oder Converter-Instanz bearbeiten. Wenn Sie leser.moveDown() von einem ungültigen Ort aus versuchen, erhalten Sie eine wirklich hässliche Ausnahme - es sollte ziemlich offensichtlich sein.

Ich musste etwas mit den moveUp/moveDown-Methoden herumspielen, um sie an die richtigen Stellen zu bringen, also bin ich mir sicher, dass du sie testen und zwicken musst, bis du bekommst, was du brauchst.

+1

in Ihrem unmarshal-Code 'String title = reader.getValue();' könnte Fehler geben, wenn der Knoten nicht in der gleichen Reihenfolge ist. 'String title = reader.getAttribute (" attributeName ");' sollte es sicherer machen. – n002213f

0

Ich finde diese Art und Weise mehr einfach zu bedienen:

@Override 
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
     Position mPosition = new Position(); 
     while (reader.hasMoreChildren()) { 

      reader.moveDown(); 

      String nodeName = reader.getNodeName(); 

      if ("Title".equalsIgnoreCase(nodeName)) { 
       mPosition.setTitle(reader.getValue()); 
      } else if ("StartDate".equalsIgnoreCase(nodeName)) { 
       mPosition.setStartDate(reader.getValue()); 
      }else if ("attributeexample".equalsIgnoreCase(nodeName)) { 
       mPosition.setAttributeExample(reader.getAttribute("attrname")); 
      } 

      reader.moveUp(); 
     } 

     return mPosition; 
    }