2012-05-15 3 views
4

У меня есть файл XML, который выглядит как:Вставьте новый элемент в файл XML с помощью SAX Filter

<?xml version="1.0" encoding="UTF-8"?> 
<game > 
    <moves> 
    <turn>2</turn> 
    <piece nr="1" /> 
    <turn>4</turn> 
    <piece nr="1" /> 

    </moves> 
</game> 

Я пишу программу Java, которая принимает файл XML в качестве входных данных затем анализирует его с SAX и SAX фильтром и вычисляет:

  • сумма содержания поворота элемента (здесь = 6)
  • количество штучных элементов (здесь = 2)

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

<s:statistics> 
    <s:turn-total>6</s:turn-total> 
    <s:piece-count>2</s:piece-count> 
</s:statistics> 

Приставка s является ссылкой на namespace.

Моя программа до сих пор:

public class test{  
     public static void main(String[] args) throws Exception { 
       if (args.length != 2) { 
       System.err.println("error "); 
       System.exit(1); 
       } 
       String xmlInput = args[0]; 
       String filteredXML = args[1]; 
       test test1 = new test(); 
        test1.sax(xmlInput, filteredXML); 
      } 
    private void sax(String gameXML, String filteredGameXML)throws Exception{ 
     FileInputStream fis = new FileInputStream(gameXML); 
     InputSource is = new InputSource(fis); 
     XMLReader xr = XMLReaderFactory.createXMLReader(); 
     XMLFilter xf = new MyFilter(); 
     xf.setParent(xr); 
     xr = xf; 
     xr.parse(is); 
     xr.setFeature("http://xml.org/sax/features/namespaces", true); 
     DefaultHandler handler = new DefaultHandler(); 
     xr.setContentHandler(handler); 
    } 
    private class MyFilter extends XMLFilterImpl{ 
      StringBuffer buffer; 
     int temp=0; 
      int sum=0; 
      String ff; 
      int numof=0; 
      private MyFilter() {} 

      @Override 
       public void startDocument() throws SAXException { 
        System.out.println("START DOCUMENT"); 
        numof=0;   
       } 

       public void startElement(String namespaceURI, String localName, String name, Attributes attributes) throws SAXException{ 
        if(localName.equals("turn")){ 
         buffer=new StringBuffer(); 
         } 
        if("piece".equals(name)){ 
         numof++; 
        } 
       } 

       public void characters(char[] ch, int start, int length) throws SAXException { 
        String s=new String(ch, start, length); 
        if(buffer!=null){ 
         buffer.append(s); 
         } 
       } 

       public void endElement(String uri, String localName, String name)throws SAXException { 
        if(buffer!=null){ 
         ff=buffer.toString(); 
         temp=Integer.valueOf(ff); 
         sum=sum+temp; 
         } 
         buffer=null; 
       } 
       public void endDocument() throws SAXException { 
        System.out.println("END DOCUMENT"); 
        System.out.println("sum of turn: "+ sum); 
        System.out.println("sum of piece: "+ numof); 
       } 
     } 

    } 

Что я должен делать дальше?

+0

И в чем проблема? Вы сказали нам, чего вы хотите достичь, и дали нам свалку кода. Не работает ли код? Если нет, то какие ошибки вы получаете. Если это работает, но не так, как ожидалось, как результат отличается от вашего ожидания? Пожалуйста, уточните свой вопрос. – Chris

+0

Я хочу знать, как я могу вставить новый элемент «» в xml-файл? и как я могу сгенерировать XML-файл в качестве вывода? –

+0

С помощью SAX Filter вы можете модифицировать разобранное дерево, но вы не можете вывести измененный XML-файл. Для лучшего понимания, пожалуйста, обратитесь к этому: http://www.cafeconleche.org/books/xmljava/chapters/ch08.html Наверное, лучший способ - использовать DocumentBuilder - http://docs.oracle.com/javase /1.5.0/docs/api/javax/xml/parsers/DocumentBuilder.html или SAXBuilder - http://www.jdom.org/docs/apidocs/org/jdom2/input/SAXBuilder.html, чтобы добавить элемент после вас создали его. Надеюсь, это помогло. – Mircea

ответ

0

Исправьте меня, если я ошибаюсь, но я думаю, что XMLReader и XMLFilter на самом деле не должны менять документ. Я могу предоставить другой подход, с вами может изменить содержание документа тоже:

