protected AbstractStructuredDataAccessPointAdapter wrapElement(TypedXPath xPath, Object value) {
    AbstractStructuredDataAccessPointAdapter adapter = null;

    if (null != adapters) {
      // was this value wrapped before?
      adapter = (AbstractStructuredDataAccessPointAdapter) adapters.get(xPath);
    }
    if (null == adapter) {
      if (xPath.isList()) {
        adapter = new StructuredDataListAccessor(xPath, null, isConstant());
      } else if (BigData.NULL == xPath.getType() || xPath.getChildXPaths().size() > 0) {
        adapter = new StructuredDataMapAccessor(xPath, null, isConstant());
      }
      if (null == adapters) {
        this.adapters = CollectionUtils.newMap();
      }
      adapters.put(xPath, adapter);
    }

    if (null != adapter) {
      if (adapter.getValue() != value) {
        adapter.bindValue(value);
      }
    }

    return adapter;
  }
  protected TypedXPath getChildXPath(String name) {
    TypedXPath result = null;

    if (null != xPath) {
      // if the "@" property is requested, assume it points to the
      // content of the current element
      if (StructuredDataConverter.NODE_VALUE_KEY.equals(name)) {
        return this.xPath;
      }

      // TODO evaluate type of attribute, if defined

      if (xPath.isList() && "[]".equals(name)) {
        return new ListValuedXPathAdapter(xPath);
      }

      result = xPath.getChildXPath(name);

      if (result == null && !name.startsWith(StructuredDataConverter.NODE_VALUE_KEY)) {
        // try to search for an attribute xpath if no element xpath was found
        // this allows to access attributes using element.attributeName
        // as well as element["@attributeName"
        result = xPath.getChildXPath(StructuredDataConverter.NODE_VALUE_KEY + name);
      }
    }

    return result;
  }