/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
* <p/>
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.module.xforms.buendia;
import org.apache.commons.lang.StringUtils;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
import org.kxml2.kdom.Document;
import org.kxml2.kdom.Element;
import org.openmrs.Concept;
import org.openmrs.ConceptMap;
import org.openmrs.ConceptReferenceTerm;
import org.openmrs.ConceptSource;
import org.openmrs.api.ConceptService;
import org.openmrs.api.context.Context;
import org.openmrs.module.xforms.XformConstants;
import org.openmrs.module.xforms.XformsService;
import org.openmrs.module.xforms.util.XformsUtil;
import org.openmrs.util.OpenmrsUtil;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_CONSTRAINT;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_ID;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_LOCKED;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_MESSAGE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_MULTIPLE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_NODESET;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_OPENMRS_ATTRIBUTE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_OPENMRS_CONCEPT;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_OPENMRS_DATATYPE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_OPENMRS_TABLE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_REQUIRED;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_TYPE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_VISIBLE;
import static org.openmrs.module.xforms.XformBuilder.ATTRIBUTE_XSI_NILL;
import static org.openmrs.module.xforms.XformBuilder.DATA_TYPE_BOOLEAN;
import static org.openmrs.module.xforms.XformBuilder.DATA_TYPE_DATE;
import static org.openmrs.module.xforms.XformBuilder.DATA_TYPE_DATETIME;
import static org.openmrs.module.xforms.XformBuilder.DATA_TYPE_INT;
import static org.openmrs.module.xforms.XformBuilder.DATA_TYPE_TEXT;
import static org.openmrs.module.xforms.XformBuilder.NAMESPACE_XFORMS;
import static org.openmrs.module.xforms.XformBuilder.NODE_BIND;
import static org.openmrs.module.xforms.XformBuilder.NODE_ENCOUNTER_ENCOUNTER_DATETIME;
import static org.openmrs.module.xforms.XformBuilder.NODE_ENCOUNTER_LOCATION_ID;
import static org.openmrs.module.xforms.XformBuilder.NODE_ENCOUNTER_PROVIDER_ID;
import static org.openmrs.module.xforms.XformBuilder.NODE_INSTANCE;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_BIRTH_DATE;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_BIRTH_DATE_ESTIMATED;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_FAMILY_NAME;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_GENDER;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_GIVEN_NAME;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_MIDDLE_NAME;
import static org.openmrs.module.xforms.XformBuilder.NODE_PATIENT_PATIENT_ID;
import static org.openmrs.module.xforms.XformBuilder.NODE_PROBLEM_LIST;
import static org.openmrs.module.xforms.XformBuilder.NODE_SEPARATOR;
import static org.openmrs.module.xforms.XformBuilder.NODE_VALUE;
import static org.openmrs.module.xforms.XformBuilder.NODE_XFORMS_VALUE;
import static org.openmrs.module.xforms.XformBuilder.VALUE_TRUE;
import static org.openmrs.module.xforms.XformBuilder.XPATH_VALUE_FALSE;
import static org.openmrs.module.xforms.XformBuilder.XPATH_VALUE_TRUE;
//TODO This class is too big. May need breaking into smaller ones.
/**
* This is a clone of the Xforms module XformBuilder class, allowing us to tinker with the view
* creation code separately from the module itself. Methods we don't need have been removed,
* and the constants are imported from XformBuilder.
*/
public final class BuendiaXformBuilder {
private static final String ATTRIBUTE_PRELOAD = "jr:preload";
private static final String ATTRIBUTE_PRELOAD_PARAMS = "jr:preloadParams";
private static final String PRELOAD_PATIENT = "patient";
/**
* Methods replaces the conceptId with a concept source name and source code.
* @param element the element with the openmrs_concept attribute
* @param conceptValueString the value of the openmrs_concept attribute
*/
public static void addConceptMapAttributes(Element element, String conceptValueString) {
String[] tokens = StringUtils.split(conceptValueString, "^");
ConceptService cs = Context.getConceptService();
try {
Concept concept = cs.getConcept(Integer.valueOf(tokens[0].trim()));
String prefSourceName = Context.getAdministrationService().getGlobalProperty(
XformConstants.GLOBAL_PROP_KEY_PREFERRED_CONCEPT_SOURCE);
if (StringUtils.isNotBlank(prefSourceName)) {
ConceptSource preferredSource = cs.getConceptSourceByName(prefSourceName);
if (concept.getConceptMappings().size() > 0) {
if (preferredSource != null) {
for (ConceptMap map : concept.getConceptMappings()) {
ConceptReferenceTerm term = map.getConceptReferenceTerm();
if (OpenmrsUtil.nullSafeEquals(
preferredSource, term.getConceptSource())) {
element.setAttribute(
null, ATTRIBUTE_OPENMRS_CONCEPT,
term.getConceptSource().getName() + ":" + term.getCode());
return;
}
}
}
}
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid concept value: " + conceptValueString, e);
}
}
/**
* Parses an openmrs template and builds the bindings in the model plus UI controls for openmrs
* table field questions.
* @param modelElement - the model element to add bindings to.
* @param formNode the form node.
* @param bindings - a hash table to populate with the built bindings.
*/
public static void parseTemplate(Element modelElement, Element formNode, Element formChild,
Map<String, Element> bindings,
Map<String, String> problemList,
Map<String, String> problemListItems, int level) {
level++;
int numOfEntries = formChild.getChildCount();
for (int i = 0; i < numOfEntries; i++) {
if (formChild.isText(i)) continue; // Ignore all text.
Element child = formChild.getElement(i);
//These two attributes are a must for all nodes to be filled with values.
//eg openmrs_concept="1740^ARV REGIMEN^99DCT" openmrs_datatype="CWE"
if (child.getAttributeValue(null, ATTRIBUTE_OPENMRS_DATATYPE) == null
&& child.getAttributeValue(null, ATTRIBUTE_OPENMRS_CONCEPT) != null) {
continue; //These could be like options for multiple select, which take true or
}
// false value.
String name = child.getName();
/* TODO(jonskeet): If we care, move this into buildUiNode.
if (name.equals("patient_relationship")) {
RelationshipBuilder.build(modelElement, bodyNode, child);
continue;
}
*/
//If the node has an openmrs_concept attribute but is not a top-level node,
//Or has the openmrs_attribute and openmrs_table attributes.
if ((child.getAttributeValue(null, ATTRIBUTE_OPENMRS_CONCEPT) != null && level > 1
/*!child.getName().equals(NODE_OBS)*/)
|| (child.getAttributeValue(null, ATTRIBUTE_OPENMRS_ATTRIBUTE) != null && child
.getAttributeValue(
null,
ATTRIBUTE_OPENMRS_TABLE) != null)) {
if (!name.equalsIgnoreCase(NODE_PROBLEM_LIST)) {
Element bindNode = createBindNode(
modelElement, child, bindings, problemList, problemListItems);
if (isMultSelectNode(child)) {
addMultipleSelectXformValueNode(child);
}
if (isTableFieldNode(child)) {
setTableFieldDataType(name, bindNode);
setTableFieldBindingAttributes(name, bindNode);
setTableFieldDefaultValue(name, formNode);
if ("identifier".equalsIgnoreCase(
child.getAttributeValue(null, ATTRIBUTE_OPENMRS_ATTRIBUTE))
&& "patient_identifier".equalsIgnoreCase(
child.getAttributeValue(null, ATTRIBUTE_OPENMRS_TABLE))) {
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(
null, ATTRIBUTE_PRELOAD_PARAMS, "patientIdentifier");
}
}
}
}
//if(child.getAttributeValue(null, ATTRIBUTE_OPENMRS_ATTRIBUTE) != null && child
// .getAttributeValue(null, ATTRIBUTE_OPENMRS_TABLE) != null){
//Build UI controls for the openmrs fixed table fields. The rest of the controls are
// built from
/* TODO(jonskeet): Move this into buildUiNodes
if (isTableFieldNode(child)) {
Element controlNode = buildTableFieldUIControlNode(child, bodyNode);
if (name.equalsIgnoreCase(NODE_ENCOUNTER_LOCATION_ID) && CONTROL_SELECT1.equals
(controlNode.getName()))
populateLocations(controlNode);
else if (name.equalsIgnoreCase(NODE_ENCOUNTER_PROVIDER_ID)) {
populateProviders(controlNode, formNode, modelElement, bodyNode);
//if this is 1.9, we need to add the provider_id_type attribute and set its
value, this
//will be used by xml to hl7 xslt to determine if it should include the
assigning
//authority so that ORUR01 handler in core considers the id to be a providerId
if (XformsUtil.isOnePointNineAndAbove()) {
((Element) child).setAttribute(null, XformBuilder
.ATTRIBUTE_PROVIDER_ID_TYPE,
XformBuilder.VALUE_PROVIDER_ID_TYPE_PROV_ID);
}
} else if (name.equalsIgnoreCase(NODE_ENCOUNTER_ENCOUNTER_DATETIME))
setNodeValue(child, "'today()'"); //Set encounter date defaulting to today
}
*/
parseTemplate(
modelElement, formNode, child, bindings, problemList, problemListItems, level);
}
}
/**
* Converts an xml document to a string.
* @param doc - the document.
* @return the xml string in in the document.
*/
public static String fromDoc2String(Document doc) throws IOException {
KXmlSerializer serializer = new KXmlSerializer();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.setOutput(bos, XformConstants.DEFAULT_CHARACTER_ENCODING);
doc.write(serializer);
serializer.flush();
return new String(bos.toByteArray(), XformConstants.DEFAULT_CHARACTER_ENCODING);
}
/** Gets a document from a stream reader. */
public static Document getDocument(Reader reader) throws XmlPullParserException, IOException {
Document doc = new Document();
KXmlParser parser = new KXmlParser();
parser.setInput(reader);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
doc.parse(parser);
return doc;
}
/**
* Sets the value of a child node in a parent node.
* @param parentNode - the node to add a child to.
* @param name - the name of the node whose value to set.
* @param value - the value to set.
* @return - true if the node with the name was found, else false.
*/
private static boolean setNodeValue(Element parentNode, String name, String value) {
Element node = getElement(parentNode, name);
if (node == null) return false;
setNodeValue(node, value);
return true;
}
/**
* Sets the text value of a node.
* @param node - the node whose value to set.
* @param value - the value to set.
*/
private static void setNodeValue(Element node, String value) {
if (value == null) {
value = "";
}
for (int i = 0; i < node.getChildCount(); i++) {
if (node.isText(i)) {
node.removeChild(i);
node.addChild(Element.TEXT, value);
return;
}
}
node.addChild(Element.TEXT, value);
}
/**
* Gets a child element of a parent node with a given name.
* @param parent - the parent element
* @param name - the name of the child.
* @return - the child element.
*/
private static Element getElement(Element parent, String name) {
for (int i = 0; i < parent.getChildCount(); i++) {
if (parent.getType(i) != Element.ELEMENT) continue;
Element child = (Element) parent.getChild(i);
if (child.getName().equalsIgnoreCase(name)) return child;
child = getElement(child, name);
if (child != null) return child;
}
return null;
}
/**
* Creates a model binding node.
* @param modelElement - the model node to add the binding to.
* @param node - the node whose binding to create.
* @param bindings - a hashtable of node bindings keyed by their names.
* @return - the created binding node.
*/
private static Element createBindNode(
Element modelElement, Element node, Map<String, Element> bindings,
Map<String, String> problemList, Map<String, String> problemListItems) {
Element bindNode = modelElement.createElement(NAMESPACE_XFORMS, null);
bindNode.setName(NODE_BIND);
String parentName = ((Element) node.getParent()).getName();
String binding = node.getName();
if (bindings.containsKey(binding)) {
binding = parentName + "_" + binding;
problemListItems.put(binding, parentName);
} else {
if (!(parentName.equalsIgnoreCase("obs")
|| parentName.equalsIgnoreCase("patient")
|| parentName.equalsIgnoreCase("encounter")
|| parentName.equalsIgnoreCase("problem_list")
|| parentName.equalsIgnoreCase("orders"))) {
//binding = parentName + "_" + binding;
//TODO Need to investigate why the above commented out code brings the no data
// node found error in the form designer
}
}
bindNode.setAttribute(null, ATTRIBUTE_ID, binding);
String name = node.getName();
String nodeset = getNodesetAttValue(node);
//For problem list element bindings, we do not add the value part.
if (parentName.equalsIgnoreCase(NODE_PROBLEM_LIST)) {
problemList.put(name, name);
nodeset = getNodePath(node);
}
//Check if this is an item of a problem list.
if (problemList.containsKey(parentName)) {
if (problemListItems.containsValue(name)) {
throw new IllegalStateException(
"Original code would use repeatSharedKids here, despite it being null");
}
problemListItems.put(name, parentName);
}
bindNode.setAttribute(null, ATTRIBUTE_NODESET, nodeset);
if (!((Element) ((Element) node.getParent()).getParent())
.getName().equals(NODE_PROBLEM_LIST)) {
modelElement.addChild(Element.ELEMENT, bindNode);
}
//store the binding node with the key being its id attribute.
bindings.put(binding, bindNode);
return bindNode;
}
/**
* Adds a node to hold the xforms value for a multiple select node. The value is a space
* delimited list of selected answers, which will later on be used to fill the true or false
* values as expected by openmrs multiple select questions.
* @param node - the multiple select node to add the value node to.
*/
private static void addMultipleSelectXformValueNode(Element node) {
//Element xformsValueNode = modelElement.createElement(null, null);
Element xformsValueNode = node.createElement(null, null);
xformsValueNode.setName(NODE_XFORMS_VALUE);
xformsValueNode.setAttribute(null, ATTRIBUTE_XSI_NILL, VALUE_TRUE);
node.addChild(Element.ELEMENT, xformsValueNode);
}
/**
* Set data types for the openmrs fixed table fields.
* @param name - the name of the question node.
* @param bindNode - the binding node whose type attribute we are to set.
*/
private static void setTableFieldDataType(String name, Element bindNode) {
if (name.equalsIgnoreCase(NODE_ENCOUNTER_ENCOUNTER_DATETIME)) {
bindNode.setAttribute(
null, ATTRIBUTE_TYPE,
XformsUtil.encounterDateIncludesTime() ? DATA_TYPE_DATETIME : DATA_TYPE_DATE);
bindNode.setAttribute(null, ATTRIBUTE_CONSTRAINT, ". <= today()");
bindNode.setAttribute(
null,
(XformsUtil.isJavaRosaSaveFormat() ? "jr:constraintMsg" : ATTRIBUTE_MESSAGE),
"Encounter date cannot be after today");
} else if (name.equalsIgnoreCase(NODE_ENCOUNTER_LOCATION_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_INT);
} else if (name.equalsIgnoreCase(NODE_ENCOUNTER_PROVIDER_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_INT);
} else if (name.equalsIgnoreCase(NODE_PATIENT_PATIENT_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_INT);
} else {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_TEXT);
}
}
/**
* Set required and readonly attributes for the openmrs fixed table fields.
* @param name - the name of the question node.
* @param bindNode - the binding node whose required and readonly attributes we are to set.
*/
private static void setTableFieldBindingAttributes(String name, Element bindNode) {
if (name.equalsIgnoreCase(NODE_ENCOUNTER_ENCOUNTER_DATETIME)) {
bindNode.setAttribute(null, ATTRIBUTE_REQUIRED, XPATH_VALUE_TRUE);
} else if (name.equalsIgnoreCase(NODE_ENCOUNTER_LOCATION_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_REQUIRED, XPATH_VALUE_TRUE);
} else if (name.equalsIgnoreCase(NODE_ENCOUNTER_PROVIDER_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_REQUIRED, XPATH_VALUE_TRUE);
} else if (name.equalsIgnoreCase(NODE_PATIENT_PATIENT_ID)) {
bindNode.setAttribute(null, ATTRIBUTE_REQUIRED, XPATH_VALUE_TRUE);
//bindNode.setAttribute(null, ATTRIBUTE_READONLY, XPATH_VALUE_TRUE);
//bindNode.setAttribute(null, ATTRIBUTE_LOCKED, XPATH_VALUE_TRUE);
bindNode.setAttribute(null, ATTRIBUTE_VISIBLE, XPATH_VALUE_FALSE);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "patientId");
} else {
//all table field are readonly on forms since they cant be populated in their tables
//form encounter forms. This population only happens when creating or editing patient.
bindNode.setAttribute(null, ATTRIBUTE_LOCKED, XPATH_VALUE_TRUE);
//The ATTRIBUTE_READONLY prevents firefox from displaying values in the disabled
//widgets. So this is why we are using locked which will still be readonly
//but values can be seen in the widgets.
}
/*else if(name.equalsIgnoreCase(NODE_PATIENT_FAMILY_NAME))
bindNode.setAttribute(null, ATTRIBUTE_READONLY, XPATH_VALUE_TRUE);
else if(name.equalsIgnoreCase(NODE_PATIENT_MIDDLE_NAME))
bindNode.setAttribute(null, ATTRIBUTE_READONLY, XPATH_VALUE_TRUE);
else if(name.equalsIgnoreCase(NODE_PATIENT_GIVEN_NAME))
bindNode.setAttribute(null, ATTRIBUTE_READONLY, XPATH_VALUE_TRUE);
else{
bindNode.setAttribute(null, ATTRIBUTE_READONLY, XPATH_VALUE_TRUE);
bindNode.setAttribute(null, ATTRIBUTE_LOCKED, XPATH_VALUE_TRUE);
}*/
//jr:preload="patient" jr:preloadParams="ID"
if (name.equalsIgnoreCase(NODE_PATIENT_BIRTH_DATE)) {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_DATE);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "birthDate");
} else if (name.equalsIgnoreCase(NODE_PATIENT_BIRTH_DATE_ESTIMATED)) {
bindNode.setAttribute(null, ATTRIBUTE_TYPE, DATA_TYPE_BOOLEAN);
}
//peloaders
if (name.equalsIgnoreCase(NODE_PATIENT_FAMILY_NAME)) {
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "familyName");
} else if (name.equalsIgnoreCase(NODE_PATIENT_MIDDLE_NAME)) {
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "middleName");
} else if (name.equalsIgnoreCase(NODE_PATIENT_GIVEN_NAME)) {
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "givenName");
} else if (name.equalsIgnoreCase(NODE_PATIENT_GENDER)) {
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD, PRELOAD_PATIENT);
bindNode.setAttribute(null, ATTRIBUTE_PRELOAD_PARAMS, "sex");
}
}
private static void setTableFieldDefaultValue(String name, Element formElement) {
Integer formId = Integer.valueOf(formElement.getAttributeValue(null, ATTRIBUTE_ID));
String val = getFieldDefaultValue(name, formId, true);
if (val != null) {
setNodeValue(formElement, name, val);
}
}
private static String getFieldDefaultValue(
String name, Integer formId, boolean forAllPatients) {
XformsService xformsService = Context.getService(XformsService.class);
String val = xformsService.getFieldDefaultValue(formId, name);
if (val == null) {
val = xformsService.getFieldDefaultValue(formId, name.replace('_', ' '));
if (val == null) return null;
}
if (!val.contains("$!{")) {
return val;
} else if (!forAllPatients) {
Integer id = getDefaultValueId(val);
if (id != null) return id.toString();
}
return null;
}
private static Integer getDefaultValueId(String val) {
int pos1 = val.indexOf('(');
if (pos1 == -1) return null;
int pos2 = val.indexOf(')');
if (pos2 == -1) return null;
if ((pos2 - pos1) < 2) return null;
String id = val.substring(pos1 + 1, pos2);
try {
return Integer.valueOf(id);
} catch (Exception e) {
}
return null;
}
/**
* Check whether a node is an openmrs table field node These are the ones with the attributes:
* openmrs_table and openmrs_attribute e.g. patient_unique_number
* openmrs_table="PATIENT_IDENTIFIER" openmrs_attribute="IDENTIFIER"
* @param node - the node to check.
* @return - true if it is, else false.
*/
private static boolean isTableFieldNode(Element node) {
return (node.getAttributeValue(null, ATTRIBUTE_OPENMRS_ATTRIBUTE) != null && node
.getAttributeValue(null, ATTRIBUTE_OPENMRS_TABLE) != null);
}
/**
* Checks whether a node is multiple select or not.
* @param child - the node to check.k
* @return - true if multiple select, else false.
*/
private static boolean isMultSelectNode(Element child) {
return (child.getAttributeValue(null, ATTRIBUTE_MULTIPLE) != null && child
.getAttributeValue(null, ATTRIBUTE_MULTIPLE).equals("1"));
}
/**
* Check if a given node as an openmrs value node.
* @param node - the node to check.
* @return - true if it has, else false.
*/
private static boolean hasValueNode(Element node) {
for (int i = 0; i < node.getChildCount(); i++) {
if (node.isText(i)) continue;
Element child = node.getElement(i);
if (child.getName().equalsIgnoreCase(NODE_VALUE)) return true;
}
return false;
}
/**
* Gets the value of the nodeset attribute, for a given node, used for xform bindings.
* @param node - the node.
* @return - the value of the nodeset attribite.
*/
private static String getNodesetAttValue(Element node) {
if (hasValueNode(node)) {
return getNodePath(node) + "/value";
} else if (isMultSelectNode(node)) {
return getNodePath(node) + "/xforms_value";
} else {
return getNodePath(node);
}
}
/**
* Gets the path of a node from the instance node.
* @param node - the node whose path to get.
* @return - the complete path from the instance node.
*/
private static String getNodePath(Element node) {
String path = node.getName();
Element parent = (Element) node.getParent();
while (parent != null && !parent.getName().equalsIgnoreCase(NODE_INSTANCE)) {
path = parent.getName() + NODE_SEPARATOR + path;
if (parent.getParent() != null && parent.getParent() instanceof Element) {
parent = (Element) parent.getParent();
} else {
parent = null;
}
}
return NODE_SEPARATOR + path;
}
}