All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.event.NamespaceDifferencer Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.event;

import net.sf.saxon.s9api.Location;
import net.sf.saxon.lib.SaxonOutputKeys;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.SchemaType;

import java.util.Properties;
import java.util.Stack;

/**
 * 

NamespaceDifferencer is a {@link ProxyReceiver} responsible for removing duplicate namespace * declarations. It also ensures that namespace undeclarations are emitted when necessary.

* *

The NamespaceDifferencer assumes that in the input event stream, all in-scope namespaces for every element * are accounted for in the call on namespace(). In the output event stream, the namespace() call represents * namespace declarations rather than in-scope namespaces. So (a) redundant namespaces are removed, * and (b) namespace undeclarations are added where necessary. A namespace undeclaration for the default * namespace is always added if the parent element has a default namespace and the child element does not; * namespace undeclarations for other namespaces are emitted only when the serialization option undeclare-namespaces * is set.

* *

The {@code NamespaceDifferencer} is part of the serialization pipeline, responsible for translating result trees * to serialized XML. As such, it is not concerned with operations such as namespace fixup and namespace * inheritance that are part of the result tree construction process.

* *

The {@code NamespaceDifferencer} is also needed when writing output to tree models such as DOM and JDOM * that require local namespace declarations to be provided for each element node.

*/ public class NamespaceDifferencer extends ProxyReceiver { private boolean undeclareNamespaces = false; private final Stack namespaceStack = new Stack<>(); private NodeName currentElement; /** * Create a NamespaceDeclarer * * @param next the Receiver to which events will be passed after namespace reduction */ public NamespaceDifferencer(Receiver next, Properties details) { super(next); undeclareNamespaces = "yes".equals(details.getProperty(SaxonOutputKeys.UNDECLARE_PREFIXES)); namespaceStack.push(NamespaceMap.emptyMap()); } /** * startElement. This call removes redundant namespace declarations, and * possibly adds an xmlns="" undeclaration. */ @Override public void startElement(NodeName elemName, SchemaType type, AttributeMap attributes, NamespaceMap namespaces, Location location, int properties) throws XPathException { currentElement = elemName; NamespaceMap parentMap = namespaceStack.peek(); namespaceStack.push(namespaces); NamespaceMap delta = getDifferences(namespaces, parentMap, currentElement.hasURI(NamespaceUri.NULL)); nextReceiver.startElement(elemName, type, attributes, delta, location, properties); } @Override public void endElement() throws XPathException { namespaceStack.pop(); super.endElement(); } private NamespaceMap getDifferences(NamespaceMap thisMap, NamespaceMap parentMap, boolean elementInDefaultNamespace) throws XPathException { if (thisMap != parentMap) { NamespaceMap delta = NamespaceDeltaMap.emptyMap(); for (NamespaceBinding nb : thisMap) { NamespaceUri parentUri = parentMap.getNamespaceUri(nb.getPrefix()); if (parentUri == null) { delta = delta.put(nb.getPrefix(), nb.getNamespaceUri()); } else if (!parentUri.equals(nb.getNamespaceUri())) { delta = delta.put(nb.getPrefix(), nb.getNamespaceUri()); } } if (undeclareNamespaces) { for (NamespaceBinding nb : parentMap) { if (thisMap.getNamespaceUri(nb.getPrefix()) == null) { delta = delta.put(nb.getPrefix(), NamespaceUri.NULL); } } } else { // undeclare the default namespace if the parent element has a default namespace and the child does not // See also bug 4696, test if (!parentMap.getDefaultNamespace().isEmpty() && thisMap.getDefaultNamespace().isEmpty()) { delta = delta.put("", NamespaceUri.NULL); } } return delta; } return NamespaceMap.emptyMap(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy