Insert new element to an XML file using SAX Filter

前端 未结 3 586
逝去的感伤
逝去的感伤 2021-01-20 01:22

I have an XMl file that looks like:



  
    2
    

        
相关标签:
3条回答
  • Using @Jorn Horstmann's (http://stackoverflow.com/users/139595/jorn-horstmann) answer from above you can easily add the missing elements. But to write the results to an XML file you should use the TransformerHandler.

    Just create a very basic ContentHandler and use it instead of the DefaultHandler. In the ContentHandler you can implement all the basic functions (startDocument, startElement etc.) and add every element to a new Transformer. e.g. In your startDocument function:

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

    And then (in each other function) add this: e.g. for startElement:

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

    Finally you can write all this to a file in the endDocument method.

    0 讨论(0)
  • 2021-01-20 01:38

    Correct me if i'm wrong but i think XMLReader and XMLFilter are not really supposed to change a document. I can provide a different approach which with you can change the content of your document too:

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

    Using this class to parse your xml-Files you would only need a Class like this:

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

    with Move being an instance of another class which has the fields you need and also has a annotation for XmlRootElement.

    I hope this helps.

    0 讨论(0)
  • 2021-01-20 01:55

    Your XMLFilter should delegate to another ContentHandler that serializes the document based on the sax events.

    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(...));
    

    Your callback should delegate to the super implementation, which forwards the events to the serializing ContentHandler.

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

    In your endElement callback you can check if your are at the final closing tag and add additional sax events.

    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 讨论(0)
提交回复
热议问题