Example usage for org.dom4j Element createCopy

List of usage examples for org.dom4j Element createCopy

Introduction

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

Prototype

Element createCopy();

Source Link

Document

Creates a deep copy of this element The new element is detached from its parent, and getParent() on the clone will return null.

Usage

From source file:org.jivesoftware.openfire.sip.log.LogListenerImpl.java

License:Open Source License

public IQ logReceived(IQ iq) {

    String username = iq.getTo().toBareJID().split("@")[0];

    if (username != null) {

        CallLog callLog = new CallLog(username);
        Element pe = iq.getChildElement().element("callLog");

        if (pe != null) {

            Element numA = pe.element("numA");
            Element numB = pe.element("numB");
            Element duration = pe.element("duration");
            Element type = pe.element("type");

            callLog.setNumA((numA != null) ? numA.getTextTrim() : "");
            callLog.setNumB((numB != null) ? numB.getTextTrim() : "");
            callLog.setDateTime(new Date().getTime());
            callLog.setDuration((duration != null) ? Integer.parseInt(duration.getText()) : 0);
            if (type != null && "loss".equals(type.getTextTrim())) {
                // Backwards compatibility change
                type.setText("missed");
            }// ww w  .  j  a va 2  s . c o m
            callLog.setType((type != null) ? CallLog.Type.valueOf(type.getTextTrim()) : CallLog.Type.dialed);

            try {
                CallLogDAO.insert(callLog);
            } catch (SQLException e) {
                Log.error(e.getMessage(), e);
            }
        }
    }
    iq.setType(IQ.Type.result);

    iq.deleteExtension(CallLogExtension.ELEMENT_NAME, CallLogExtension.NAMESPACE);

    Element childElement = iq.getChildElement();
    if (childElement != null) {
        Element childElementCopy = childElement.createCopy();
        iq.setChildElement(childElementCopy);
    }
    return iq;
}

From source file:org.jivesoftware.openfire.vcard.VCardManager.java

License:Open Source License

/**
 * Returns the vCard of a given user or null if none was defined before. Changes to the
 * returned vCard will not be stored in the database. Use the returned vCard as a
 * read-only vCard./*from   w ww .  j a  v a  2s.com*/
 *
 * @param username Username (not full JID) whose vCard to retrieve.
 * @return the vCard of a given user.
 */
public Element getVCard(String username) {
    Element vCardElement = getOrLoadVCard(username);
    return vCardElement == null ? null : vCardElement.createCopy();
}

From source file:org.jivesoftware.openfire.websocket.XmppWebSocket.java

License:Open Source License

private void sendPacketError(Element stanza, PacketError.Condition condition) {
    Element reply = stanza.createCopy();
    reply.addAttribute("type", "error");
    reply.addAttribute("to", stanza.attributeValue("from"));
    reply.addAttribute("from", stanza.attributeValue("to"));
    reply.add(new PacketError(condition).getElement());
    deliver(reply.asXML());/*from www  . ja v  a  2 s. co m*/
}

From source file:org.jivesoftware.xmpp.workgroup.disco.IQDiscoInfoHandler.java

License:Open Source License

