private void handleReferenceEndElement() {
        // end of the ref data item so ensure it is persisted in the store
        valueCount++;
        try {
            if (mapName != null) {
                final RefDataLoader refDataLoader = Objects.requireNonNull(refDataLoaderHolder.getRefDataLoader());
                final MapDefinition mapDefinition = new MapDefinition(refDataLoader.getRefStreamDefinition(), mapName);

                if (key != null) {
                    LOGGER.trace("Putting key {} into map {}", key, mapDefinition);
                    refDataLoaderHolder.getRefDataLoader().put(mapDefinition, key, stagingValueOutputStream);
                } else if (rangeFrom != null && rangeTo != null) {
                    if (rangeFrom > rangeTo) {
                        errorReceiverProxy.log(Severity.ERROR, null, getElementId(),
                                "Range from '" + rangeFrom
                                + "' must be less than or equal to range to '" + rangeTo + "'",
                                null);
                    } else if (rangeFrom < 0) {
                        // negative values cause problems for the ordering of data in LMDB so prevent their use
                        // when using byteBuffer.putLong, -10, 0 & 10 will be stored in LMDB as 0, 10, -10
                        errorReceiverProxy.log(Severity.ERROR, null, getElementId(),
                                LogUtil.message(
                                        "Only non-negative numbers are supported (from: {}, to: {})",
                                        rangeFrom, rangeTo), null);

                    } else {
                        // convert from inclusive rangeTo to exclusive rangeTo
                        // if from==to we still record it as a range
                        final Range<Long> range = new Range<>(rangeFrom, rangeTo + 1);
                        LOGGER.trace("Putting range {} into map {}", range, mapDefinition);
                        refDataLoaderHolder.getRefDataLoader().put(mapDefinition, range, stagingValueOutputStream);
                    }
                }
            }
        } catch (final BufferOverflowException boe) {
            final String msg = LogUtil.message("Value for key {} in map {} is too big for the buffer",
                    key,
                    mapName);
            errorReceiverProxy.log(Severity.ERROR, null, getElementId(), msg, boe);
            LOGGER.error(msg, boe);
        } catch (final RuntimeException e) {
            errorReceiverProxy.log(Severity.ERROR, null, getElementId(), e.getMessage(), e);
            LOGGER.error("Error putting key {} into map {}: {} {}",
                    key, mapName, e.getClass().getSimpleName(), e.getMessage());
            LOGGER.debug("Error putting key {} into map {}: {}", key, mapName, e.getMessage(), e);
        }

        // Set keys to null.
        mapName = null;
        key = null;
        rangeFrom = null;
        rangeTo = null;
        haveSeenXmlInValueElement = false;
        valueXmlDefaultNamespaceUri = null;
    }
This method applies a post processing function if we are currently within
a function element. At this stage we should have details of the function
to apply from the corresponding start element and content to apply it to
from the characters event.

@param uri       The element's Namespace URI, or the empty string.
@param localName The element's local name, or the empty string.
@param qName     The element's qualified (prefixed) name, or the empty string.
@throws org.xml.sax.SAXException The client may throw an exception during processing.
@see stroom.pipeline.filter.AbstractXMLFilter#endElement(java.lang.String,
java.lang.String, java.lang.String)
stroom-pipeline/src/main/java/stroom/pipeline/refdata/ReferenceDataFilter.java