diff --git a/src/main/java/org/apache/xmlbeans/XmlOptions.java b/src/main/java/org/apache/xmlbeans/XmlOptions.java index 1799da9b5..7ee0272a8 100644 --- a/src/main/java/org/apache/xmlbeans/XmlOptions.java +++ b/src/main/java/org/apache/xmlbeans/XmlOptions.java @@ -107,6 +107,7 @@ public enum XmlOptionsKeys { SAVE_CDATA_LENGTH_THRESHOLD, SAVE_CDATA_ENTITY_COUNT_THRESHOLD, SAVE_SAX_NO_NSDECLS_IN_ATTRIBUTES, + SAVE_EXTRA_NAMESPACES, LOAD_REPLACE_DOCUMENT_ELEMENT, LOAD_STRIP_WHITESPACE, LOAD_STRIP_COMMENTS, @@ -448,6 +449,23 @@ public Map getSaveSuggestedPrefixes() { return (Map) get(XmlOptionsKeys.SAVE_SUGGESTED_PREFIXES); } + /** + * A map of hints to pass to the saver for which prefixes to use + * for which namespace URI. + * + * @param extraNamespaces a map from URIs to prefixes + * @see XmlTokenSource#save(java.io.File, XmlOptions) + * @see XmlTokenSource#xmlText(XmlOptions) + */ + public XmlOptions setSaveExtraNamespaces(Map extraNamespaces) { + return set(XmlOptionsKeys.SAVE_EXTRA_NAMESPACES, extraNamespaces); + } + + @SuppressWarnings("unchecked") + public Map getSaveExtraNamespaces() { + return (Map) get(XmlOptionsKeys.SAVE_EXTRA_NAMESPACES); + } + /** * This option causes the saver to filter a Processing Instruction * with the given target diff --git a/src/main/java/org/apache/xmlbeans/impl/store/Saver.java b/src/main/java/org/apache/xmlbeans/impl/store/Saver.java index 14ef6080a..da6767f52 100755 --- a/src/main/java/org/apache/xmlbeans/impl/store/Saver.java +++ b/src/main/java/org/apache/xmlbeans/impl/store/Saver.java @@ -46,6 +46,9 @@ abstract class Saver { private SaveCur _cur; + protected boolean _isTopLevelElement = true; + protected final Map _extraNamespaces; + private List _ancestorNamespaces; private final Map _suggestedPrefixes; protected XmlOptionCharEscapeMap _replaceChar; @@ -135,6 +138,8 @@ protected void syntheticNamespace(String prefix, String uri, boolean considerDef _suggestedPrefixes = options.getSaveSuggestedPrefixes(); _ancestorNamespaces = _cur.getAncestorNamespaces(); + + _extraNamespaces = options.getSaveExtraNamespaces(); } private static SaveCur createSaveCur(Cur c, XmlOptions options) { @@ -287,10 +292,12 @@ protected final boolean process() { switch (_cur.kind()) { case ROOT: { processRoot(); + _isTopLevelElement = true; break; } case ELEM: { processElement(); + _isTopLevelElement = false; break; } case -ELEM: { @@ -899,6 +906,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emitNamespacesHelper(); } + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { emitAttrHelper(attrNames.get(i), attrValues.get(i)); } @@ -943,6 +952,17 @@ protected void emitXmlns(String prefix, String uri) { emit('"'); } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces) + return; + + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + emit(' '); + emitXmlns(nsEntry.getKey(), nsEntry.getValue()); + } + + } + private void emitNamespacesHelper() { LinkedHashMap nsMap = new LinkedHashMap<>(); for (iterateMappings(); hasMapping(); nextMapping()) { @@ -1853,6 +1873,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emit('<'); emitName(c.getName(), false); + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { emitAttrHelper(attrNames.get(i), attrValues.get(i)); } @@ -1902,6 +1924,15 @@ private void emitNamespacesHelper() { } } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces) + return; + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + emit(' '); + emitXmlns(nsEntry.getKey(), nsEntry.getValue()); + } + } + private void emitAttrHelper(QName attrName, String attrValue) { emit(' '); emitName(attrName, true); @@ -2578,6 +2609,15 @@ private String getPrefixedName(QName name) { return prefix + ":" + local; } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces|| !_nsAsAttrs) + return; + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + String prefix = nsEntry.getKey(); + _attributes.addAttribute("http://www.w3.org/2000/xmlns/", prefix, "xmlns:" + prefix , "CDATA", nsEntry.getValue()); + } + } + private void emitNamespacesHelper() { for (iterateMappings(); hasMapping(); nextMapping()) { String prefix = mappingPrefix(); @@ -2607,6 +2647,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emitNamespacesHelper(); } + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { QName name = attrNames.get(i);