public IQ handleIQ(IQ packet) {
    if (packet.getType() == IQ.Type.result) {
        List<Element> features = packet.getChildElement().elements("feature");
        // Detect if this item is the MUC service
        for (Element feature : features) {
            String variable = feature.attributeValue("var");

            if ("http://jabber.org/protocol/muc".equals(variable)) {
                workgroupManager.setMUCServiceName(packet.getFrom().getDomain());
            }/* w  w w .j  a  va 2 s  . com*/
        }
        return null;
    }

    // Create a copy of the sent pack that will be used as the reply
    // we only need to add the requested info to the reply if any, otherwise add
    // a not found error
    IQ reply = IQ.createResultIQ(packet);

    // Check if the disco#info was sent to the workgroup service itself
    if (workgroupManager.getAddress().equals(packet.getTo())) {
        Element iq = packet.getChildElement();
        String node = iq.attributeValue("node");
        reply.setChildElement(iq.createCopy());
        Element queryElement = reply.getChildElement();

        if (node == null) {
            // Create and add a the identity of the workgroup service
            Element identity = queryElement.addElement("identity");
            identity.addAttribute("category", "collaboration");
            // TODO Get the name from a property
            identity.addAttribute("name", "Fastpath");
            identity.addAttribute("type", "workgroup");

            // Create and add a the feature provided by the workgroup service
            Element feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/workgroup");
            // Create and add a the disco#info feature
            feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/disco#info");
            // Indicate that we can provide information about the software version being used
            feature = queryElement.addElement("feature");
            feature.addAttribute("var", "jabber:iq:version");
            // Indicate that we support ad-hoc commands
            feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/commands");

            // Add the features provided by the features providers
            for (DiscoFeaturesProvider provider : featuresProviders) {
                for (String newFeature : provider.getFeatures()) {
                    feature = queryElement.addElement("feature");
                    feature.addAttribute("var", newFeature);
                }
            }
        } else if ("http://jabber.org/protocol/commands".equals(node)) {
            // Create and add a the identity of the workgroup service
            Element identity = queryElement.addElement("identity");
            identity.addAttribute("category", "collaboration");
            // TODO Get the name from a property
            identity.addAttribute("name", "Fastpath");
            identity.addAttribute("type", "workgroup");

            // Create and add a the disco#info feature
            Element feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/disco#info");
            // Indicate that we support ad-hoc commands
            feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/commands");
        } else {
            // Check if the node matches a supported command
            boolean found = false;
            for (AdHocCommand command : commandManager.getCommands()) {
                if (node.equals(command.getCode())) {
                    found = true;
                    // Only include commands that the sender can invoke (i.e. has enough permissions)
                    if (command.hasPermission(packet.getFrom())) {
                        // Create and add a the identity of the command
                        Element identity = queryElement.addElement("identity");
                        identity.addAttribute("category", "automation");
                        identity.addAttribute("name", command.getLabel());
                        identity.addAttribute("type", "command-node");

                        // Indicate that we support ad-hoc commands
                        Element feature = queryElement.addElement("feature");
                        feature.addAttribute("var", "http://jabber.org/protocol/commands");
                    } else {
                        // Return Forbidden error
                        reply.setError(PacketError.Condition.forbidden);
                    }
                }
            }
            if (!found) {
                // Return item_not_found error
                reply.setError(PacketError.Condition.item_not_found);
            }
        }

    } else {
        // Check if the disco#info was sent to a given workgroup
        try {
            Workgroup workgroup = workgroupManager.getWorkgroup(packet.getTo());
            Element iq = packet.getChildElement();
            reply.setChildElement(iq.createCopy());
            Element queryElement = reply.getChildElement();

            // Create and add a the identity of the workgroup service
            Element identity = queryElement.addElement("identity");
            identity.addAttribute("category", "collaboration");
            identity.addAttribute("name", workgroup.getJID().getNode());
            identity.addAttribute("type", "workgroup");

            // Create and add a the disco#info feature
            Element feature = queryElement.addElement("feature");
            feature.addAttribute("var", "http://jabber.org/protocol/disco#info");

            Element form = queryElement.addElement("x", "jabber:x:data");
            form.addAttribute("type", "result");
            // Add static field
            Element field = form.addElement("field");
            field.addAttribute("var", "FORM_TYPE");
            field.addAttribute("type", "hidden");
            field.addElement("value").setText("http://jabber.org/protocol/workgroup#workgroupinfo");
            // Add workgroup description
            field = form.addElement("field");
            field.addAttribute("var", "workgroup#description");
            field.addAttribute("label", "Description");
            field.addElement("value")
                    .setText(workgroup.getDescription() == null ? "" : workgroup.getDescription());
            // Add workgroup online status
            field = form.addElement("field");
            field.addAttribute("var", "workgroup#online");
            field.addAttribute("label", "Status");
            field.addElement("value").setText(workgroup.getStatus().name());
        } catch (UserNotFoundException e) {
            // If we didn't find a workgroup then answer a not found error
            reply.setChildElement(packet.getChildElement().createCopy());
            reply.setError(PacketError.Condition.item_not_found);
        }
    }
    return reply;
}

From source file:org.jivesoftware.xmpp.workgroup.disco.IQDiscoItemsHandler.java

License:Open Source License

