Search code examples
serializationeclipse-emfxmi

Escape ">" character in Eclipse EMF serialization


I am serializing an EMF EObject to file. This works fine and is all correct.

But: a third-party tool relies on escaping the > character, also for text fields. What is the cleanest way to do this? I would like to prevent post processing the serialized file. I could not find any export option which would enable this extended escaping.


Solution

  • There is no export option to do this. The way to go here is to override XMLSaveImpl. Also see https://github.com/eclipse-emf/org.eclipse.emf/discussions/57 .

    This is my example code:

    package org.eclipse.emf.ecore.xmi.impl;
    
    import java.util.Map;
    
    import org.eclipse.emf.ecore.resource.Resource;
    import org.eclipse.emf.ecore.xmi.XMLHelper;
    import org.eclipse.emf.ecore.xmi.XMLResource;
    
    public class CustomXMLSaveImpl extends XMLSaveImpl {
    
        public CustomXMLSaveImpl(final XMLHelper helper) {
            super(helper);
        }
    
        public CustomXMLSaveImpl(final Map<?, ?> options, final XMLHelper helper, final String encoding, final String xmlVersion) {
            super(options, helper, encoding, xmlVersion);
        }
    
        protected void init(XMLResource resource, Map<?, ?> options) {
            super.init(resource, options);
            overrideEscape(options);
        }
    
        /**
         * Replace the Escape instance with our custom version.
         */
        protected void overrideEscape(Map<?, ?> options) {
            if (this.escape == null) {
                return;
            }
            MyEscape myEscape = new MyEscape(options, encoding, xmlVersion);
            this.escape = myEscape;
        }
    
        protected static class MyEscape extends Escape {
            private static final int MAX_UTF_MAPPABLE_CODEPOINT = 0x10FFFF;
            private static final int MAX_LATIN1_MAPPABLE_CODEPOINT = 0xFF;
            private static final int MAX_ASCII_MAPPABLE_CODEPOINT = 0x7F;
    
            public MyEscape(Map<?, ?> options, String encoding, String xmlVersion) {
                String lineSeparator = (String) options.get(Resource.OPTION_LINE_DELIMITER);
                setLineFeed(lineSeparator);
                int maxSafeChar = MAX_UTF_MAPPABLE_CODEPOINT;
                if (encoding != null) {
                    if (encoding.equalsIgnoreCase("ASCII") || encoding.equalsIgnoreCase("US-ASCII")) {
                        maxSafeChar = MAX_ASCII_MAPPABLE_CODEPOINT;
                    } else if (encoding.equalsIgnoreCase("ISO-8859-1")) {
                        maxSafeChar = MAX_LATIN1_MAPPABLE_CODEPOINT;
                    }
                }
    
                setMappingLimit(maxSafeChar);
                if (!"1.0".equals(xmlVersion)) {
                    setAllowControlCharacters(true);
                }
    
                setUseCDATA(Boolean.TRUE.equals(options.get(XMLResource.OPTION_ESCAPE_USING_CDATA)));
            }
    
            @Override
            public String convertText(final String input) {
                String converted = super.convertText(input);
                return converted.replace(">", "&gt;");
            }
    
            @Override
            public String convert(final String input) {
                String converted = super.convertText(input);
                return converted.replace(">", "&gt;");
            }
        }
    }