private void addData() {
        if (NullSafe.isBlankString(mapName)) {
            error("Null map name");
        } else if (stateDoc == null) {
            error("No state doc found for " + mapName);
        } else {
            // end of the ref data item so ensure it is persisted in the store
            valueCount++;
            try {
                final String tableName = stateDoc.getName();
                switch (stateDoc.getStateType()) {
                    case STATE -> {
                        if (key == null) {
                            error(LogUtil.message("Key is null for {}", tableName));
                        } else {
                            LOGGER.trace("Putting key {} into table {}", key, tableName);
                            final ByteBuffer value = stagingValueOutputStream.getByteBuffer();
                            value.flip();
                            stateMap.computeIfAbsent(stateDoc, k -> new ArrayList<>())
                                    .add(new State(key, typeId, value));
                            tryFlush();
                        }
                    }
                    case TEMPORAL_STATE -> {
                        if (key == null) {
                            error(LogUtil.message("Key is null for {}", tableName));
                        } else if (effectiveTime == null) {
                            error(LogUtil.message("Effective time is null for {}", tableName));
                        } else {
                            LOGGER.trace("Putting key {} into table {}", key, tableName);
                            final ByteBuffer value = stagingValueOutputStream.getByteBuffer();
                            value.flip();
                            temporalStateMap.computeIfAbsent(stateDoc, k -> new ArrayList<>())
                                    .add(new TemporalState(key, effectiveTime, typeId, value));
                            tryFlush();
                        }
                    }
                    case RANGED_STATE -> {
                        if (rangeFrom == null) {
                            error(LogUtil.message("Range from is null for {}", tableName));
                        } else if (rangeTo == null) {
                            error(LogUtil.message("Range to is null for {}", tableName));
                        } else if (rangeFrom > rangeTo) {
                            error(LogUtil.message(
                                    "Range from must be less than or equal to range to (from: {}, to: {}) for {}",
                                    rangeFrom, rangeTo, tableName));
                        } 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
                            error(LogUtil.message(
                                    "Only non-negative numbers are supported (from: {}, to: {}) for {}",
                                    rangeFrom, rangeTo, tableName));
                        } else {
                            final ByteBuffer value = stagingValueOutputStream.getByteBuffer();
                            value.flip();
                            rangedStateMap.computeIfAbsent(stateDoc, k -> new ArrayList<>())
                                    .add(new RangedState(rangeFrom, rangeTo, typeId, value));
                            tryFlush();
                        }
                    }
                    case TEMPORAL_RANGED_STATE -> {
                        if (rangeFrom == null) {
                            error(LogUtil.message("Range from is null for {}", tableName));
                        } else if (rangeTo == null) {
                            error(LogUtil.message("Range to is null for {}", tableName));
                        } else if (effectiveTime == null) {
                            error(LogUtil.message("Effective time is null for {}", tableName));
                        } else if (rangeFrom > rangeTo) {
                            error(LogUtil.message(
                                    "Range from must be less than or equal to range to (from: {}, to: {}) for {}",
                                    rangeFrom, rangeTo, tableName));
                        } 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
                            error(LogUtil.message(
                                    "Only non-negative numbers are supported (from: {}, to: {}) for {}",
                                    rangeFrom, rangeTo, tableName));
                        } else {
                            final ByteBuffer value = stagingValueOutputStream.getByteBuffer();
                            value.flip();
                            temporalRangedStateMap.computeIfAbsent(stateDoc, k -> new ArrayList<>())
                                    .add(new TemporalRangedState(rangeFrom, rangeTo, effectiveTime, typeId, value));
                            tryFlush();
                        }
                    }
                    case SESSION -> {
                        if (key == null) {
                            error(LogUtil.message("Session key is null for {}", tableName));
                        } else if (time == null) {
                            error(LogUtil.message("Session time is null for {}", tableName));
                        } else {
                            final Session.Builder sessionBuilder = new Session.Builder();
                            sessionBuilder.key(key);
                            sessionBuilder.start(time);
                            sessionBuilder.end(time);
                            if (start) {
                                if (timeout != null) {
                                    sessionBuilder.end(time.plus(timeout));
                                }
                            } else {
                                sessionBuilder.terminal(true);
                            }

                            LOGGER.trace("Putting session {} into table {}", key, tableName);
                            sessionMap.computeIfAbsent(stateDoc, k -> new ArrayList<>()).add(sessionBuilder.build());
                            tryFlush();
                        }
                    }
                    default -> error("Unexpected state type: " + stateDoc.getStateType());
                }
            } catch (final BufferOverflowException boe) {
                final String msg = LogUtil.message("Value for key {} in map {} is too big for the buffer",
                        key,
                        mapName);
                error(msg, boe);
                LOGGER.error(msg, boe);
            } catch (final RuntimeException e) {
                error(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;
        stateDoc = null;
        key = null;
        rangeFrom = null;
        rangeTo = null;
        haveSeenXmlInValueElement = false;
        valueXmlDefaultNamespaceUri = null;
        start = true;
        time = null;
        timeout = 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 SAXException The client may throw an exception during processing.
@see stroom.pipeline.filter.AbstractXMLFilter#endElement(String,
String, String)
stroom-state/stroom-state-impl/src/main/java/stroom/state/impl/pipeline/StateFilter.java