xmlbeans-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ra...@apache.org
Subject svn commit: r225349 - in /xmlbeans/trunk/src: store/org/apache/xmlbeans/impl/store/Saver.java xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java xmlpublic/org/apache/xmlbeans/XmlOptions.java
Date Tue, 26 Jul 2005 17:06:23 GMT
Author: radup
Date: Tue Jul 26 10:06:12 2005
New Revision: 225349

URL: http://svn.apache.org/viewcvs?rev=225349&view=rev
Log:
Fix for XMLBEANS-177. Added a setSaveSubstituteCharacters() option to XmlOptions. This enables
characters to be replaced during ouptut by their hex, decimal or predefined-entity escapes.

Contributed by Roger Weber and Lawrence Jones

Added:
    xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java
Modified:
    xmlbeans/trunk/src/store/org/apache/xmlbeans/impl/store/Saver.java
    xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptions.java

Modified: xmlbeans/trunk/src/store/org/apache/xmlbeans/impl/store/Saver.java
URL: http://svn.apache.org/viewcvs/xmlbeans/trunk/src/store/org/apache/xmlbeans/impl/store/Saver.java?rev=225349&r1=225348&r2=225349&view=diff
==============================================================================
--- xmlbeans/trunk/src/store/org/apache/xmlbeans/impl/store/Saver.java (original)
+++ xmlbeans/trunk/src/store/org/apache/xmlbeans/impl/store/Saver.java Tue Jul 26 10:06:12
2005
@@ -20,6 +20,7 @@
 import org.apache.xmlbeans.SystemProperties;
 import org.apache.xmlbeans.XmlDocumentProperties;
 import org.apache.xmlbeans.XmlOptions;
+import org.apache.xmlbeans.XmlOptionCharEscapeMap;
 
 import org.apache.xmlbeans.impl.common.QNameHelper;
 import org.apache.xmlbeans.impl.common.EncodingMap;
@@ -67,9 +68,9 @@
     Saver ( Cur c, XmlOptions options )
     {
         assert c._locale.entered();
-        
+
         options = XmlOptions.maskNull( options );
-        
+
         _cur = createSaveCur( c, options );
 
         _locale = c._locale;
@@ -83,13 +84,13 @@
         _attrValues = new ArrayList ();
 
         // Define implicit xml prefixed namespace
-        
+
         addMapping( "xml", Locale._xml1998Uri );
 
         if (options.hasOption( XmlOptions.SAVE_IMPLICIT_NAMESPACES ))
         {
             Map m = (Map) options.get( XmlOptions.SAVE_IMPLICIT_NAMESPACES );
-            
+
             for ( Iterator i = m.keySet().iterator() ; i.hasNext() ; )
             {
                 String prefix = (String) i.next();
@@ -97,14 +98,21 @@
             }
         }
 
+        // define character map for escaped replacements
+        if (options.hasOption( XmlOptions.SAVE_SUBSITITUTE_CHARACTERS ))
+        {
+            _replaceChar = (XmlOptionCharEscapeMap)
+                options.get( XmlOptions.SAVE_SUBSITITUTE_CHARACTERS);
+        }
+
         // If the default prefix has not been mapped, do so now
-        
+
         if (getNamespaceForPrefix( "" ) == null)
         {
             _initialDefaultUri = new String( "" );
             addMapping( "", _initialDefaultUri );
         }
-        
+
         if (options.hasOption( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES ) &&
                 !(this instanceof SynthNamespaceSaver))
         {
@@ -116,15 +124,15 @@
             if (!saver._synthNamespaces.isEmpty())
                 _preComputedNamespaces = saver._synthNamespaces;
         }
-        
+
         _useDefaultNamespace =
             options.hasOption( XmlOptions.SAVE_USE_DEFAULT_NAMESPACE );
 
         _saveNamespacesFirst = options.hasOption( XmlOptions.SAVE_NAMESPACES_FIRST );
-        
+
         if (options.hasOption( XmlOptions.SAVE_SUGGESTED_PREFIXES ))
             _suggestedPrefixes = (Map) options.get( XmlOptions.SAVE_SUGGESTED_PREFIXES);
-        
+
         _ancestorNamespaces = _cur.getAncestorNamespaces();
     }
 
@@ -136,13 +144,13 @@
 
         if (fragName == null)
         {
-            fragName = 
+            fragName =
                 options.hasOption( XmlOptions.SAVE_USE_OPEN_FRAGMENT )
                     ? Locale._openuriFragment
                     : Locale._xmlFragment;
         }
 
-        boolean saveInner = 
+        boolean saveInner =
             options.hasOption( XmlOptions.SAVE_INNER ) &&
                 !options.hasOption( XmlOptions.SAVE_OUTER );
 
@@ -168,13 +176,13 @@
 
             break;
         }
