Example usage for org.dom4j Element getData

List of usage examples for org.dom4j Element getData

Introduction

In this page you can find the example usage for org.dom4j Element getData.

Prototype

Object getData();

Source Link

Document

Accesses the data of this element which may implement data typing bindings such as XML Schema or Java Bean bindings or will return the same value as #getText

Usage

From source file:org.orbeon.oxf.transformer.xupdate.TemplatesHandlerImpl.java

License:Open Source License

private Statement[] parseStatements(List nodes) {
    List statements = new ArrayList();
    for (Iterator i = nodes.iterator(); i.hasNext();) {
        Node node = (Node) i.next();
        if (node.getNodeType() == Node.TEXT_NODE) {
            if (!"".equals(node.getText().trim()))
                statements.add(new Text(node.getText().trim()));
        } else if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element element = (Element) node;
            NamespaceContext namespaceContext = new SimpleNamespaceContext(
                    Dom4jUtils.getNamespaceContext(element));
            if (XUpdateConstants.XUPDATE_NAMESPACE_URI.equals(element.getNamespaceURI())) {
                if (element.getName().equals("remove")) {
                    statements.add(new Remove((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("update")) {
                    statements//from  w w w  . java 2s.  c om
                            .add(new Update((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("append")) {
                    statements.add(new Append((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext, element.attributeValue("child"),
                            parseStatements(element.content())));
                } else if (element.getName().equals("insert-before")) {
                    statements.add(
                            new InsertBefore((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("insert-after")) {
                    statements.add(
                            new InsertAfter((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("for-each")) {
                    statements
                            .add(new ForEach((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("while")) {
                    statements.add(new While((LocationData) element.getData(), element.attributeValue("select"),
                            namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("value-of")) {
                    statements.add(new ValueOf((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("copy-of")) {
                    statements.add(new CopyOf((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("node-set")) {
                    statements.add(new NodeSet((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("attribute")) {
                    statements.add(new Attribute((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("namespace")) {
                    statements.add(new Namespace((LocationData) element.getData(),
                            element.attributeValue("name"), element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("element")) {
                    statements.add(new DynamicElement((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("if")) {
                    statements.add(new If((LocationData) element.getData(), element.attributeValue("test"),
                            namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("choose")) {
                    List whenTests = new ArrayList();
                    List whenNamespaceContext = new ArrayList();
                    List whenStatements = new ArrayList();
                    for (Iterator j = element.elements("when").iterator(); j.hasNext();) {
                        Element whenElement = (Element) j.next();
                        whenTests.add(whenElement.attributeValue("test"));
                        whenNamespaceContext
                                .add(new SimpleNamespaceContext(Dom4jUtils.getNamespaceContext(whenElement)));
                        whenStatements.add(parseStatements(whenElement.content()));
                    }
                    Element otherwiseElement = element.element("otherwise");
                    statements.add(new Choose((LocationData) element.getData(),
                            (String[]) whenTests.toArray(new String[whenTests.size()]),
                            (NamespaceContext[]) whenNamespaceContext
                                    .toArray(new NamespaceContext[whenNamespaceContext.size()]),
                            (Statement[][]) whenStatements.toArray(new Statement[whenStatements.size()][]),
                            otherwiseElement == null ? null : parseStatements(otherwiseElement.content())));
                } else if (element.getName().equals("variable")) {
                    statements.add(new Variable((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("assign")) {
                    statements.add(new Assign((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("function")) {
                    statements.add(new Function((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("param")) {
                    statements.add(new Param((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("message")) {
                    statements.add(
                            new Message((LocationData) element.getData(), parseStatements(element.content())));
                } else if (element.getName().equals("error")) {
                    statements.add(
                            new Error((LocationData) element.getData(), parseStatements(element.content())));
                } else {
                    throw new ValidationException(
                            "Unsupported XUpdate element '" + element.getQualifiedName() + "'",
                            (LocationData) element.getData());
                }
            } else {
                Element staticElement = new NonLazyUserDataElement(element.getQName());
                List childNodes = new ArrayList();
                for (Iterator j = element.attributes().iterator(); j.hasNext();)
                    staticElement.add((org.dom4j.Attribute) ((org.dom4j.Attribute) j.next()).clone());
                for (Iterator j = element.content().iterator(); j.hasNext();) {
                    Node child = (Node) j.next();
                    if (child instanceof org.dom4j.Namespace) {
                        staticElement.add((Node) child.clone());
                    } else {
                        childNodes.add(child);
                    }
                }
                statements.add(new StaticElement((LocationData) element.getData(), staticElement,
                        parseStatements(childNodes)));
            }
        } else if (node.getNodeType() == Node.NAMESPACE_NODE) {
            // Ignore namespace declarations
        } else {
            throw new OXFException("Unsupported node: " + node.getNodeTypeName());
        }
    }
    return (Statement[]) statements.toArray(new Statement[statements.size()]);
}

From source file:org.orbeon.oxf.transformer.xupdate.TemplatesHandlerImpl.java

License:Open Source License

/**
 * Parse a name / namespace attributes of <xu:element> and
 * <xu:attribute>/* w w w  .j a v a2  s  .c  om*/
 */
private QName parseQName(Element element) {
    String name = element.attributeValue("name");
    String namespace = element.attributeValue("namespace");
    int columnPosition = name.indexOf(':');

    // Check syntax of qname
    if (columnPosition == 0 || columnPosition == name.length() - 1)
        throw new ValidationException("Invalid qname '" + name + "'", (LocationData) element.getData());

    if (columnPosition == -1 && namespace == null) {
        // Simple name
        return new QName(name);
    } else if (columnPosition != -1 && namespace == null) {
        // Qualified name using namespace declaration in context
        String prefix = name.substring(0, columnPosition);
        String namespaceFromContext = (String) Dom4jUtils.getNamespaceContext(element).get(prefix);
        if (namespaceFromContext == null)
            throw new ValidationException("No namespace declared for prefix '" + prefix + "'",
                    (LocationData) element.getData());
        return new QName(name.substring(columnPosition + 1),
                new org.dom4j.Namespace(prefix, namespaceFromContext));
    } else if (columnPosition == -1 && namespace != null) {
        // Non-qualified name with namespace declaration
        return new QName(name, new org.dom4j.Namespace("", namespace));
    } else if (columnPosition != -1 && namespace != null) {
        // Qualified name using namespace specified
        return new QName(name.substring(columnPosition + 1),
                new org.dom4j.Namespace(name.substring(0, columnPosition), namespace));
    } else {
        // This can't happen
        throw new OXFException("Invalid state");
    }
}

From source file:org.orbeon.oxf.xforms.action.actions.XFormsRefreshAction.java

License:Open Source License

public void execute(XFormsActionInterpreter actionInterpreter, Element actionElement, Scope actionScope,
        boolean hasOverriddenContext, Item overriddenContext) {

    final XFormsContainingDocument containingDocument = actionInterpreter.containingDocument();

    final String modelId = actionElement.attributeValue(XFormsConstants.MODEL_QNAME);
    final XFormsModel model = actionInterpreter.resolveModel(actionElement, modelId);

    if (model == null)
        throw new ValidationException("Invalid model id: " + modelId, (LocationData) actionElement.getData());

    // NOTE: We no longer need to force the refresh flag here because the refresh flag is global. If a change in any
    // model occurred, then the flag will be already set and we are safe. Otherwise, it is safe not to do anything.
    Dispatch.dispatchEvent(new XFormsRefreshEvent(containingDocument, model));
}

From source file:org.orbeon.oxf.xforms.action.XFormsActionInterpreter.java

License:Open Source License

/**
 * Execute an XForms action.//from  w w  w .  j a v  a  2  s.  c  o m
 */
public void runAction(ElementAnalysis actionAnalysis) {

    final Element actionElement = actionAnalysis.element();
    final ActionTrait actionTrait = (ActionTrait) actionAnalysis;

    try {

        // Condition
        final String ifConditionAttribute = actionTrait.ifConditionJava();
        final String whileIterationAttribute = actionTrait.whileConditionJava();
        final String iterateIterationAttribute = actionTrait.iterateJava();

        // Push @iterate (if present) within the @model and @context context
        final NamespaceMapping namespaceMapping = actionAnalysis.namespaceMapping();
        // TODO: function context
        _actionXPathContext.pushBinding(iterateIterationAttribute, actionAnalysis.contextJava(), null,
                actionAnalysis.modelJava(), null, actionElement, namespaceMapping,
                getSourceEffectiveId(actionElement), actionAnalysis.scope(), false);

        // NOTE: At this point, the context has already been set to the current action element
        if (iterateIterationAttribute != null) {
            // Gotta iterate

            // NOTE: It's not 100% how @context and @iterate should interact here. Right now @iterate overrides @context,
            // i.e. @context is evaluated first, and @iterate sets a new context for each iteration
            {
                final List<Item> currentNodeset = _actionXPathContext.getCurrentNodeset();
                final int iterationCount = currentNodeset.size();
                for (int index = 1; index <= iterationCount; index++) {

                    // Push iteration
                    _actionXPathContext.pushIteration(index);

                    final Item overriddenContextNodeInfo = currentNodeset.get(index - 1);
                    runSingleIteration(actionAnalysis, actionElement.getQName(), ifConditionAttribute,
                            whileIterationAttribute, true, overriddenContextNodeInfo);

                    // Restore context
                    _actionXPathContext.popBinding();
                }
            }
        } else {
            // Do a single iteration run (but this may repeat over the @while condition!)
            runSingleIteration(actionAnalysis, actionElement.getQName(), ifConditionAttribute,
                    whileIterationAttribute, _actionXPathContext.hasOverriddenContext(),
                    _actionXPathContext.getContextItem());
        }

        // Restore
        _actionXPathContext.popBinding();
    } catch (Exception e) {
        throw OrbeonLocationException.wrapException(e,
                new ExtendedLocationData((LocationData) actionElement.getData(), "running XForms action",
                        actionElement,
                        new String[] { "action name", actionElement.getQName().getQualifiedName() }));
    }
}

From source file:org.orbeon.oxf.xforms.action.XFormsActionInterpreter.java

License:Open Source License

/**
 * Evaluate an expression as a string. This returns "" if the result is an empty sequence.
 *//*from  w ww .ja  v a 2  s .c  o m*/
public String evaluateAsString(Element actionElement, List<Item> nodeset, int position,
        String xpathExpression) {

    // Setup function context
    final XFormsFunction.Context functionContext = _actionXPathContext
            .getFunctionContext(getSourceEffectiveId(actionElement));

    // @ref points to something
    final String result = XPathCache.evaluateAsString(nodeset, position, xpathExpression,
            getNamespaceMappings(actionElement), _actionXPathContext.getCurrentVariables(),
            XFormsContainingDocument.getFunctionLibrary(), functionContext, null,
            (LocationData) actionElement.getData(), containingDocument().getRequestStats().getReporter());

    // Restore function context
    _actionXPathContext.returnFunctionContext();

    return result != null ? result : "";
}

From source file:org.orbeon.oxf.xforms.action.XFormsActionInterpreter.java

License:Open Source License

public List<Item> evaluateKeepItems(Element actionElement, List<Item> nodeset, int position,
        String xpathExpression) {

    // Setup function context
    final XFormsFunction.Context functionContext = _actionXPathContext
            .getFunctionContext(getSourceEffectiveId(actionElement));

    // @ref points to something
    final List<Item> result = XPathCache.evaluateKeepItems(nodeset, position, xpathExpression,
            getNamespaceMappings(actionElement), _actionXPathContext.getCurrentVariables(),
            XFormsContainingDocument.getFunctionLibrary(), functionContext, null,
            (LocationData) actionElement.getData(), containingDocument().getRequestStats().getReporter());

    // Restore function context
    _actionXPathContext.returnFunctionContext();

    return result;
}

From source file:org.orbeon.oxf.xforms.action.XFormsActionInterpreter.java

License:Open Source License

/**
 * Resolve a value which may be an AVT./*from   w  ww.j  a va2 s .c om*/
 *
 * @param actionElement     action element
 * @param attributeValue    raw value to resolve
 * @return                  resolved attribute value, null if the value is null or if the XPath context item is missing
 */
public String resolveAVTProvideValue(Element actionElement, String attributeValue) {

    if (attributeValue == null)
        return null;

    // Whether this can't be an AVT
    final String resolvedAVTValue;
    if (XFormsUtils.maybeAVT(attributeValue)) {
        // We have to go through AVT evaluation
        final BindingContext bindingContext = _actionXPathContext.getCurrentBindingContext();

        // We don't have an evaluation context so return
        // CHECK: In the future we want to allow an empty evaluation context so do we really want this check?
        if (bindingContext.getSingleItem() == null)
            return null;

        final NamespaceMapping namespaceMapping = getNamespaceMappings(actionElement);
        final LocationData locationData = (LocationData) actionElement.getData();

        // Setup function context
        final XFormsFunction.Context functionContext = _actionXPathContext
                .getFunctionContext(getSourceEffectiveId(actionElement));

        resolvedAVTValue = XPathCache.evaluateAsAvt(bindingContext.getNodeset(), bindingContext.getPosition(),
                attributeValue, namespaceMapping, _actionXPathContext.getCurrentVariables(),
                XFormsContainingDocument.getFunctionLibrary(), functionContext, null, locationData,
                containingDocument().getRequestStats().getReporter());

        // Restore function context
        _actionXPathContext.returnFunctionContext();
    } else {
        // We optimize as this doesn't need AVT evaluation
        resolvedAVTValue = attributeValue;
    }

    return resolvedAVTValue;
}

From source file:org.orbeon.oxf.xforms.action.XFormsActionInterpreter.java

License:Open Source License

/**
 * Search a model given a static id and/or the current action element.
 *
 * @param actionElement     current action element
 * @param modelStaticId     static id of the model searched, or null if current model
 * @return                  model//ww  w  .j  a  v a2 s.  c o m
 */
public XFormsModel resolveModel(Element actionElement, String modelStaticId) {
    final XFormsModel model;
    if (modelStaticId != null) {
        // Id is specified, resolve the effective object
        final XFormsObject o = resolveObject(actionElement, modelStaticId);
        if (!(o instanceof XFormsModel))
            throw new ValidationException("Invalid model id: " + modelStaticId,
                    (LocationData) actionElement.getData());
        model = (XFormsModel) o;
    } else {
        // Id is not specified
        model = _actionXPathContext.getCurrentModel();
    }
    if (model == null)
        throw new ValidationException("Invalid model id: " + modelStaticId,
                (LocationData) actionElement.getData());
    return model;
}

From source file:org.orbeon.oxf.xforms.InstanceData.java

License:Open Source License

private static InstanceData createNewInstanceData(Node node) {
    final InstanceData instanceData;
    if (node instanceof Element) {
        final Element element = (Element) node;
        instanceData = InstanceData.createNewInstanceData(element.getData());
        element.setData(instanceData);/*w  w w . j a  va2 s .  c o m*/
    } else if (node instanceof Attribute) {
        final Attribute attribute = (Attribute) node;
        instanceData = InstanceData.createNewInstanceData(attribute.getData());
        attribute.setData(instanceData);
    } else if (node instanceof Document) {
        // We can't store data on the Document object. Use root element instead.
        final Element element = ((Document) node).getRootElement();
        instanceData = InstanceData.createNewInstanceData(element.getData());
        element.setData(instanceData);
    } else {
        // No other node type is supported
        throw new OXFException("Cannot create InstanceData on node type: " + node.getNodeTypeName());
    }
    return instanceData;
}

From source file:org.orbeon.oxf.xforms.itemset.XFormsItemUtils.java

License:Open Source License

/**
 * Evaluate the itemset for a given xf:select or xf:select1 control.
 *
 * @param select1Control        control to evaluate
 * @return                      Itemset//from   w  w  w .j a v  a  2  s .com
 */
public static Itemset evaluateItemset(final XFormsSelect1Control select1Control) {

    final SelectionControlTrait staticControl = (SelectionControlTrait) select1Control.staticControl();

    // Optimize static itemsets
    if (staticControl.hasStaticItemset())
        return staticControl.staticItemset().get();

    final boolean isMultiple = staticControl.isMultiple();
    final XBLContainer container = select1Control.container();

    final Itemset result = new Itemset(isMultiple);

    // Set binding on this control, after saving the current context because the context stack must
    // remain unmodified.
    final XFormsContextStack contextStack = container.getContextStack();
    final BindingContext savedBindingContext = contextStack.getCurrentBindingContext();
    contextStack.setBinding(select1Control.bindingContext());

    // TODO: This visits all of the control's descendants. It should only visit the top-level item|itemset|choices elements.
    final boolean isEncryptItemValues = select1Control.isEncryptValues();
    Dom4jUtils.visitSubtree(select1Control.element(), new Dom4jUtils.VisitorListener() {

        private int position = 0;
        private ItemContainer currentContainer = result;

        private String getElementEffectiveId(Element element) {
            return XFormsUtils.getRelatedEffectiveId(select1Control.getEffectiveId(),
                    XFormsUtils.getElementId(element));
        }

        public void startElement(Element element) {
            final String localname = element.getName();

            if (XFormsConstants.XFORMS_ITEM_QNAME.getName().equals(localname)) {
                // xf:item

                contextStack.pushBinding(element, getElementEffectiveId(element),
                        select1Control.getChildElementScope(element));

                final Label label = getLabelValue(element.element(XFormsConstants.LABEL_QNAME));
                final String value = getValueValue(element.element(XFormsConstants.XFORMS_VALUE_QNAME));

                final Map<QName, String> attributes = getAttributes(element);
                currentContainer.addChildItem(Item.apply(position++, isMultiple, isEncryptItemValues,
                        attributes, label, StringUtils.defaultString(value)));

            } else if (XFormsConstants.XFORMS_ITEMSET_QNAME.getName().equals(localname)) {
                // xf:itemset

                contextStack.pushBinding(element, getElementEffectiveId(element),
                        select1Control.getChildElementScope(element));

                final BindingContext currentBindingContext = contextStack.getCurrentBindingContext();

                //if (model == null || model == currentBindingContext.getModel()) { // it is possible to filter on a particular model
                final List<org.orbeon.saxon.om.Item> currentNodeSet = currentBindingContext.getNodeset();
                if (currentNodeSet != null) {

                    // Node stack tracks the relative position of the current node wrt ancestor nodes
                    final Stack<org.orbeon.saxon.om.Item> nodeStack = new Stack<org.orbeon.saxon.om.Item>();
                    int currentLevel = 0;

                    final int iterationCount = currentNodeSet.size();
                    for (int currentPosition = 1; currentPosition <= iterationCount; currentPosition++) {

                        // Push iteration
                        contextStack.pushIteration(currentPosition);
                        {
                            final org.orbeon.saxon.om.Item currentNodeInfo = currentNodeSet
                                    .get(currentPosition - 1);

                            // Handle children of xf:itemset

                            // We support relevance of items as an extension to XForms

                            // NOTE: If a node is non-relevant, all its descendants will be non-relevant as
                            // well. If a node is non-relevant, it should be as if it had not even been part of
                            // the nodeset.
                            final boolean isRelevant = (!(currentNodeInfo instanceof NodeInfo))
                                    || InstanceData.getInheritedRelevant((NodeInfo) currentNodeInfo);
                            if (isRelevant) {
                                final Label label = getLabelValue(element.element(XFormsConstants.LABEL_QNAME));
                                final Element valueCopyElement;
                                {
                                    final Element valueElement = element
                                            .element(XFormsConstants.XFORMS_VALUE_QNAME);
                                    valueCopyElement = (valueElement != null) ? valueElement
                                            : element.element(XFormsConstants.XFORMS_COPY_QNAME);
                                }
                                if (valueCopyElement == null)
                                    throw new ValidationException(
                                            "xf:itemset element must contain one xf:value or one xf:copy element.",
                                            select1Control.getLocationData());

                                // Update stack and containers
                                if (nodeStack.size() != 0) {
                                    final int newLevel = getItemLevel(currentNodeInfo, nodeStack);
                                    if (newLevel == currentLevel) {
                                        //  We are staying at the same level, pop old item
                                        nodeStack.pop();
                                    } else if (newLevel < currentLevel) {
                                        //  We are going down one or more levels
                                        nodeStack.pop();
                                        for (int i = newLevel; i < currentLevel; i++) {
                                            nodeStack.pop();
                                            currentContainer = currentContainer.parent();
                                        }
                                    } else if (newLevel > currentLevel) {
                                        // Going up one level, set new container as last added child
                                        currentContainer = currentContainer.lastChild();
                                    }
                                    currentLevel = newLevel;
                                }

                                // Handle new item
                                if (valueCopyElement.getName()
                                        .equals(XFormsConstants.XFORMS_VALUE_QNAME.getName())) {
                                    // Handle xf:value
                                    // TODO: This could be optimized for xf:value/@ref|@value as we could get the expression from the cache only once
                                    final String value = getValueValue(valueCopyElement);

                                    // NOTE: At this point, if the value is null, we should consider the item
                                    // non-relevant if it is a leaf item. But we don't yet know if this item is
                                    // a leaf item, so we prune such non-relevant items later.

                                    final Map<QName, String> attributes = getAttributes(element);
                                    currentContainer.addChildItem(Item.apply(position++, isMultiple,
                                            isEncryptItemValues, attributes, label, value));
                                } else {
                                    // TODO: handle xf:copy
                                    throw new ValidationException("xf:copy is not yet supported.",
                                            select1Control.getLocationData());
                                }

                                // Always push the last item to the stack
                                nodeStack.push(currentNodeInfo);

                            }
                        }
                        contextStack.popBinding();
                    }
                }

            } else if (XFormsConstants.XFORMS_CHOICES_QNAME.getName().equals(localname)) {
                // xf:choices

                contextStack.pushBinding(element, getElementEffectiveId(element),
                        select1Control.getChildElementScope(element));

                final Element labelElement = element.element(XFormsConstants.LABEL_QNAME);
                if (labelElement != null) {
                    final Label label = getLabelValue(labelElement);

                    // NOTE: returned label can be null in some cases

                    final Map<QName, String> attributes = getAttributes(element);
                    final Item newContainer = Item.apply(position++, isMultiple, isEncryptItemValues,
                            attributes, label, null);
                    currentContainer.addChildItem(newContainer);
                    currentContainer = newContainer;
                }
            }
        }

        public void endElement(Element element) {
            final String localname = element.getName();
            if (XFormsConstants.XFORMS_ITEM_QNAME.getName().equals(localname)) {
                contextStack.popBinding();
            } else if (XFormsConstants.XFORMS_ITEMSET_QNAME.getName().equals(localname)) {
                contextStack.popBinding();
            } else if (XFormsConstants.XFORMS_CHOICES_QNAME.getName().equals(localname)) {
                contextStack.popBinding();

                final Element labelElement = element.element(XFormsConstants.LABEL_QNAME);
                if (labelElement != null) {
                    currentContainer = currentContainer.parent();
                }
            }
        }

        private String getValueValue(Element valueElement) {
            if (valueElement == null)
                throw new ValidationException("xf:item or xf:itemset must contain an xf:value element.",
                        select1Control.getLocationData());
            final Scope elementScope = select1Control.getChildElementScope(valueElement);
            final String elementEffectiveId = getElementEffectiveId(valueElement);
            return XFormsUtils.getChildElementValue(container, elementEffectiveId, elementScope, valueElement,
                    false, false, null);
        }

        private Label getLabelValue(Element labelElement) {
            if (labelElement == null)
                throw new ValidationException("xf:item or xf:itemset must contain an xf:label element.",
                        select1Control.getLocationData());
            final Scope elementScope = select1Control.getChildElementScope(labelElement);
            final String elementEffectiveId = getElementEffectiveId(labelElement);
            final boolean supportsHTML = select1Control.isFullAppearance(); // Only support HTML when appearance is "full"
            final boolean[] containsHTML = new boolean[] { false };

            // FIXME: Would be good to do this check statically
            final boolean defaultToHTML = LHHAAnalysis.isHTML(labelElement);
            final String label = XFormsUtils.getChildElementValue(container, elementEffectiveId, elementScope,
                    labelElement, supportsHTML, defaultToHTML, containsHTML);
            return new Label(StringUtils.defaultString(label), containsHTML[0]);
        }

        private Map<QName, String> getAttributes(Element itemChoiceItemsetElement) {
            final String elementEffectiveId = getElementEffectiveId(itemChoiceItemsetElement);

            final Map<QName, String> result = new LinkedHashMap<QName, String>();
            for (QName attributeName : ATTRIBUTES_TO_PROPAGATE) {
                final String attributeValue = itemChoiceItemsetElement.attributeValue(attributeName);
                if (attributeValue != null)
                    addAttributeAVTValue(itemChoiceItemsetElement, attributeName, attributeValue,
                            elementEffectiveId, result);
            }
            return result;
        }

        private void addAttributeAVTValue(Element itemChoiceItemsetElement, QName attributeName,
                String attributeValue, String elementEffectiveId, Map<QName, String> result) {
            if (!XFormsUtils.maybeAVT(attributeValue)) {
                // Definitely not an AVT
                result.put(attributeName, attributeValue);
            } else {
                // Possible AVT
                final BindingContext currentBindingContext = contextStack.getCurrentBindingContext();
                final List<org.orbeon.saxon.om.Item> currentNodeset = currentBindingContext.getNodeset();
                if (currentNodeset != null && currentNodeset.size() > 0) {
                    String tempResult;
                    try {
                        tempResult = XPathCache.evaluateAsAvt(currentNodeset,
                                currentBindingContext.getPosition(), attributeValue,
                                container.getNamespaceMappings(itemChoiceItemsetElement),
                                contextStack.getCurrentVariables(),
                                XFormsContainingDocument.getFunctionLibrary(),
                                contextStack.getFunctionContext(elementEffectiveId), null,
                                (LocationData) itemChoiceItemsetElement.getData(),
                                container.getContainingDocument().getRequestStats().getReporter());
                    } catch (Exception e) {
                        XFormsError.handleNonFatalXPathError(container, e);
                        tempResult = "";
                    } finally {
                        contextStack.returnFunctionContext();
                    }

                    result.put(attributeName, tempResult);
                }
            }
        }

        public void text(Text text) {
        }

        /**
         * Return the item level for the given item. If the stack is empty, the level is 0.
         *
         * @param item      item to check
         * @param stack     stack of potential ancestors
         * @return          node level
         */
        private int getItemLevel(org.orbeon.saxon.om.Item item, Stack<org.orbeon.saxon.om.Item> stack) {
            // Iterate stack from top to bottom
            if (item instanceof NodeInfo) {
                int level = stack.size();
                // Only nodes can have ancestor relationship
                final NodeInfo nodeInfo = (NodeInfo) item;
                // Reverse order
                Collections.reverse(stack);
                for (Iterator<org.orbeon.saxon.om.Item> i = stack.iterator(); i.hasNext(); level--) {
                    final org.orbeon.saxon.om.Item currentItem = i.next();
                    if (currentItem instanceof NodeInfo) {
                        // Only nodes can have ancestor relationship
                        final NodeInfo currentNode = (NodeInfo) currentItem;
                        if (isAncestorNode(nodeInfo, currentNode)) {
                            // Restore order
                            Collections.reverse(stack);
                            return level;
                        }
                    }
                }
                // Restore order
                Collections.reverse(stack);
                return level;
            } else {
                // If it's not a node, stay at current level
                return stack.size() - 1;
            }
        }

        /**
         * Whether the given node has potentialAncestor as ancestor.
         *
         * @param node                  node to check
         * @param potentialAncestor     potential ancestor
         * @return                      true iif potentialAncestor is an ancestor of node
         */
        private boolean isAncestorNode(NodeInfo node, NodeInfo potentialAncestor) {
            NodeInfo parent = node.getParent();
            while (parent != null) {
                if (parent.isSameNodeInfo(potentialAncestor))
                    return true;
                parent = parent.getParent();
            }

            return false;
        }
    });

    // Make sure to restore the stack
    contextStack.setBinding(savedBindingContext);

    // Prune non-relevant children
    result.pruneNonRelevantChildren();

    return result;
}