2010-01-11 3 views
6

У меня есть документ XML (сгенерированный Adobe XFA форм), который содержит данные, такие как следующие:XStream: Свертывание иерархии XML, как я анализирую

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

Поскольку этот файл определяется в другом месте, я не на свободе изменить формат XML, который я получаю.

В моем Java-коде я создаю класс Position, который содержит Title, Start и End Dates.

Моя проблема в том, что когда я использую XStream для анализа файла, он хочет, чтобы класс PositionBorder сохранял заголовок и даты. Я хочу в основном игнорировать границу и поместить все поля в класс Position.

Что бы я хотел сделать, это использовать что-то вроде метода convertAnother, чтобы преобразовать дочерний элемент позиции. Я пытался сделать именно это, и это терпит неудачу, потому что мой PositionConverter вызывается для PositionBorder (когда я вызываю convertAnother).

У кого-нибудь есть подсказки, как бороться с разрушением структуры XML при разборе?

+0

сделать и есть использовать XSTREAM для синтаксического анализа XML? –

+0

Это не требование, но у меня есть много существующего кода, поэтому я не хочу менять его сейчас. – Steve

ответ

4

Это не очень сложно сделать с пользовательским конвертером. Это немного длинного примера, но я надеюсь, что это достаточно просто, чтобы получить суть того, что вам нужно сделать:

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; 
     } 
    } 
} 

Попробуйте запустить это и посмотреть, что происходит. Разумеется, вам нужно будет модифицировать его в соответствии с вашими собственными типами - я просто использовал строки для всех полей Position (и я уверен, что вы также не являетесь классом Position), но преобразование из String на дату (или что-то еще) должно быть довольно тривиально.

Одна вещь, на которую вы хотите следить (и я, возможно, не получил ее полностью прямо в моем примере) соответствует вашим вызовам reader.moveDown() и reader.moveUp(). (И, если вы собираетесь делать какие-либо сортировки вместо того, чтобы просто разборчиво - что я не ожидаю от вашего вопроса, вы захотите сопоставить свои вызовы writer.startNode() и writer.endNode() .) Вероятно, это не вызовет никаких проблем с этим примером, но я уверен, что это вызовет проблемы, если вы делаете что-то большее или обрабатываете несколько файлов с тем же экземпляром XStream или Converter. Кроме того, если вы попробуете reader.moveDown() из недопустимого местоположения, вы получите действительно уродливое исключение - оно должно быть довольно очевидным.

Мне пришлось немного поиграть с методами moveUp/moveDown, чтобы получить их в нужном месте, поэтому я уверен, что вам нужно будет протестировать его и настроить его, пока не получите то, что вам нужно.

+1

в коде без маршала 'String title = reader.getValue();' может выдавать ошибку, если узел не в том же порядке. 'String title = reader.getAttribute (" attributeName ");' должен сделать его более безопасным. – n002213f

0

Я нахожу этот способ более прост в использовании:

@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; 
    } 
Смежные вопросы