-        
+
         case ELEM :
         {
             if (saveInner)
             {
                 positionToInner( c, start, end );
-                
+
                 cur =
                     new FragSaveCur(
                         start, end, Locale.isFragment( start, end ) ? fragName : synthName
);
@@ -182,7 +190,7 @@
             else if (synthName != null)
             {
                 positionToInner( c, start, end );
-                
+
                 cur = new FragSaveCur( start, end, synthName );
             }
             else
@@ -218,7 +226,7 @@
             {
                 start.moveToCur( c );
                 start.next();
-                
+
                 end.moveToCur( c );
                 end.toEnd();
             }
@@ -230,7 +238,7 @@
             else
             {
                 assert k == COMMENT || k == PROCINST;
-                
+
                 start.moveToCur( c );
                 end.moveToCur( c );
                 end.skip();
@@ -277,33 +285,33 @@
 
         if (_cur == null)
             return false;
-        
+
         if (_version != _locale.version())
             throw new ConcurrentModificationException( "Document changed during save" );
-        
+
         switch ( _cur.kind() )
         {
             case   ROOT     : { processRoot();                        break; }
             case   ELEM     : { processElement();                     break; }
             case - ELEM     : { processFinish ();                     break; }
             case   TEXT     : { emitText      ( _cur );               break; }
-                
+
             case   COMMENT  : { emitComment   ( _cur ); _cur.toEnd(); break; }
             case   PROCINST : { emitProcinst  ( _cur ); _cur.toEnd(); break; }
-                              
+
             case - ROOT :
             {
                 _cur.release();
                 _cur = null;
-                
+
                 return false;
             }
-                
+
             default : throw new RuntimeException( "Unexpected kind" );
         }
 
         _cur.next();
-        
+
         return true;
     }
 
@@ -389,7 +397,7 @@
                 QName attrName = _cur.getName();
 
                 _attrNames.add( attrName );
-                               
+
                 for ( int i = _attrNames.size() - 2 ; i >= 0 ; i-- )
                 {
                     if (_attrNames.get( i ).equals( attrName ))
@@ -400,11 +408,11 @@
                 }
 
                 _attrValues.add( _cur.getAttrValue() );
-                
+
                 ensureMapping( attrName.getNamespaceURI(), attrName.getPrefix(), false, true
);
             }
         }
-        
+
         _cur.pop();
 
         // If I am doing aggressive namespaces and we're emitting a
@@ -419,7 +427,7 @@
                 String uri = (String) i.next();
                 String prefix = (String) _preComputedNamespaces.get( uri );
                 boolean considerDefault = prefix.length() == 0 && !ensureDefaultEmpty;
-                
+
                 ensureMapping( uri, prefix, considerDefault, false );
             }
 
@@ -483,7 +491,7 @@
     private final void pushMappings ( SaveCur c, boolean ensureDefaultEmpty )
     {
         assert c.isContainer();
-        
+
         _namespaceStack.add( null );
 
         c.push();
@@ -501,13 +509,13 @@
             {
                 String prefix = (String) _ancestorNamespaces.get( i );
                 String uri    = (String) _ancestorNamespaces.get( i + 1 );
-                
+
                 addNewFrameMapping( prefix, uri, ensureDefaultEmpty );
             }
 
             _ancestorNamespaces = null;
         }
-        
+
         if (ensureDefaultEmpty)
         {
             String defaultUri = (String) _prefixMap.get( "" );
@@ -525,7 +533,7 @@
         // If the prefix maps to "", this don't include this mapping 'cause it's not well
formed.
         // Also, if we want to make sure that the default namespace is always "", then check
that
         // here as well.
-        
+
         if ((prefix.length() == 0 || uri.length() > 0) &&
                 (!ensureDefaultEmpty || prefix.length() > 0 || uri.length() == 0))
         {
@@ -562,7 +570,7 @@
         {
             // See if this prefix is already mapped to this uri.  If
             // so, then add to the stack, but there is nothing to rename
-        
+
             if (renameUri.equals( uri ))
                 renameUri = null;
             else
@@ -618,7 +626,7 @@
         if (renameUri != null)
             _uriMap.put( renameUri, renamePrefix );
     }
-    
+
     private final void popMappings ( )
     {
         for ( ; ; )
@@ -634,21 +642,21 @@
                 break;
             }
 
-            Object oldUri = _namespaceStack.get( i - 7 ); 
-            Object oldPrefix = _namespaceStack.get( i - 8 ); 
+            Object oldUri = _namespaceStack.get( i - 7 );
+            Object oldPrefix = _namespaceStack.get( i - 8 );
+
+            if (oldPrefix == null)
+                _uriMap.remove( oldUri );
+            else
+                _uriMap.put( oldUri, oldPrefix );
+
+            oldPrefix = _namespaceStack.get( i - 4 );
+            oldUri = _namespaceStack.get( i - 3 );
 
-            if (oldPrefix == null) 
-                _uriMap.remove( oldUri ); 
-            else 
-                _uriMap.put( oldUri, oldPrefix ); 
-
-            oldPrefix = _namespaceStack.get( i - 4 ); 
-            oldUri = _namespaceStack.get( i - 3 ); 
-
-            if (oldUri == null) 
-                _prefixMap.remove( oldPrefix ); 
-            else 
-                _prefixMap.put( oldPrefix, oldUri ); 
+            if (oldUri == null)
+                _prefixMap.remove( oldPrefix );
+            else
+                _prefixMap.put( oldPrefix, oldUri );
 
             String uri = (String) _namespaceStack.get( i - 5 );
 
@@ -666,7 +674,7 @@
             _namespaceStack.remove( i - 8 );
         }
     }