public IQ handleIQ(IQ packet) {
    if (packet.getType() == IQ.Type.result) {
        List<Element> items = packet.getChildElement().elements("item");
        // Send a disco#info to each discovered item
        for (Element item : items) {
            String jid = item.attributeValue("jid");

            IQ disco = new IQ(IQ.Type.get);
            disco.setTo(jid);/*from  w w  w .ja  v  a  2 s  .  com*/
            disco.setFrom(packet.getTo());
            disco.setChildElement("query", "http://jabber.org/protocol/disco#info");
            workgroupManager.send(disco);
        }
        return null;
    }

    // Create a copy of the sent pack that will be used as the reply
    // we only need to add the requested info to the reply if any, otherwise add
    // a not found error
    IQ reply = IQ.createResultIQ(packet);

    if (IQ.Type.set == packet.getType()) {
        reply.setChildElement(packet.getChildElement().createCopy());
        reply.setError(PacketError.Condition.bad_request);
        return reply;
    }

    // Check if the disco#items was sent to the workgroup service itself
    if (workgroupManager.getAddress().equals(packet.getTo())) {
        Element iq = packet.getChildElement();
        String node = iq.attributeValue("node");
        reply.setChildElement(iq.createCopy());
        Element queryElement = reply.getChildElement();
        if (node == null) {
            // Add the hosted workgroups to the reply
            for (Workgroup workgroup : workgroupManager.getWorkgroups()) {
                Element item = queryElement.addElement("item");
                item.addAttribute("jid", workgroup.getJID().toString());
                item.addAttribute("name", workgroup.getJID().getNode());
            }
        } else if ("http://jabber.org/protocol/commands".equals(node)) {
            for (AdHocCommand command : commandManager.getCommands()) {
                // Only include commands that the sender can invoke (i.e. has enough permissions)
                if (command.hasPermission(packet.getFrom())) {
                    Element item = queryElement.addElement("item");
                    item.addAttribute("jid", workgroupManager.getAddress().toString());
                    item.addAttribute("node", command.getCode());
                    item.addAttribute("name", command.getLabel());
                }
            }
        } else {
            // Unknown node. Service not available
            reply.setError(PacketError.Condition.service_unavailable);
        }
    } else {
        // Answer an error if the user is trying to discover items of a workgroup
        reply.setChildElement(packet.getChildElement().createCopy());
        reply.setError(PacketError.Condition.not_acceptable);
    }
    return reply;
}

From source file:org.jivesoftware.xmpp.workgroup.search.IQChatSearchHandler.java

License:Open Source License

public void handleIQ(IQ packet) {
    try {/*from w w  w. j  av a  2 s. c o m*/
        // Check that the sender of this IQ is an agent
        workgroupManager.getAgentManager().getAgent(packet.getFrom());

        Element iq = packet.getChildElement();

        IQ reply = IQ.createResultIQ(packet);

        if (iq.elements().isEmpty()) {
            reply.setChildElement(iq.createCopy());
            // Send the search form to the agent
            reply.addExtension(searchForm.createCopy());
            workgroupManager.send(reply);
        } else {
            // Send the result of the search to the agent
            Date startDate = null;
            Date endDate = null;
            Collection<Workgroup> workgroups = WorkgroupManager.getInstance().getWorkgroups();
            JID agentJID = null;
            String queryString = null;

            // Get the search parameters from the completed form
            DataForm submitedForm = (DataForm) packet.getExtension(DataForm.ELEMENT_NAME, DataForm.NAMESPACE);
            for (FormField field : submitedForm.getFields()) {
                if ("date/start".equals(field.getVariable())) {
                    try {
                        startDate = DataForm.parseDate(field.getValues().get(0));
                    } catch (ParseException e) {
                        Log.debug("Invalid startDate " + field.getValues().get(0), e);
                    }
                } else if ("date/end".equals(field.getVariable())) {
                    try {
                        endDate = DataForm.parseDate(field.getValues().get(0));
                    } catch (ParseException e) {
                        Log.debug("Invalid endDate " + field.getValues().get(0), e);
                    }
                } else if ("workgroups".equals(field.getVariable())) {
                    if (!field.getValues().isEmpty()) {
                        workgroups = new ArrayList<Workgroup>();
                        for (String value : field.getValues()) {
                            try {
                                workgroups.add(WorkgroupManager.getInstance().getWorkgroup(new JID(value)));
                            } catch (UserNotFoundException e) {
                                Log.debug("Invalid workgroup JID " + value, e);
                            }
                        }
                    } else {
                        // Search in all the workgroups since no one was specified
                        workgroups = WorkgroupManager.getInstance().getWorkgroups();
                    }
                } else if ("agent".equals(field.getVariable())) {
                    agentJID = new JID(field.getValues().get(0));
                } else if ("queryString".equals(field.getVariable())) {
                    queryString = field.getValues().get(0);
                }
            }

            // Build the response
            DataForm searchResults = resultForm.createCopy();
            // Perform the search
            for (Workgroup workgroup : workgroups) {
                ChatSearch search = new ChatSearch(workgroup, startDate, endDate, agentJID, queryString);
                for (QueryResult result : search.getResults()) {
                    Map<String, Object> fields = new LinkedHashMap<String, Object>();
                    fields.put("workgroup", result.getWorkgroup().getJID().toBareJID());
                    fields.put("sessionID", result.getSessionID());
                    fields.put("startDate", result.getStartDate());
                    fields.put("agentJIDs", result.getAgentJIDs());
                    fields.put("relevance", result.getRelevance());

                    // Add Metadata
                    Map<String, String> metadata = getMetadataMap(result.getSessionID());
                    if (metadata.containsKey("question")) {
                        fields.put("question", metadata.get("question"));
                    }

                    if (metadata.containsKey("email")) {
                        fields.put("email", metadata.get("email"));
                    }

                    if (metadata.containsKey("username")) {
                        fields.put("username", metadata.get("username"));
                    }

                    searchResults.addItemFields(fields);
                }
            }
            reply.setChildElement(iq.getName(), iq.getNamespaceURI());
            reply.addExtension(searchResults);
            workgroupManager.send(reply);
        }
    } catch (AgentNotFoundException e) {
        IQ reply = IQ.createResultIQ(packet);
        reply.setChildElement(packet.getChildElement().createCopy());
        reply.setError(new PacketError(PacketError.Condition.not_authorized));
        workgroupManager.send(reply);
    }
}

