2010-01-11 19 views
6

Tôi có một tài liệu XML (được tạo ra bởi các biểu mẫu Adobe XFA), có chứa dữ liệu như sau:XStream: Việc thu gọn hệ thống thứ bậc XML như tôi phân tích

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

Kể từ tập tin này được định nghĩa ở đâu đó, tôi không phải là tự do thay đổi định dạng của XML mà tôi nhận được.

Trong mã Java của mình, tôi tạo lớp Vị trí có chứa tiêu đề, ngày bắt đầu và ngày kết thúc.

Vấn đề của tôi là khi tôi sử dụng XStream để phân tích cú pháp tệp, nó muốn lớp PositionBorder giữ tiêu đề và ngày tháng. Tôi muốn cơ bản bỏ qua biên giới và đặt tất cả các trường vào lớp Vị trí.

Điều tôi thực sự muốn làm là sử dụng một cái gì đó giống như phương thức convertAnother để chuyển đổi phần tử con của phần tử vị trí. Tôi đã cố gắng để làm điều đó và nó không thành công, bởi vì PositionConverter của tôi được gọi cho PositionBorder (khi tôi gọi convertAnother).

Bất kỳ ai có bất kỳ manh mối nào về cách xử lý việc thu gọn cấu trúc của XML khi phân tích cú pháp?

+0

làm u phải sử dụng xStream để phân tích xml? –

+0

Nó không phải là một yêu cầu, nhưng tôi có rất nhiều mã hiện có đầu tư nên tôi không muốn thay đổi ngay bây giờ. – Steve

Trả lời

4

Không quá khó để thực hiện với trình chuyển đổi tùy chỉnh. Đây là một ví dụ dài, nhưng tôi hy vọng nó đủ đơn giản để có được ý chính của những gì bạn cần làm:

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

Hãy thử chạy điều đó và xem điều gì xảy ra. Bạn sẽ cần phải sửa đổi nó cho phù hợp với các kiểu của riêng bạn, tất nhiên - tôi chỉ sử dụng các chuỗi cho tất cả các trường của Position (và tôi chắc chắn bạn là lớp Position không được lồng nhau), nhưng chuyển đổi từ một String đến một ngày (hoặc bất cứ điều gì) nên được khá tầm thường.

Một điều bạn sẽ muốn theo dõi (và tôi có thể không nhận được nó hoàn toàn ngay trong ví dụ của tôi) phù hợp với các cuộc gọi reader.moveDown() và reader.moveUp() của bạn. (Và, nếu bạn định làm gì đó thay vì chỉ là unmarshalling - mà tôi không mong đợi từ câu hỏi của bạn - bạn sẽ muốn kết hợp các lệnh writer.startNode() và writer.endNode() của bạn .) Nó có thể sẽ không gây ra bất kỳ vấn đề với ví dụ này, nhưng tôi chắc chắn nó sẽ nâng cao vấn đề nếu bạn đang làm bất cứ điều gì lớn hơn hoặc xử lý nhiều tập tin với cùng một trường hợp XStream hoặc Converter. Ngoài ra, nếu bạn thử reader.moveDown() từ một vị trí không hợp lệ, bạn sẽ nhận được một ngoại lệ thực sự xấu xí - nó phải là khá rõ ràng.

Tôi phải chơi xung quanh với các phương pháp moveUp/moveDown một chút để đưa chúng vào đúng vị trí, vì vậy tôi chắc chắn bạn sẽ cần phải kiểm tra và tinh chỉnh nó cho đến khi bạn có được những gì bạn cần.

+1

trong mã unmarshal của bạn 'String title = reader.getValue();' có thể cung cấp lỗi nếu nút không theo thứ tự giống nhau. 'String title = reader.getAttribute (" attributeName ");' sẽ làm cho nó an toàn hơn. – n002213f

0

tôi thấy cách này dễ dàng hơn để sử dụng:

@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; 
    } 
Các vấn đề liên quan