-    
+
     private final void dumpMappings ( )
     {
         for ( int i = _namespaceStack.size() ; i > 0 ; )
@@ -732,10 +740,10 @@
         //  3) The default mapping is allowed
         //  4) ns#++
         //
-        
+
         if (candidatePrefix != null && candidatePrefix.length() == 0)
             candidatePrefix = null;
-        
+
         if (candidatePrefix == null || !tryPrefix( candidatePrefix ))
         {
             if (_suggestedPrefixes != null &&
@@ -750,12 +758,12 @@
             {
                 String basePrefix = QNameHelper.suggestPrefix( uri );
                 candidatePrefix = basePrefix;
-                
+
                 for ( int i = 1 ; ; i++ )
                 {
                     if (tryPrefix( candidatePrefix ))
                         break;
-                    
+
                     candidatePrefix = basePrefix + i;
                 }
             }
@@ -769,7 +777,7 @@
 
         return candidatePrefix;
     }
-    
+
     protected final String getUriMapping ( String uri )
     {
         assert _uriMap.get( uri ) != null;
@@ -782,7 +790,7 @@
 
         if (prefix != null && prefix.length() > 0)
             return prefix;
-        
+
         for ( Iterator keys = _prefixMap.keySet().iterator() ; keys.hasNext() ; )
         {
             prefix = (String) keys.next();
@@ -819,32 +827,32 @@
     public final String getNamespaceForPrefix ( String prefix )
     {
         assert !prefix.equals( "xml" ) || _prefixMap.get( prefix ).equals( Locale._xml1998Uri
);
-        
+
         return (String) _prefixMap.get( prefix );
     }
 
     //
     //
     //
-    
+
     static final class SynthNamespaceSaver extends Saver
     {
         LinkedHashMap _synthNamespaces = new LinkedHashMap();
-        
+
         SynthNamespaceSaver ( Cur c, XmlOptions options )
         {
             super( c, options );
         }
-        
+
         protected void syntheticNamespace (
             String prefix, String uri, boolean considerCreatingDefault )
         {
             _synthNamespaces.put( uri, considerCreatingDefault ? "" : prefix );
         }
-        
+
         protected boolean emitElement (
             SaveCur c, ArrayList attrNames, ArrayList attrValues ) { return false; }
-        
+
         protected void emitFinish    ( SaveCur c ) { }
         protected void emitText      ( SaveCur c ) { }
         protected void emitComment   ( SaveCur c ) { }
@@ -865,22 +873,22 @@
 
             boolean noSaveDecl =
                 options != null && options.hasOption( XmlOptions.SAVE_NO_XML_DECL
);
-            
+
             if (encoding != null && !noSaveDecl)
             {
                 XmlDocumentProperties props = Locale.getDocProps( c, false );
-                
+
                 String version = props == null ? null : props.getVersion();
 
                 if (version == null)
                     version = "1.0";
-                
+
                 emit( "<?xml version=\"" );
                 emit( version );
                 emit( "\" encoding=\"" + encoding + "\"?>" + _newLine );
             }
         }
-        
+
         protected boolean emitElement ( SaveCur c, ArrayList attrNames, ArrayList attrValues
)
         {
             assert c.isElem();
@@ -908,14 +916,14 @@
                 return false;
             }
         }
-        
+
         protected void emitFinish ( SaveCur c )
         {
             emit( "</" );
             emitName( c.getName(), false );
             emit( '>' );
         }
-        
+
         protected void emitXmlns ( String prefix, String uri )
         {
             assert prefix != null;
@@ -947,7 +955,7 @@
                 emitXmlns( mappingPrefix(), mappingUri() );
             }
         }
-                                     
+
         private void emitAttrHelper ( QName attrName, String attrValue )
         {
             emit( ' ' );
@@ -961,12 +969,12 @@
         protected void emitText ( SaveCur c )
         {
             assert c.isText();
-            
+
             emit( c );
 
             entitizeContent();
         }
-        
+
         protected void emitComment ( SaveCur c )
         {
             assert c.isComment();
@@ -979,7 +987,7 @@
             emit( c );
 
             c.pop();
-            
+
             entitizeComment();
             emit( "-->" );
         }
@@ -987,9 +995,9 @@
         protected void emitProcinst ( SaveCur c )
         {
             assert c.isProcinst();
-            
+
             emit( "<?" );
-            
+
             // TODO - encoding issues here?
             emit( c.getName().getLocalPart() );
 
@@ -1005,7 +1013,7 @@
             }
 
             c.pop();
-            
+
             emit( "?>" );
         }
 
@@ -1054,7 +1062,7 @@
         //
         //
         //
-        
+
         private void emitName ( QName name, boolean needsPrefix )
         {
             assert name != null;
@@ -1077,7 +1085,7 @@
                 // NOTE - Consider keeping the currently mapped default URI separate fromn
the
                 // _urpMap and _prefixMap.  This way, I would not have to look it up manually
                 // here
-                
+
                 if (needsPrefix && prefix.length() == 0)
                     prefix = getNonDefaultUriMapping( uri );
 
@@ -1101,7 +1109,7 @@
 
             _in = (_in + 1) % _buf.length;
         }
-        
+
         private void emit ( String s )
         {
             int cch = s == null ? 0 : s.length();
@@ -1123,14 +1131,14 @@
                 _in = (_in + cch) % _buf.length;
             }
         }
-        
+
         private void emit ( SaveCur c )
         {
             if (c.isText())
             {
                 Object src = c.getChars();
                 int cch = c._cchSrc;
-                
+
                 if (preEmit( cch ))
                     return;
 
@@ -1151,11 +1159,11 @@
             else
                 preEmit( 0 );
         }
-        
+
         private boolean preEmit ( int cch )
         {
             assert cch >= 0;
-            
+
             _lastEmitCch = cch;
 
             if (cch == 0)
@@ -1171,7 +1179,7 @@
             // if we are about to emit and there is noting in the buffer, reset
             // the buffer to be at the beginning so as to not grow it anymore
             // than needed.
-            
+
             if (used == 0)
             {
                 assert _in == _out;
@@ -1182,12 +1190,12 @@
             _lastEmitIn = _in;
 
             _free -= cch;
-            
+
             assert _free >= 0;
 
             return false;
         }
-        
+
         private void entitizeContent ( )
         {
             if (_lastEmitCch == 0)
@@ -1196,8 +1204,8 @@
             int i = _lastEmitIn;
             final int n = _buf.length;
 
-            boolean hasOutOfRange = false;
-            
+            boolean hasCharToBeReplaced = false;
+
             int count = 0;
             for ( int cch = _lastEmitCch ; cch > 0 ; cch-- )
             {
@@ -1205,14 +1213,14 @@
 
                 if (ch == '<' || ch == '&')
                     count++;
-                else if (isBadChar( ch ))
-                    hasOutOfRange = true;
+                else if (isBadChar( ch ) || isEscapedChar( ch ))
+                    hasCharToBeReplaced = true;
 
                 if (++i == n)
                     i = 0;
             }
 
-            if (count == 0 && !hasOutOfRange)
+            if (count == 0 && !hasCharToBeReplaced)
                 return;
 
             i = _lastEmitIn;
@@ -1220,7 +1228,6 @@
             //
             // Heuristic for knowing when to save out stuff as a CDATA.
             //
-
             if (_lastEmitCch > 32 && count > 5 &&
                   count * 100 / _lastEmitCch > 1)
             {
@@ -1272,6 +1279,8 @@
                         i = replace( i, "&gt;" );
                     else if (isBadChar( ch ))
                         i = replace( i, "?" );
+                    else if (isEscapedChar( ch ))
+                        i = replace( i, _replaceChar.getEscapedString( ch ) );
                     else
                         i++;
 
@@ -1394,7 +1403,7 @@
          * Test if a character is valid in xml character content. See
          * http://www.w3.org/TR/REC-xml#NT-Char
          */
-        
+
         private boolean isBadChar ( char ch )
         {
             return ! (
@@ -1405,6 +1414,14 @@
                 );
         }
 
+        /**
+         * Test if a character is to be replaced with an escaped value
+         */
+        private boolean isEscapedChar ( char ch )
+        {
+            return ( null != _replaceChar && _replaceChar.containsChar( ch ) );
+        }
+
         private int replace ( int i, String replacement )
         {
             assert replacement.length() > 0;
@@ -1421,7 +1438,7 @@
 
             if (dCch > _free)
                 i = resize( dCch, i );
-            
+
             assert _free >= 0;
 
             assert _free >= dCch;
@@ -1443,7 +1460,7 @@
             replacement.getChars( 0, dCch + 1, _buf, i );
 
             _free -= dCch;
-            
+
             assert _free >= 0;
 
             return i + dCch + 1;
@@ -1509,7 +1526,7 @@
                     System.arraycopy( _buf, 0, newBuf, used - _in, _in );
                     i = i >= _out ? i - _out : i + _out;
                 }
-                
+
                 _out = 0;
                 _in = used;
                 _free += newBuf.length - _buf.length;
@@ -1612,9 +1629,9 @@
                 }
 
                 _free += charsAvailable;
-                
+
                 assert _free >= 0;
-                
+
                 _in = 0;
             }
 
@@ -1651,7 +1668,7 @@
         private int    _out;
         private char[] _buf;
     }
-    
+
     static final class TextReader extends Reader
     {
         TextReader ( Cur c, XmlOptions options )
@@ -1668,7 +1685,7 @@
         public int read ( ) throws IOException
         {
             checkClosed();
-            
+
             if (_locale.noSync())         { _locale.enter(); try { return _textSaver.read();
} finally { _locale.exit(); } }
             else synchronized ( _locale ) { _locale.enter(); try { return _textSaver.read();
} finally { _locale.exit(); } }
         }
@@ -1676,7 +1693,7 @@
         public int read ( char[] cbuf ) throws IOException
         {
             checkClosed();
-            
+
             if (_locale.noSync())         { _locale.enter(); try { return _textSaver.read(
cbuf, 0, cbuf == null ? 0 : cbuf.length ); } finally { _locale.exit(); } }
             else synchronized ( _locale ) { _locale.enter(); try { return _textSaver.read(
cbuf, 0, cbuf == null ? 0 : cbuf.length ); } finally { _locale.exit(); } }
         }
@@ -1684,7 +1701,7 @@
         public int read ( char[] cbuf, int off, int len ) throws IOException
         {
             checkClosed();
-            
+
             if (_locale.noSync())         { _locale.enter(); try { return _textSaver.read(
cbuf, off, len ); } finally { _locale.exit(); } }
             else synchronized ( _locale ) { _locale.enter(); try { return _textSaver.read(
cbuf, off, len ); } finally { _locale.exit(); } }
         }
@@ -1694,12 +1711,12 @@
             if (_closed)
                 throw new IOException( "Reader has been closed" );
         }
-        
+
         private Locale    _locale;
         private TextSaver _textSaver;
         private boolean   _closed;
     }
-    
+
     static final class InputStreamSaver extends InputStream
     {
         InputStreamSaver ( Cur c, XmlOptions options )
@@ -1707,17 +1724,17 @@
             _locale = c._locale;
 
             _closed = false;
-            
+
             assert _locale.entered();
-            
+
             options = XmlOptions.maskNull( options );
-            
+
             _outStreamImpl = new OutputStreamImpl();
 
             String encoding = null;
 
             XmlDocumentProperties props = Locale.getDocProps( c, false );
-            
+
             if (props != null && props.getEncoding() != null)
                 encoding = EncodingMap.getIANA2JavaMapping( props.getEncoding() );
 
@@ -1765,11 +1782,11 @@
 
         // Having the gateway here is kinda slow for the single character case.  It may be
possible
         // to only enter the gate when there are no chars in the buffer.
-        
+
         public int read ( ) throws IOException
         {
             checkClosed();
-            
+
             if (_locale.noSync())         { _locale.enter(); try { return _outStreamImpl.read();
} finally { _locale.exit(); } }
             else synchronized ( _locale ) { _locale.enter(); try { return _outStreamImpl.read();
} finally { _locale.exit(); } }
         }
@@ -1777,13 +1794,13 @@
         public int read ( byte[] bbuf, int off, int len ) throws IOException
         {
             checkClosed();
-            
+
             if (bbuf == null)
                 throw new NullPointerException( "buf to read into is null" );
 
             if (off < 0 || off > bbuf.length)
                 throw new IndexOutOfBoundsException( "Offset is not within buf" );
-            
+
             if (_locale.noSync())         { _locale.enter(); try { return _outStreamImpl.read(
bbuf, off, len ); } finally { _locale.exit(); } }
             else synchronized ( _locale ) { _locale.enter(); try { return _outStreamImpl.read(
bbuf, off, len ); } finally { _locale.exit(); } }
         }
@@ -1989,12 +2006,12 @@
             throws SAXException
         {
             super( c, options );
-            
+
             _contentHandler = ch;
             _lexicalHandler = lh;
 
             _attributes = new AttributesImpl();
-            
+
             _contentHandler.startDocument();
 
             try
@@ -2006,7 +2023,7 @@
             {
                 throw e._saxException;
             }
-            
+
             _contentHandler.endDocument();
         }
 
@@ -2016,7 +2033,7 @@
             {
                 _saxException = e;
             }
-            
+
             SAXException _saxException;
         }
 
@@ -2035,7 +2052,7 @@
 
             return prefix + ":" + local;
         }