From source file:org.jivesoftware.xmpp.workgroup.WorkgroupStats.java

License:Open Source License

public void getChatTranscript(IQ iq, String sessionID) {
    final IQ reply = IQ.createResultIQ(iq);

    String transcriptXML = null;/*from   w  w w .ja  v  a2  s  . c o  m*/
    try {
        Element transcript = reply.setChildElement("transcript", "http://jivesoftware.com/protocol/workgroup");
        transcript.addAttribute("sessionID", sessionID);
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(GET_TRANSCRIPT);
            pstmt.setString(1, sessionID);
            rs = pstmt.executeQuery();
            if (rs.next()) {
                transcriptXML = DbConnectionManager.getLargeTextField(rs, 1);
            }
        } catch (SQLException sqle) {
            Log.error(sqle.getMessage(), sqle);
        } finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        if (transcriptXML != null) {
            Document element = DocumentHelper.parseText(transcriptXML);
            // Add the Messages and Presences contained in the retrieved transcript element
            for (Iterator<Element> it = element.getRootElement().elementIterator(); it.hasNext();) {
                Element packet = it.next();
                transcript.add(packet.createCopy());
            }
        }
        workgroup.send(reply);
    } catch (Exception ex) {
        Log.error("There was an error retrieving the following transcript. SessionID = " + sessionID
                + " Transcript=" + transcriptXML, ex);

        reply.setChildElement(iq.getChildElement().createCopy());
        reply.setError(new PacketError(PacketError.Condition.item_not_found));
        workgroup.send(reply);
    }
}

From source file:org.nuxeo.automation.scripting.blockly.converter.Chains2Blockly.java

License:Open Source License

