@Override
    public T put(final String path, final T value) {
        if (path == null) {
            throw new IllegalArgumentException("Parameter path must not be null");
        }
        if (value == null) {
            return remove(path);
        }
        if (boundNode == null) {
            // If there is no context node yet, ignore if
            // we had read the dom before. We need to create it now.
            domChangeTracker.domChanged();
        }
        domChangeTracker.refreshForWriteIfNeeded();
        assert boundNode != null : "Bound node does not exist. No evaluation possible";
        final Document document = DOMHelper.getOwnerDocumentFor(baseNode);
        final DuplexExpression duplexExpression = new DuplexXPathParser(invocationContext.getProjector().config().getUserDefinedNamespaceMapping()).compile(path);
        if ((ExpressionType.ATTRIBUTE == duplexExpression.getExpressionType()) && ProjectionInvocationHandler.isStructureChangingType(valueType)) {
            throw new IllegalArgumentException("Value of type " + valueType + "can not be written to XML attributes. Choose a different xpath expression or use a different map component type");
        }
        try {
            final XPathExpression expression = invocationContext.getProjector().config().createXPath(document).compile(duplexExpression.getExpressionAsStringWithoutFormatPatterns());
            Node prevNode = (Node) expression.evaluate(boundNode, XPathConstants.NODE);
            final T previousValue = DefaultXPathEvaluator.convertToComponentType(invocationContext, prevNode, invocationContext.getTargetComponentType());
            if (ProjectionInvocationHandler.isStructureChangingValue(value)) {
                final Element parent = duplexExpression.ensureParentExistence(boundNode);
                if (Node.class.isAssignableFrom(invocationContext.getTargetComponentType())) {
                    if (!(value instanceof Node)) {
                        throw new IllegalArgumentException("Parameter value is not a DOM node.");
                    }
                    parent.appendChild((Node) value);
                    return previousValue;
                }
                if (invocationContext.getTargetComponentType().isInterface()) {
                    if (!(value instanceof DOMAccess)) {
                        throw new IllegalArgumentException("Parameter value is not a subprojection.");
                    }
                    // Dont't add the value, add a copy.
                    //parent.appendChild(DOMAccess.class.cast(value).getDOMNode());
                    DOMHelper.appendClone(parent, DOMAccess.class.cast(value).getDOMNode());
                }
                return previousValue;
            }
            assert boundNode != null : "Without bound node, there is no context where something could be created in.";
            Node node = duplexExpression.ensureExistence(boundNode);
            node.setTextContent(value.toString());

            return previousValue;
        } catch (XPathExpressionException e) {
            throw new XBPathException(e, path);
        }
    }
@ Override public T put ( final String path , final T value ) { if ( path == null ) { throw new IllegalArgumentException ( "Parameter path must not be null" ) ; } if ( value == null ) { return remove ( path ) ; } if ( boundNode == null ) { domChangeTracker . domChanged ( ) ; } domChangeTracker . refreshForWriteIfNeeded ( ) ; assert boundNode != null : "Bound node does not exist. No evaluation possible" ; final Document document = DOMHelper . getOwnerDocumentFor ( baseNode ) ; final DuplexExpression duplexExpression = new DuplexXPathParser ( invocationContext . getProjector ( ) . config ( ) . getUserDefinedNamespaceMapping ( ) ) . compile ( path ) ; if ( ( ExpressionType . ATTRIBUTE == duplexExpression . getExpressionType ( ) ) && ProjectionInvocationHandler . isStructureChangingType ( valueType ) ) { throw new IllegalArgumentException ( "Value of type " + valueType + "can not be written to XML attributes. Choose a different xpath expression or use a different map component type" ) ; } try { final XPathExpression expression = invocationContext . getProjector ( ) . config ( ) . createXPath ( document ) . compile ( duplexExpression . getExpressionAsStringWithoutFormatPatterns ( ) ) ; Node prevNode = ( Node ) expression . evaluate ( boundNode , XPathConstants . NODE ) ; final T previousValue = DefaultXPathEvaluator . convertToComponentType ( invocationContext , prevNode , invocationContext . getTargetComponentType ( ) ) ; if ( ProjectionInvocationHandler . isStructureChangingValue ( value ) ) { final Element parent = duplexExpression . ensureParentExistence ( boundNode ) ; if ( Node . class . isAssignableFrom ( invocationContext . getTargetComponentType ( ) ) ) { if ( ! ( value instanceof Node ) ) { throw new IllegalArgumentException ( "Parameter value is not a DOM node." ) ; } parent . appendChild ( ( Node ) value ) ; return previousValue ; } if ( invocationContext . getTargetComponentType ( ) . isInterface ( ) ) { if ( ! ( value instanceof DOMAccess ) ) { throw new IllegalArgumentException ( "Parameter value is not a subprojection." ) ; } DOMHelper . appendClone ( parent , DOMAccess . class . cast ( value ) . getDOMNode ( ) ) ; } return previousValue ; } assert boundNode != null : "Without bound node, there is no context where something could be created in." ; Node node = duplexExpression . ensureExistence ( boundNode ) ; node . setTextContent ( value . toString ( ) ) ; return previousValue ; } catch ( XPathExpressionException e ) { throw new XBPathException ( e , path ) ; } }
{@inheritDoc}