-        
+
         private void emitNamespacesHelper ( )
         {
             for ( iterateMappings() ; hasMapping() ; nextMapping() )
@@ -2058,18 +2075,18 @@
                     _attributes.addAttribute( "http://www.w3.org/2000/xmlns/", "", "xmlns:"
+ prefix, "CDATA", uri );
             }
         }
-            
+
         protected boolean emitElement ( SaveCur c, ArrayList attrNames, ArrayList attrValues
)
         {
             _attributes.clear();
-            
+
             if (saveNamespacesFirst())
                 emitNamespacesHelper();
 
             for ( int i = 0 ; i < attrNames.size() ; i++ )
             {
                 QName name = (QName) attrNames.get( i );
-                
+
                 _attributes.addAttribute(
                     name.getNamespaceURI(), name.getLocalPart(), getPrefixedName( name ),
                     "CDATA", (String) attrValues.get( i ) );
@@ -2093,7 +2110,7 @@
 
             return false;
         }
-        
+
         protected void emitFinish ( SaveCur c )
         {
             QName name = c.getName();
@@ -2102,7 +2119,7 @@
             {
                 _contentHandler.endElement(
                     name.getNamespaceURI(), name.getLocalPart(), getPrefixedName( name )
);
-            
+
                 for ( iterateMappings() ; hasMapping() ; nextMapping() )
                     _contentHandler.endPrefixMapping( mappingPrefix() );
             }
@@ -2111,7 +2128,7 @@
                 throw new SaverSAXException( e );
             }
         }