public class ExtXMLConfig { 
private JAXBContext context; 
private Marshaller m; 
private Unmarshaller um; 
private Schema schema = null; 

/** 
* Creates an ExtXMLConfig-object, which uses rootClass as object to parse 
* and save XML-files. 
* 
* @param rootClass 
*   the class use create/parse xml-files from 
* @throws JAXBException 
*/ 
public ExtXMLConfig(Class<?> rootClass) throws JAXBException { 
    context = JAXBContext.newInstance(rootClass); 

    init(); 
} 

/** 
* Creates an ExtXMLConfig, which uses a classPath like javax.xml.bin to use 
* all classes in that path to parse and write xml-files 
* 
* @param classPath 
*   the class path containing all needed java-objects 
* @throws JAXBException 
*/ 
public ExtXMLConfig(String classPath) throws JAXBException { 
    context = JAXBContext.newInstance(classPath); 

    init(); 
} 

/** 
* Parses a xml-file into a JavaObject. 
* 
* @param file 
*   path to the xml-file 
* @return a java-Object 
*/ 
public Object load(String file) { 
    return load(new File(file)); 
} 

/** 
* Parses a xml-file into a JavaObject. 
* 
* @param xml 
*   File-object representing the xml-file 
* @return a java-Object 
*/ 
public Object load(File xml) { 
    um.setSchema(schema); 

    if (xml.exists() && xml.isFile()) { 
     try { 
      return um.unmarshal(xml); 
     } catch (JAXBException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } else { 
     System.out.println("Failed to open file: " + xml.getAbsolutePath()); 
    } 

    return null; 
} 

/** 
* Saves a object into a xml-file. 
* 
* @param xml 
*   the object to save 
* @param file 
*   path to the file to save to 
*/ 
public void save(Object xml, String file) { 
    save(xml, new File(file)); 
} 

/** 
* Saves a object into a xml-file. 
* 
* @param xml 
*   the object to save 
* @param file 
*   File-object representing the file to save to 
*/ 
public void save(Object xml, File file) { 
    if (xml != null) { 
     m.setSchema(schema); 

     if (!file.isDirectory()) { 
      try { 
       if (!file.exists()) { 
        file.createNewFile(); 
       } 

       m.marshal(xml, file); 
      } catch (JAXBException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

/** 
* Returns a formatted string representation of a xml-file given as a 
* java-Object. 
* 
* @param xml 
*   the java-object to parse the xml from. 
* @return a formatted string representation of the given object 
*/ 
public String toString(Object xml) { 
    StringWriter out = new StringWriter(); 
    try { 
     m.setSchema(schema); 
     m.marshal(xml, out); 

     return out.toString(); 
    } catch (JAXBException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    return null; 
} 

private void init() throws JAXBException { 
    m = context.createMarshaller(); 
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 

    um = context.createUnmarshaller(); 
} 

Используя этот класс, чтобы разобрать ваш XML-файлов вам нужно будет только класс вроде этого:

@XmlRootElement // used to parse this class as xml-Root 
public class Game { 
    private Move moves; 

    public Game() {}; 

    public void setMove(Move moves) { 
     this.moves = moves; 
    } 

    public Moves getMoves() { 
     return this.moves; 
    } 
} 

с Move - экземпляр другого класса, который имеет нужные вам поля, а также имеет аннотацию для XmlRootElement.

Надеюсь, это поможет.

+0

спасибо за повтор, он работает, но, к сожалению, я должен это сделать, используя Sax Filters (используя Sax Fliter u можно изменить файл ur xml) –

4

Ваш XMLFilter должен делегировать другому ContentHandler, который сериализует документ на основе событий sax.

SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance(); 
TransformerHandler serializer = factory.newTransformerHandler(); 
Result result = new StreamResult(...); 
serializer.setResult(result); 

XMLFilterImpl filter = new MyFilter(); 
filter.setContentHandler(serializer); 

XMLReader xmlreader = XMLReaderFactory.createXMLReader(); 
xmlreader.setFeature("http://xml.org/sax/features/namespaces", true); 
xmlreader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); 
xmlreader.setContentHandler(filter); 

xmlreader.parse(new InputSource(...)); 

Ваш обратный вызов должен делегировать super реализации, которая передает события в сериализации ContentHandler.

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 
    super.startElement(namespaceURI, localName, qName, atts); 
    ... 
} 

В вашем endElement обратного вызова вы можете проверить, если ваши в конечном закрывающем теге и добавить дополнительные события саксофона.

public void endElement(String namespaceURI, String localName, String qName) throws SAXException { 
    super.endElement(namespaceURI, localName, qName); 
    if ("game".equals(localName)) { 
     super.startElement("", "statistics", "statistics", new AttributesImpl()); 
     char[] chars = String.valueOf(num).toCharArray(); 
     super.characters(chars, 0, chars.length); 
     super.endElement("", "statistics", "statistics"); 
    } 
    ... 
} 
+0

+1: Правильная тактика. OP хотел пространство имен для нового элемента, но это должно быть относительно легко добавить. –

0

Используя ответ @Jorn HORSTMANN в (http://stackoverflow.com/users/139595/jorn-horstmann) сверху вы можете легко добавить недостающие элементы. Но для записи результатов в файл XML вы должны использовать TransformerHandler.

Просто создайте базовый ContentHandler и используйте его вместо DefaultHandler. В ContentHandler вы можете реализовать все основные функции (startDocument, startElement и т. Д.) И добавить каждый элемент в новый Transformer. , например. В функции StartDocument:

Transformer t = hd.getTransformer(); 
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
t.setOutputProperty(OutputKeys.METHOD, "xml"); 
t.setOutputProperty(OutputKeys.INDENT, "yes"); 
hd.startDocument(); 

А затем (в каждой другой функции) добавить следующее: например для startElement:

hd.startElement(uri,localName,name,attributes); 

Наконец, вы можете записать все это в файл в методе endDocument.

Смежные вопросы