Handling XML escape characters (e.g. quotes) using JAXB Marshaller

前端 未结 5 726
無奈伤痛
無奈伤痛 2020-12-01 21:47

I need to serialize an XML java object to a XML file using the JAXB Marshaller (JAXB version 2.2). Now in the xml object, I have a tag which contains String value

相关标签:
5条回答
  • 2020-12-01 22:27

    With JAXB marshaller if you want full control over which characters to escape(e.g. "\'") you will have to add property :

    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CustomCharacterEscapeHandler());
    

    and create a new CustomCharacterEscapeHandler class

    import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
    
    import java.io.IOException;
    import java.io.Writer;
    
    public class CustomCharacterEscapeHandler implements CharacterEscapeHandler {
    
        public CustomCharacterEscapeHandler() {
            super();
        }
    
        public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
            // avoid calling the Writerwrite method too much by assuming
            // that the escaping occurs rarely.
            // profiling revealed that this is faster than the naive code.
            int limit = start+length;
            for (int i = start; i < limit; i++) {
                char c = ch[i];
                if(c == '&' || c == '<' || c == '>' || c == '\'' || (c == '\"' && isAttVal) ) {
                    if(i!=start)
                        out.write(ch,start,i-start);
                    start = i+1;
                    switch (ch[i]) {
                        case '&':
                            out.write("&amp;");
                            break;
                        case '<':
                            out.write("&lt;");
                            break;
                        case '>':
                            out.write("&gt;");
                            break;
                        case '\"':
                            out.write("&quot;");
                            break;
                        case '\'':
                            out.write("&apos;");
                            break;
                    }
                }
            }
    
            if( start!=limit )
                out.write(ch,start,limit-start);
        }
    }
    

    Hope that helps.

    0 讨论(0)
  • 2020-12-01 22:30

    Depending on what you are exactly looking for you can either :

    • disable character escaping
    • or use CDATA string which support can be added into JAXB with just a bit of configuration
    0 讨论(0)
  • 2020-12-01 22:32

    Done it by setting the following property for the JAXB Marshaller:

    marshaller.setProperty("jaxb.encoding", "Unicode");
    
    0 讨论(0)
  • 2020-12-01 22:48

    You can leverage the CDATA structure. Standard JAXB does not cover this structure. There is an extension in EclipseLink JAXB (MOXy) for this (I'm the tech lead). Check out my answer to a related question:

    • How to generate CDATA block using JAXB?

    It describes the @XmlCDATA annotation in MOXy:

    import javax.xml.bind.annotation.XmlRootElement;
    import org.eclipse.persistence.oxm.annotations.XmlCDATA;
    
    @XmlRootElement(name="c")
    public class Customer {
    
       private String bio;
    
       @XmlCDATA
       public void setBio(String bio) {
          this.bio = bio;
       }
    
       public String getBio() {
          return bio;
       }
    
    }
    

    For more information see:

    • http://bdoughan.blogspot.com/2010/07/cdata-cdata-run-run-data-run.html
    0 讨论(0)
  • 2020-12-01 22:54

    There is one simpler way. First use custom escape sequence:

    m.setProperty(CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() {
        @Override
        public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
            out.write( ch, start, length ); 
        }
    }); 
    

    Then marshal it to a String like mentioned below

    StringWriter writer = new StringWriter();
    m.marshal(marshalObject, writer);
    

    and then create a document object from the writer mentioned below

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = new InputSource( new StringReader( writer.toString() ) );
    Document doc = builder.parse( is );
    

    escape characters issue will be resolved

    0 讨论(0)
提交回复
热议问题