-        
+
         protected void emitText ( SaveCur c )
         {
             assert c.isText();
@@ -2148,7 +2165,7 @@
                 throw new SaverSAXException( e );
             }
         }
-        
+
         protected void emitComment ( SaveCur c )
         {
             if (_lexicalHandler != null)
@@ -2189,11 +2206,11 @@
                 c.pop();
             }
         }
-        
+
         protected void emitProcinst ( SaveCur c )
         {
             String target = c.getName().getLocalPart();
-            
+
             c.push();
 
             c.next();
@@ -2235,7 +2252,7 @@
 
         private char[] _buf;
     }
-    
+
     //
     //
     //
@@ -2255,22 +2272,22 @@
         final boolean skip ( ) { toEnd(); return next(); }
 
         abstract void release ( );
-        
+
         abstract int kind ( );
-        
+
         abstract QName  getName ( );
         abstract String getXmlnsPrefix ( );
         abstract String getXmlnsUri ( );
-        
+
         abstract boolean isXmlns ( );
-        
+
         abstract boolean hasChildren  ( );
         abstract boolean hasText      ( );
-        
+
         abstract boolean toFirstAttr ( );
         abstract boolean toNextAttr ( );
         abstract String  getAttrValue ( );
-        
+
         abstract boolean next  ( );
         abstract void    toEnd ( );
 
@@ -2284,10 +2301,10 @@
         int _offSrc;
         int _cchSrc;
     }
-    
+
     // TODO - saving a fragment need to take namesapces from root and
     // reflect them on the document element
-    
+
     private static final class DocSaveCur extends SaveCur
     {
         DocSaveCur ( Cur c )
@@ -2301,34 +2318,34 @@
             _cur.release();
             _cur = null;
         }
-        
+
         int kind ( ) { return _cur.kind(); }
-        
+
         QName  getName        ( ) { return _cur.getName(); }
         String getXmlnsPrefix ( ) { return _cur.getXmlnsPrefix(); }
         String getXmlnsUri    ( ) { return _cur.getXmlnsUri(); }
-        
+
         boolean isXmlns       ( ) { return _cur.isXmlns();     }
-        
+
         boolean hasChildren   ( ) { return _cur.hasChildren(); }
         boolean hasText       ( ) { return _cur.hasText();     }
-        
+
         boolean toFirstAttr   ( ) { return _cur.toFirstAttr(); }
         boolean toNextAttr    ( ) { return _cur.toNextAttr();  }
         String  getAttrValue  ( ) { assert _cur.isAttr(); return _cur.getValueAsString();
}
-        
+
         void    toEnd         ( ) { _cur.toEnd();              }
         boolean next          ( ) { return _cur.next();        }
-        
+
         void push ( )         { _cur.push(); }
         void pop  ( )         { _cur.pop(); }
 
         List getAncestorNamespaces ( ) { return null; }
-        
+
         Object getChars ( )
         {
             Object o = _cur.getChars( -1 );
-            
+
             _offSrc = _cur._offSrc;
             _cchSrc = _cur._cchSrc;
 
@@ -2356,24 +2373,24 @@
             _cur.release();
             _cur = null;
         }
-        
+
         int kind ( ) { return _cur.kind(); }