protected void assembleChains(Map<String, Element> convertedChains, List<String> nestedChains) {

    // / XXX handle recursion !

    for (String name : convertedChains.keySet()) {
        Element chain = convertedChains.get(name);
        for (Element placeHolder : findPlaceHolders(chain)) {
            String target = placeHolder.attributeValue("target");
            Boolean allowPipe = Boolean.parseBoolean(placeHolder.attributeValue("allowPipe"));
            Boolean loop = Boolean.parseBoolean(placeHolder.attributeValue("loop"));
            Element targetChain = (Element) convertedChains.get(target).elements().get(0);
            if (targetChain != null) {
                nestedChains.add(target);
                Element parent = placeHolder.getParent();
                Element previousBlock = BlockHelper.getPreviousBlock(placeHolder);

                placeHolder.detach();//  w w w  . ja v a2 s  .  c om

                if (BlockHelper.isSwallowBlock(targetChain)) {
                    targetChain = BlockHelper.getInputElementValue(targetChain);
                }

                targetChain = targetChain.createCopy();

                Element input = BlockHelper.getInputElementRecursive(targetChain);
                if (allowPipe && input != null) {
                    // try to pipe chain
                    if (input.elements().size() == 0) {
                        Element inputValue = parent.getParent();
                        if (BlockHelper.isSwallowBlock(inputValue)) {
                            inputValue = BlockHelper.getInputElementValue(inputValue);
                        }

                        Element newParent = previousBlock;
                        inputValue.detach();

                        if (loop) {
                            // wrap in a for each block !
                            Element loopBlock = XMLSerializer.createLoopBlock(inputValue, targetChain);
                            if (BlockHelper.isSwallowBlock(newParent)) {
                                Element realNewParent = BlockHelper.getPreviousBlock(newParent);
                                if (realNewParent == null) {
                                    realNewParent = newParent.getParent();
                                }
                                newParent.detach();
                                BlockHelper.getNext(realNewParent).add(loopBlock);

                            } else {
                                BlockHelper.getNext(newParent).add(loopBlock);
                            }
                        } else {
                            input.add(inputValue);
                            newParent.add(targetChain);
                        }

                    } else {
                        System.out.println(targetChain.asXML());
                        throw new UnsupportedOperationException("Input should be null");
                    }
                } else {
                    parent.add(targetChain);
                }

            }
        }
    }
}

From source file:org.olat.ims.qti.container.ItemContext.java

License:Apache License

/**
 * Method shuffle. shuffle clones the current item (since the whole qti tree is readonly) and shuffles it
 * //from w w  w .  ja  v a 2 s.co  m
 * @param item
 * @return Element
 */
private Element shuffle(final Element item) {
    // get the render_choice
    final XPath choice = DocumentHelper.createXPath(".//render_choice[@shuffle=\"Yes\"]");
    final Element tel_rendchoice = (Element) choice.selectSingleNode(item);
    // if shuffle is disable, just return the item
    if (tel_rendchoice == null) {
        return item;
    }
    // else: we have to shuffle
    // assume: all response_label have same parent: either render_choice or a
    // flow_label
    final Element shuffleItem = item.createCopy();
    // clone the whole item
    final Element el_rendchoice = (Element) choice.selectSingleNode(shuffleItem);
    // <!ELEMENT render_choice ((material | material_ref | response_label |
    // flow_label)* ,response_na?)>
    // <!ATTLIST response_label rshuffle (Yes | No ) 'Yes' .....
    final List el_labels = el_rendchoice.selectNodes(".//response_label[@rshuffle=\"Yes\"]");
    final int shusize = el_labels.size();

    // set up a list of children with their parents and the position of the
    // child (in case several children have the same parent
    final List respList = new ArrayList(shusize);
    final List parentList = new ArrayList(shusize);
    final int[] posList = new int[shusize];
    int j = 0;

    for (final Iterator responses = el_labels.iterator(); responses.hasNext();) {
        final Element response = (Element) responses.next();
        final Element parent = response.getParent();
        final int pos = parent.indexOf(response);
        posList[j++] = pos;
        respList.add(response.clone()); // need to use clones so they are not
        // attached anymore
        parentList.add(parent);
    }
    Collections.shuffle(respList);
    // put the children back to the parents
    for (int i = 0; i < parentList.size(); i++) {
        final Element parent = (Element) parentList.get(i);
        final int pos = posList[i];
        final Element child = (Element) respList.get(i);
        parent.elements().set(pos, child);
    }
    return shuffleItem;
}

From source file:org.olat.ims.qti.render.ResultsBuilder.java

License:Apache License

/**
 * Method getResDoc./*from w w  w  . ja v a 2  s. com*/
 * 
 * @param ai The assessment instance
 * @param locale The users locale
 * @param identity
 * @return Document The XML document
 */