-        
+
         QName  getName        ( ) { return _cur.getName();        }
         String getXmlnsPrefix ( ) { return _cur.getXmlnsPrefix(); }
         String getXmlnsUri    ( ) { return _cur.getXmlnsUri();    }
-        
+
         boolean isXmlns       ( ) { return _cur.isXmlns();      }
-        
+
         boolean hasChildren   ( ) { return _cur.hasChildren();  }
         boolean hasText       ( ) { return _cur.hasText();      }
-        
+
         boolean toFirstAttr   ( ) { return _cur.toFirstAttr();  }
         boolean toNextAttr    ( ) { return _cur.toNextAttr();   }
         String  getAttrValue  ( ) { return _cur.getAttrValue(); }
-        
+
         void toEnd ( ) { _cur.toEnd(); }
-        
+
         boolean next ( )
         {
             if (!_cur.next())
@@ -2381,29 +2398,29 @@
 
             if (!filter())
                 return true;
-            
+
             assert !isRoot() && !isText() && !isAttr();
-                
+
             toEnd();
-            
+
             return next();
         }
-        
+
         void push ( ) { _cur.push(); }
         void pop  ( ) { _cur.pop(); }
 
         List getAncestorNamespaces ( ) { return _cur.getAncestorNamespaces(); }
-        
+
         Object getChars ( )
         {
             Object o = _cur.getChars();
-            
+
             _offSrc = _cur._offSrc;
             _cchSrc = _cur._cchSrc;
 
             return o;
         }
-        
+
         XmlDocumentProperties getDocProps ( ) { return _cur.getDocProps(); }
 
         private SaveCur _cur;
@@ -2414,7 +2431,7 @@
         FilterPiSaveCur ( SaveCur c, String target )
         {
             super( c );
-            
+
             _piTarget = target;
         }
 
@@ -2436,9 +2453,9 @@
             _end = end.weakCur( this );
 
             _elem = synthElem;
-            
+
             _state = ROOT_START;
-            
+
             _stateStack = new int [ 8 ];
 
             start.push();
@@ -2450,11 +2467,11 @@
         {
             return _ancestorNamespaces;
         }
-        
+
         private void computeAncestorNamespaces ( Cur c )
         {
             _ancestorNamespaces = new ArrayList();
-            
+
             while ( c.toParentRaw() )
             {
                 if (c.toFirstAttr())
@@ -2467,7 +2484,7 @@
                             String uri = c.getXmlnsUri();
 
                             // Don't let xmlns:foo="" get used
-                            
+
                             if (uri.length() > 0 || prefix.length() == 0)
                             {
                                 _ancestorNamespaces.add( c.getXmlnsPrefix() );
@@ -2476,16 +2493,16 @@
                         }
                     }
                     while ( c.toNextAttr() );
-                    
+
                     c.toParent();
                 }
             }
         }
-        
+
         //
         //
         //
-        
+
         void release ( )
         {
             _cur.release();
@@ -2504,49 +2521,49 @@
             case ELEM_END   : return -ELEM;
             case ROOT_END   : return -ROOT;
             }
-            
+
             assert _state == CUR;
-            
+
             return _cur.kind();
         }
-        
+
         QName getName ( )
         {
             switch ( _state )
             {
             case ROOT_START :
             case ROOT_END   : return null;
-            case ELEM_START : 
+            case ELEM_START :
             case ELEM_END   : return _elem;
             }
-            
+
             assert _state == CUR;
 
             return _cur.getName();
         }
-        
+
         String getXmlnsPrefix ( )
         {
             assert _state == CUR && _cur.isAttr();
             return _cur.getXmlnsPrefix();
         }
-        
+
         String getXmlnsUri ( )
         {
             assert _state == CUR && _cur.isAttr();
             return _cur.getXmlnsUri();
         }
-        
+
         boolean isXmlns ( )
         {
             assert _state == CUR && _cur.isAttr();
             return _cur.isXmlns();
         }
-        
+
         boolean hasChildren ( )
         {
             boolean hasChildren = false;
-            
+
             if (isContainer())
             {   // is there a faster way to do this?
                 push();
@@ -2554,17 +2571,17 @@
 
                 if (!isText() && !isFinish())
                     hasChildren = true;
-                
+
                 pop();
             }
 
             return hasChildren;
         }
-        
+
         boolean hasText ( )
         {
             boolean hasText = false;
-            
+
             if (isContainer())
             {
                 push();
@@ -2572,25 +2589,25 @@
 
                 if (isText())
                     hasText = true;
-                
+
                 pop();
             }
 
             return hasText;
         }
-        
+
         Object getChars ( )
         {
             assert _state == CUR && _cur.isText();
 
             Object src = _cur.getChars( -1 );
-            
+
             _offSrc = _cur._offSrc;
             _cchSrc = _cur._cchSrc;
 
             return src;
         }
-        
+
         boolean next ( )
         {
             switch ( _state )
@@ -2633,7 +2650,7 @@
 
                 break;
             }
-            
+
             case ELEM_END :
             {
                 _state = ROOT_END;
@@ -2645,7 +2662,7 @@
 
             return true;
         }
-        
+
         void toEnd ( )
         {
             switch ( _state )
@@ -2660,33 +2677,33 @@
 
             _cur.toEnd();
         }
-        
+
         boolean toFirstAttr ( )
         {
             switch ( _state )
             {
             case ROOT_END   :
-            case ELEM_END   : 
+            case ELEM_END   :
             case ROOT_START : return false;
             case CUR        : return _cur.toFirstAttr();
             }
-            
+
             assert _state == ELEM_START;
 
             if (!_cur.isAttr())
                 return false;
-            
+
             _state = CUR;
-                
+
             return true;
         }
-        
+
         boolean toNextAttr ( )
         {
             assert _state == CUR;
             return !_saveAttr && _cur.toNextAttr();
         }
-        
+
         String getAttrValue ( )
         {
             assert _state == CUR && _cur.isAttr();
@@ -2711,7 +2728,7 @@
             _cur.pop();
             _state = _stateStack [ --_stateStackSize ];
         }
-        
+
         XmlDocumentProperties getDocProps ( ) { return Locale.getDocProps(_cur, false); }
 
         //
@@ -2726,26 +2743,26 @@
         private QName _elem;
 
         private boolean _saveAttr;
-        
+
         private static final int ROOT_START = 1;
         private static final int ELEM_START = 2;
         private static final int ROOT_END   = 3;
         private static final int ELEM_END   = 4;
         private static final int CUR        = 5;
-        
+
         private int _state;
 
         private int[] _stateStack;
         private int   _stateStackSize;
     }
-    
+
     private static final class PrettySaveCur extends SaveCur
     {
         PrettySaveCur ( SaveCur c, XmlOptions options )
         {
             _sb = new StringBuffer();
             _stack = new ArrayList();
-            
+
             _cur = c;
 
             assert options != null;
@@ -2766,37 +2783,37 @@
         }
 
         List getAncestorNamespaces ( ) { return _cur.getAncestorNamespaces(); }
-        
+
         void release ( ) { _cur.release(); }
-        
+
         int kind ( ) { return _txt == null ? _cur.kind() : TEXT; }
-        
+
         QName  getName        ( ) { assert _txt == null; return _cur.getName(); }
         String getXmlnsPrefix ( ) { assert _txt == null; return _cur.getXmlnsPrefix(); }
         String getXmlnsUri    ( ) { assert _txt == null; return _cur.getXmlnsUri(); }
-        
+
         boolean isXmlns       ( ) { return _txt == null ? _cur.isXmlns()      : false; }
-        
+
         boolean hasChildren   ( ) { return _txt == null ? _cur.hasChildren() : false; }
         boolean hasText       ( ) { return _txt == null ? _cur.hasText()     : false; }
-        
+
         boolean toFirstAttr   ( ) { assert _txt == null; return _cur.toFirstAttr(); }
         boolean toNextAttr    ( ) { assert _txt == null; return _cur.toNextAttr(); }
         String  getAttrValue  ( ) { assert _txt == null; return _cur.getAttrValue(); }
-        
+
         void toEnd ( )
         {
             assert _txt == null;
             _cur.toEnd();
-            
+
             if (_cur.kind() == -ELEM)
                 _depth--;
         }
-        
+
         boolean next ( )
         {
             int k;
-            
+
             if (_txt != null)
             {
                 assert _txt.length() > 0;
@@ -2826,7 +2843,7 @@
                 k = _cur.kind();
 
                 // Check for non leaf, _prettyIndent < 0 means that the save is all on
one line
-                
+
                 if (_prettyIndent >= 0 &&
                       prevKind != COMMENT && prevKind != PROCINST && (prevKind
!= ELEM || k != -ELEM))
 //                if (prevKind != COMMENT && prevKind != PROCINST && (prevKind
!= ELEM || k != -ELEM))
@@ -2836,12 +2853,12 @@
                         _sb.insert( 0, _newLine );
                         spaces( _sb, _newLine.length(), _prettyOffset + _prettyIndent * _depth
);
                     }
-                    
+
                     if (k != -ROOT)
                     {
                         if (prevKind != ROOT)
                             _sb.append( _newLine );
-                        
+
                         int d = k < 0 ? _depth - 1 : _depth;
                         spaces( _sb, _sb.length(), _prettyOffset + _prettyIndent * d );
                     }
@@ -2861,21 +2878,21 @@
 
             return true;
         }
-        
+
         void push ( )
         {
             _cur.push();
             _stack.add( _txt );
             _stack.add( new Integer( _depth ) );
         }
-        
+
         void pop ( )
         {
             _cur.pop();
             _depth = ((Integer) _stack.remove( _stack.size() - 1 )).intValue();
             _txt = (String) _stack.remove( _stack.size() - 1 );
         }
-        
+
         Object getChars ( )
         {
             if (_txt != null)
@@ -2884,15 +2901,15 @@
                 _cchSrc = _txt.length();
                 return _txt;
             }
-            
+
             Object o = _cur.getChars();
-            
+
             _offSrc = _cur._offSrc;
             _cchSrc = _cur._cchSrc;
 
             return o;
         }
-        
+
         XmlDocumentProperties getDocProps ( ) { return _cur.getDocProps(); }
 
         final static void spaces ( StringBuffer sb, int offset, int count )
@@ -2927,21 +2944,22 @@
         private StringBuffer _sb;
 
         private int          _depth;
-        
+
         private ArrayList    _stack;
     }
-    
+
     //
     //
     //
 
     private final Locale _locale;
     private final long   _version;
-    
+
     private SaveCur _cur;
 
     private List    _ancestorNamespaces;
     private Map     _suggestedPrefixes;
+    protected XmlOptionCharEscapeMap _replaceChar;
     private boolean _useDefaultNamespace;
     private Map     _preComputedNamespaces;
     private boolean _saveNamespacesFirst;