public Document getResDoc(final AssessmentInstance ai, final Locale locale, final Identity identity) {
    final AssessmentContext ac = ai.getAssessmentContext();
    final DocumentFactory df = DocumentFactory.getInstance();
    final Document res_doc = df.createDocument();
    final Element root = df.createElement("qti_result_report");
    res_doc.setRootElement(root);
    final Element result = root.addElement("result");
    final Element extension_result = result.addElement("extension_result");

    // add items (not qti standard, but nice to display original questions ->
    // put it into extensions)
    // extension_result.
    final int sectioncnt = ac.getSectionContextCount();
    for (int i = 0; i < sectioncnt; i++) {
        final SectionContext sc = ac.getSectionContext(i);
        final int itemcnt = sc.getItemContextCount();
        for (int j = 0; j < itemcnt; j++) {
            final ItemContext it = sc.getItemContext(j);
            final Element el_item = it.getEl_item();
            extension_result.add(el_item);
        }
    }

    // add ims cp id for any media references
    addStaticsPath(extension_result, ai);

    // add assessment_result

    // Add User information
    final Element context = result.addElement("context");
    final User user = identity.getUser();
    final String name = user.getProperty(UserConstants.LASTNAME, locale) + " "
            + user.getProperty(UserConstants.FIRSTNAME, locale) + " (" + identity.getName() + ")";
    String instId = user.getProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, locale);
    final String instName = user.getProperty(UserConstants.INSTITUTIONALNAME, locale);

    if (instId == null) {
        instId = "N/A";
    }
    context.addElement("name").addText(name);

    String institution;
    if (instName == null) {
        institution = "N/A";
    } else {
        institution = instName;
    }
    if (institution == null) {
        institution = "N/A";
    }

    // Add institutional identifier (e.g. Matrikelnummer)
    final Element generic_identifier = context.addElement("generic_identifier");
    generic_identifier.addElement("type_label").addText(institution);
    generic_identifier.addElement("identifier_string").addText(instId);

    // Add start and stop date formatted as datetime
    final Element beginDate = context.addElement("date");
    beginDate.addElement("type_label").addText("Start");
    beginDate.addElement("datetime").addText(Formatter.formatDatetime(new Date(ac.getTimeOfStart())));
    final Element stopDate = context.addElement("date");
    stopDate.addElement("type_label").addText("Stop");
    stopDate.addElement("datetime").addText(Formatter.formatDatetime(new Date(ac.getTimeOfStop())));

    final Element ares = result.addElement("assessment_result");
    ares.addAttribute("ident_ref", ac.getIdent());
    if (ac.getTitle() != null) {
        ares.addAttribute("asi_title", ac.getTitle());
    }

    // process assessment score
    final Element a_score = ares.addElement("outcomes").addElement("score");
    a_score.addAttribute("varname", "SCORE");
    String strVal = StringHelper.formatFloat(ac.getScore(), 2);
    a_score.addElement("score_value").addText(strVal);

    strVal = ac.getMaxScore() == -1.0f ? "N/A" : StringHelper.formatFloat(ac.getMaxScore(), 2);
    a_score.addElement("score_max").addText(strVal);

    strVal = ac.getCutvalue() == -1.0f ? "N/A" : StringHelper.formatFloat(ac.getCutvalue(), 2);
    a_score.addElement("score_cut").addText(strVal);

    addElementText(ares, "duration", QTIHelper.getISODuration(ac.getDuration()));
    addElementText(ares, "num_sections", "" + ac.getSectionContextCount());
    addElementText(ares, "num_sections_presented", "0");
    addElementText(ares, "num_items", "" + ac.getItemContextCount());
    addElementText(ares, "num_items_presented", "" + ac.getItemsPresentedCount());
    addElementText(ares, "num_items_attempted", "" + ac.getItemsAttemptedCount());

    // add section_result
    final int secnt = ac.getSectionContextCount();
    for (int i = 0; i < secnt; i++) {
        final SectionContext secc = ac.getSectionContext(i);
        final Element secres = ares.addElement("section_result");
        secres.addAttribute("ident_ref", secc.getIdent());
        if (secc.getTitle() != null) {
            secres.addAttribute("asi_title", secc.getTitle());
        }
        addElementText(secres, "duration", QTIHelper.getISODuration(secc.getDuration()));
        addElementText(secres, "num_items", "" + secc.getItemContextCount());
        addElementText(secres, "num_items_presented", "" + secc.getItemsPresentedCount());
        addElementText(secres, "num_items_attempted", "" + secc.getItemsAttemptedCount());

        // process section score
        final Element sec_score = secres.addElement("outcomes").addElement("score");
        sec_score.addAttribute("varname", "SCORE");
        strVal = secc.getScore() == -1.0f ? "N/A" : "" + StringHelper.formatFloat(secc.getScore(), 2);
        sec_score.addElement("score_value").addText(strVal);
        strVal = secc.getMaxScore() == -1.0f ? "N/A" : "" + StringHelper.formatFloat(secc.getMaxScore(), 2);
        sec_score.addElement("score_max").addText(strVal);
        strVal = secc.getCutValue() == -1 ? "N/A" : "" + secc.getCutValue();
        sec_score.addElement("score_cut").addText(strVal);

        // iterate over all items in this section context
        final List itemsc = secc.getSectionItemContexts();
        for (final Iterator it_it = itemsc.iterator(); it_it.hasNext();) {
            final ItemContext itemc = (ItemContext) it_it.next();
            final Element itres = secres.addElement("item_result");
            itres.addAttribute("ident_ref", itemc.getIdent());
            itres.addAttribute("asi_title", itemc.getEl_item().attributeValue("title"));
            final Element it_duration = itres.addElement("duration");
            it_duration.addText(QTIHelper.getISODuration(itemc.getTimeSpent()));

            // process item score
            final DecimalVariable scoreVar = (DecimalVariable) (itemc.getVariables().getSCOREVariable());
            final Element it_score = itres.addElement("outcomes").addElement("score");
            it_score.addAttribute("varname", "SCORE");
            it_score.addElement("score_value")
                    .addText(StringHelper.formatFloat(scoreVar.getTruncatedValue(), 2));
            strVal = scoreVar.hasMinValue() ? "" + scoreVar.getMinValue() : "0.0";
            it_score.addElement("score_min").addText(strVal);
            strVal = scoreVar.hasMaxValue() ? "" + scoreVar.getMaxValue() : "N/A";
            it_score.addElement("score_max").addText(strVal);
            strVal = scoreVar.hasCutValue() ? "" + scoreVar.getCutValue() : "N/A";
            it_score.addElement("score_cut").addText(strVal);

            final Element el_item = itemc.getEl_item();
            final Map res_responsehash = new HashMap(3);

            // iterate over all responses of this item
            final List resps = el_item.selectNodes(
                    ".//response_lid|.//response_xy|.//response_str|.//response_num|.//response_grp");
            for (final Iterator it_resp = resps.iterator(); it_resp.hasNext();) {
                final Element resp = (Element) it_resp.next();
                final String ident = resp.attributeValue("ident");
                final String rcardinality = resp.attributeValue("rcardinality");
                final String rtiming = resp.attributeValue("rtiming");

                // add new response
                final Element res_response = itres.addElement("response");
                res_response.addAttribute("ident_ref", ident);
                res_responsehash.put(ident, res_response); // enable lookup of
                // @identref of <response>
                // (needed with <varequal>
                // elements

                // add new response_form
                // <response_lid ident="MR01" rcardinality="Multiple" rtiming="No">
                final Element res_responseform = res_response.addElement("response_form");
                res_responseform.addAttribute("cardinality", rcardinality);
                res_responseform.addAttribute("timing", rtiming);
                final String respName = resp.getName();
                final String type = respName.substring(respName.indexOf("_") + 1);
                res_responseform.addAttribute("response_type", type);

                // add user answer
                final ItemInput itemInp = itemc.getItemInput();
                final Translator trans = Util.createPackageTranslator(QTIModule.class, locale);
                if (itemInp == null) { // user did not answer this question at all
                    res_response.addElement("response_value").addText(trans.translate("ResBuilder.NoAnswer"));
                } else {
                    final List userAnswer = itemInp.getAsList(ident);
                    if (userAnswer == null) { // user did not answer this question at
                        // all
                        res_response.addElement("response_value")
                                .addText(trans.translate("ResBuilder.NoAnswer"));
                    } else { // the user chose at least one option of an answer (did not
                             // simply click send)
                        for (final Iterator it_ans = userAnswer.iterator(); it_ans.hasNext();) {
                            res_response.addElement("response_value").addText((String) it_ans.next());
                        }
                    }
                }

            }

            /*
             * The simple element correct_response can only list correct elements, that is, no "or" or "and" elements may be in the conditionvar. Pragmatic solution:
             * if condition has ors or ands, then put whole conditionvar into <extension_response> (proprietary), and for easier cases (just "varequal" "not"
             * elements) use correct_response.
             */

            final Map corr_answers = new HashMap(); // keys: respIdents, values: HashSet
            // of correct answers for this
            // respIdent
            final List respconds = el_item.selectNodes(".//respcondition");
            for (final Iterator it_respc = respconds.iterator(); it_respc.hasNext();) {
                final Element el_respc = (Element) it_respc.next();

                // check for add/set in setvar elements (check for single instance
                // only -> spec allows for multiple instances)
                final Element el_setvar = (Element) el_respc.selectSingleNode(".//setvar");
                if (el_setvar == null) {
                    continue;
                }
                if (el_setvar.attributeValue("action").equals("Add")
                        || el_setvar.attributeValue("action").equals("Set")) {
                    // This resrocessing gives points -> assume correct answer
                    float numPoints = 0;
                    try {
                        numPoints = Float.parseFloat(el_setvar.getTextTrim());
                    } catch (final NumberFormatException nfe) {
                        //
                    }
                    if (numPoints <= 0) {
                        continue;
                    }
                    Element conditionvar = (Element) el_respc.selectSingleNode(".//conditionvar");
                    // there is an evaluation defined (a "resprocessing" element exists)
                    // if (xpath(count(.//varequal) + count(.//not) = count(.//*)) is
                    // true, then there are only "not" and "varequal" elements
                    final XPath xCanHandle = DocumentHelper
                            .createXPath("count(.//varequal) + count(.//not) = count(.//*)");
                    boolean canHandle = xCanHandle.matches(conditionvar);
                    if (!canHandle) { // maybe we have <condvar> <and> <...>, try again
                        final Element el_and = (Element) conditionvar.selectSingleNode("and");
                        if (el_and != null) {
                            canHandle = xCanHandle.matches(el_and);
                            if (canHandle) { // simultate the el_and to be the conditionvar
                                conditionvar = el_and;
                            }
                        } else { // and finally, maybe we have an <or> element ..
                            final Element el_or = (Element) conditionvar.selectSingleNode("or");
                            if (el_or != null) {
                                canHandle = xCanHandle.matches(el_or);
                                if (canHandle) { // simultate the el_and to be the conditionvar
                                    conditionvar = el_or;
                                }
                            }
                        }
                    }

                    if (!canHandle) {
                        // qti res 1.2.1 can't handle it
                        final Element condcopy = conditionvar.createCopy();
                        itres.addElement("extension_item_result").add(condcopy);
                    } else {
                        /*
                         * easy case: get all varequal directly under the conditionvar element and assume the "not" elements do not contain "not" elements again...
                         * <!ELEMENT response (qti_comment? , response_form? , num_attempts? , response_value* , extension_response?)> <!ELEMENT response_form
                         * (correct_response* , extension_responseform?)> <!ELEMENT correct_response (#PCDATA)>
                         */
                        final List vareqs = conditionvar.selectNodes("./varequal");
                        for (final Iterator it_vareq = vareqs.iterator(); it_vareq.hasNext();) {
                            /*
                             * get the identifier of the response, so that we can attach the <correct_response> to the right <response> element quote: ims qti asi xml
                             * binding :3.6.23.1 <varequal> Element: respident (required). The identifier of the corresponding <response_lid>, <response_xy>, etc.
                             * element (this was assigned using its ident attribute).
                             */
                            final Element vareq = (Element) it_vareq.next();
                            final String respIdent = vareq.attributeValue("respident");
                            Set respIdent_corr_answers = (Set) corr_answers.get(respIdent);
                            if (respIdent_corr_answers == null) {
                                respIdent_corr_answers = new HashSet(3);
                            }
                            respIdent_corr_answers.add(vareq.getText());
                            corr_answers.put(respIdent, respIdent_corr_answers);
                        } // for varequal
                    } // else varequal
                } // add/set setvar
            } // for resprocessing
            final Set resp_ids = corr_answers.keySet();
            for (final Iterator idents = resp_ids.iterator(); idents.hasNext();) {
                final String respIdent = (String) idents.next();
                final Set respIdent_corr_answers = (Set) corr_answers.get(respIdent);
                final Element res_response = (Element) res_responsehash.get(respIdent);
                final Element res_respform = res_response.element("response_form");
                for (final Iterator iter = respIdent_corr_answers.iterator(); iter.hasNext();) {
                    final String answer = (String) iter.next();
                    res_respform.addElement("correct_response").addText(answer);
                }
            }
        } // for response_xy
    }
    return res_doc;
}