Added: xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java
URL: http://svn.apache.org/viewcvs/xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java?rev=225349&view=auto
==============================================================================
--- xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java (added)
+++ xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptionCharEscapeMap.java Tue Jul 26
10:06:12 2005
@@ -0,0 +1,142 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.xmlbeans;
+
+import java.util.HashMap;
+
+/**
+ * Corresponds to the Saver and XmlOptions.
+ * <p>
+ * This class is used to set up a map containing characters to be escaped.
+ * Characters can be escaped as hex, decimal or as a predefined entity (this
+ * latter option applies only to the 5 characters defined as predefined entities
+ * in the XML Spec).
+ * <p>
+ * <ul>
+ * For example:
+ * <pre>
+ *      XmlOptionCharEscapeMap escapes = new XmlOptionCharEscapeMap();
+ *      escapes.addMapping('A', XmlOptionCharEscapeMap.HEXADECIMAL);
+ *      escapes.addMapping('B', XmlOptionCharEscapeMap.DECIMAL);
+ *      escapes.addMapping('>', XmlOptionCharEscapeMap.PREDEF_ENTITY);
+ *
+ *      XmlOptions opts = new XmlOptions();
+ *      opts.setSaveSubstituteCharacters(escapes);
+ *      System.out.println(myXml.xmlText(opts));
+ *
+ *      will result in:
+ *      A being printed as &#x41;
+ *      B being printed as &#66;
+ *      > being printed as &gt;
+ *
+ * </pre>
+ */
+public class XmlOptionCharEscapeMap
+{
+    public static final int PREDEF_ENTITY = 0;
+    public static final int DECIMAL       = 1;
+    public static final int HEXADECIMAL   = 2;
+
+    // map of Character to String which will represent it in the output document
+    private HashMap _charMap;
+
+    // internal HashMap just for predefined entities
+    private static final HashMap _predefEntities = new HashMap();
+    static {
+        _predefEntities.put(new Character('<'), "&lt;");
+        _predefEntities.put(new Character('>'), "&gt;");
+        _predefEntities.put(new Character('&'), "&amp;");
+        _predefEntities.put(new Character('\''), "&apos;");
+        _predefEntities.put(new Character('"'), "&quot;");
+    }
+
+    /**
+     * Construct a new XmlOptionCharEncoder.
+     */
+    public XmlOptionCharEscapeMap()
+    {
+        _charMap = new HashMap();
+    }
+
+    /**
+     *  @return whether a character encoding exists for this character
+     */
+    public boolean containsChar(char ch)
+    {
+        return _charMap.containsKey(new Character(ch));
+    }
+
+    /**
+     * set up this character to be escaped in output documents
+     * according to the given mode
+     */
+    public void addMapping(char ch, int mode) throws XmlException
+    {
+        Character theChar = new Character(ch);
+        switch(mode)
+        {
+            case PREDEF_ENTITY:
+                String replString = (String)_predefEntities.get(theChar);
+                if ( replString == null )
+                {
+                    throw new XmlException("XmlOptionCharEncoderMap.addMapping(): " +
+                        "the PREDEF_ENTITY mode can only be used for the following " +
+                        "characters: <, >, &, \" and '");
+                }
+                _charMap.put(theChar, replString);
+                break;
+
+            case DECIMAL:
+                _charMap.put(theChar, "&#" + (int)ch + ";");
+                break;
+
+            case HEXADECIMAL:
+                String hexCharPoint = Integer.toHexString((int)ch);
+                _charMap.put(theChar, "&#x" + hexCharPoint + ";");
+                break;
+
+            default:
+                throw new XmlException("XmlOptionCharEncoderMap.addMapping(): " +
+                    "mode must be PREDEF_ENTITY, DECIMAL or HEXADECIMAL");
+        }
+    }
+
+    /**
+     * set up this contiguous set of characters to be escaped in
+     * output documents according to the given mode
+     */
+    public void addMappings(char ch1, char ch2, int mode) throws XmlException
+    {
+        if (ch1 > ch2)
+        {
+            throw new XmlException("XmlOptionCharEncoderMap.addMappings(): " +
+                "ch1 must be <= ch2");
+        }
+
+        for (char c = ch1; c <= ch2; c++)
+        {
+            addMapping(c, mode);
+        }
+    }
+
+    /**
+     * returns the escaped String for the character
+     */
+    public String getEscapedString(char ch)
+    {
+        return (String)_charMap.get(new Character(ch));
+    }
+}

Modified: xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptions.java
URL: http://svn.apache.org/viewcvs/xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptions.java?rev=225349&r1=225348&r2=225349&view=diff
==============================================================================
--- xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptions.java (original)
+++ xmlbeans/trunk/src/xmlpublic/org/apache/xmlbeans/XmlOptions.java Tue Jul 26 10:06:12 2005
@@ -309,6 +309,23 @@
     }
 
     /**
+     * This option causes the saver to replace characters with other values in
+     * the output stream.  It is intended to be used for escaping non-standard
+     * characters during output.
+     * 
+     * @param characterReplacementMap is an XmlOptionCharEscapeMap containing
+     * the characters to be escaped.
+     * 
+     * @see XmlTokenSource#save(java.io.File, XmlOptions)
+     * @see XmlTokenSource#xmlText(XmlOptions)
+     * @see XmlOptionCharEscapeMap
+     */
+    public XmlOptions setSaveSubstituteCharacters (
+        XmlOptionCharEscapeMap characterReplacementMap) {
+        return set( SAVE_SUBSITITUTE_CHARACTERS, characterReplacementMap );
+    }
+
+    /**
      * When saving a fragment, this option changes the qname of the synthesized
      * root element.  Normally &lt;xml-fragment&gt; is used.
      * 
@@ -714,7 +731,8 @@
     public static final String SAVE_INNER                      = "SAVE_INNER";
     /** @exclude */
     public static final String SAVE_NO_XML_DECL                = "SAVE_NO_XML_DECL";
-    
+    /** @exclude */
+    public static final String SAVE_SUBSITITUTE_CHARACTERS     = "SAVE_SUBSITITUTE_CHARACTERS";
     /** @exclude */
     public static final String LOAD_REPLACE_DOCUMENT_ELEMENT   = "LOAD_REPLACE_DOCUMENT_ELEMENT";
     /** @exclude */



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlbeans.apache.org
For additional commands, e-mail: commits-help@xmlbeans.apache.org


Mime
View raw message