use of org.kxml2.kdom.Element in project briefcase by opendatakit.
the class XmlManipulationUtils method findMetaTag.
/**
* Traverse submission looking for OpenRosa metadata tag (with or without
* namespace).
*
* @param parent
* @return
*/
private static Element findMetaTag(Element parent, String rootUri) {
for (int i = 0; i < parent.getChildCount(); ++i) {
if (parent.getType(i) == Node.ELEMENT) {
Element child = parent.getElement(i);
String cnUri = child.getNamespace();
String cnName = child.getName();
if (cnName.equals(OPEN_ROSA_METADATA_TAG) && (cnUri == null || cnUri.equals(EMPTY_STRING) || cnUri.equals(rootUri) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE_SLASH) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE_PRELIM))) {
return child;
} else {
Element descendent = findMetaTag(child, rootUri);
if (descendent != null)
return descendent;
}
}
}
return null;
}
use of org.kxml2.kdom.Element in project briefcase by opendatakit.
the class XmlManipulationUtils method parseFormManifestResponse.
public static final List<MediaFile> parseFormManifestResponse(boolean isOpenRosaResponse, Document doc) throws ParsingException {
List<MediaFile> files = new ArrayList<>();
if (!isOpenRosaResponse) {
log.error("Manifest reply doesn't report an OpenRosa version -- bad server?");
throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
}
// Attempt OpenRosa 1.0 parsing
Element manifestElement = doc.getRootElement();
if (!manifestElement.getName().equals("manifest")) {
log.error("Root element is not <manifest> -- was " + manifestElement.getName());
throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
}
String namespace = manifestElement.getNamespace();
if (!isXformsManifestNamespacedElement(manifestElement)) {
log.error("Root element Namespace is incorrect: " + namespace);
throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
}
int nElements = manifestElement.getChildCount();
for (int i = 0; i < nElements; ++i) {
if (manifestElement.getType(i) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element mediaFileElement = (Element) manifestElement.getElement(i);
if (!isXformsManifestNamespacedElement(mediaFileElement)) {
// someone else's extension?
continue;
}
String name = mediaFileElement.getName();
if (name.equalsIgnoreCase("mediaFile")) {
String filename = null;
String hash = null;
String downloadUrl = null;
// don't process descriptionUrl
int childCount = mediaFileElement.getChildCount();
for (int j = 0; j < childCount; ++j) {
if (mediaFileElement.getType(j) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element child = mediaFileElement.getElement(j);
if (!isXformsManifestNamespacedElement(child)) {
// someone else's extension?
continue;
}
String tag = child.getName();
if (tag.equals("filename")) {
filename = XFormParser.getXMLText(child, true);
if (filename != null && filename.length() == 0) {
filename = null;
}
} else if (tag.equals("hash")) {
hash = XFormParser.getXMLText(child, true);
if (hash != null && hash.length() == 0) {
hash = null;
}
} else if (tag.equals("downloadUrl")) {
downloadUrl = XFormParser.getXMLText(child, true);
if (downloadUrl != null && downloadUrl.length() == 0) {
downloadUrl = null;
}
}
}
if (filename == null || downloadUrl == null || hash == null) {
log.error("Manifest entry " + Integer.toString(i) + " is missing one or more tags: filename, hash, or downloadUrl");
throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
}
files.add(new MediaFile(filename, hash, downloadUrl));
}
}
return files;
}
use of org.kxml2.kdom.Element in project briefcase by opendatakit.
the class XmlManipulationUtils method parseDownloadSubmissionResponse.
public static final SubmissionManifest parseDownloadSubmissionResponse(Document doc) throws ParsingException {
// and parse the document...
List<MediaFile> attachmentList = new ArrayList<>();
Element rootSubmissionElement = null;
String instanceID = null;
// Attempt parsing
Element submissionElement = doc.getRootElement();
if (!submissionElement.getName().equals("submission")) {
String msg = "Parsing downloadSubmission reply -- root element is not <submission> :" + submissionElement.getName();
log.error(msg);
throw new ParsingException(msg);
}
String namespace = submissionElement.getNamespace();
if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
String msg = "Parsing downloadSubmission reply -- root element namespace is incorrect:" + namespace;
log.error(msg);
throw new ParsingException(msg);
}
int nElements = submissionElement.getChildCount();
for (int i = 0; i < nElements; ++i) {
if (submissionElement.getType(i) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element subElement = (Element) submissionElement.getElement(i);
namespace = subElement.getNamespace();
if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
// someone else's extension?
continue;
}
String name = subElement.getName();
if (name.equalsIgnoreCase("data")) {
// find the root submission element and get its instanceID attribute
int nIdElements = subElement.getChildCount();
for (int j = 0; j < nIdElements; ++j) {
if (subElement.getType(j) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
rootSubmissionElement = (Element) subElement.getElement(j);
break;
}
if (rootSubmissionElement == null) {
throw new ParsingException("no submission body found in submissionDownload response");
}
instanceID = rootSubmissionElement.getAttributeValue(null, "instanceID");
if (instanceID == null) {
throw new ParsingException("instanceID attribute value is null");
}
} else if (name.equalsIgnoreCase("mediaFile")) {
int nIdElements = subElement.getChildCount();
String filename = null;
String hash = null;
String downloadUrl = null;
for (int j = 0; j < nIdElements; ++j) {
if (subElement.getType(j) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element mediaSubElement = (Element) subElement.getElement(j);
name = mediaSubElement.getName();
if (name.equalsIgnoreCase("filename")) {
filename = XFormParser.getXMLText(mediaSubElement, true);
} else if (name.equalsIgnoreCase("hash")) {
hash = XFormParser.getXMLText(mediaSubElement, true);
} else if (name.equalsIgnoreCase("downloadUrl")) {
downloadUrl = XFormParser.getXMLText(mediaSubElement, true);
}
}
attachmentList.add(new MediaFile(filename, hash, downloadUrl));
} else {
log.warn("Unrecognized tag inside submission: " + name);
}
}
if (rootSubmissionElement == null) {
throw new ParsingException("No submission body found");
}
if (instanceID == null) {
throw new ParsingException("instanceID attribute value is null");
}
// write submission to a string
StringWriter fo = new StringWriter();
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(fo);
// setting the response content type emits the xml header.
// just write the body here...
// this has the xmlns of the submissions download, indicating that it
// originated from a briefcase download. Might be useful for discriminating
// real vs. recovered data?
rootSubmissionElement.setPrefix(null, NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS);
try {
rootSubmissionElement.write(serializer);
serializer.flush();
serializer.endDocument();
fo.close();
} catch (IOException e) {
String msg = "Unexpected IOException";
log.error(msg, e);
throw new ParsingException(msg + ": " + e.getMessage());
}
return new SubmissionManifest(instanceID, fo.toString(), attachmentList);
}
use of org.kxml2.kdom.Element in project briefcase by opendatakit.
the class XmlManipulationUtils method parseFormListResponse.
public static final List<RemoteFormDefinition> parseFormListResponse(boolean isOpenRosaResponse, Document formListDoc) throws ParsingException {
// This gets a list of available forms from the specified server.
List<RemoteFormDefinition> formList = new ArrayList<>();
if (isOpenRosaResponse) {
// Attempt OpenRosa 1.0 parsing
Element xformsElement = formListDoc.getRootElement();
if (!xformsElement.getName().equals("xforms")) {
log.error("Parsing OpenRosa reply -- root element is not <xforms> :" + xformsElement.getName());
throw new ParsingException(BAD_OPENROSA_FORMLIST);
}
String namespace = xformsElement.getNamespace();
if (!isXformsListNamespacedElement(xformsElement)) {
log.error("Parsing OpenRosa reply -- root element namespace is incorrect:" + namespace);
throw new ParsingException(BAD_OPENROSA_FORMLIST);
}
int nElements = xformsElement.getChildCount();
for (int i = 0; i < nElements; ++i) {
if (xformsElement.getType(i) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element xformElement = (Element) xformsElement.getElement(i);
if (!isXformsListNamespacedElement(xformElement)) {
// someone else's extension?
continue;
}
String name = xformElement.getName();
if (!name.equalsIgnoreCase("xform")) {
// someone else's extension?
continue;
}
// this is something we know how to interpret
String formId = null;
String formName = null;
String version = null;
String majorMinorVersion = null;
String description = null;
String downloadUrl = null;
String manifestUrl = null;
// don't process descriptionUrl
int fieldCount = xformElement.getChildCount();
for (int j = 0; j < fieldCount; ++j) {
if (xformElement.getType(j) != Element.ELEMENT) {
// whitespace
continue;
}
Element child = xformElement.getElement(j);
if (!isXformsListNamespacedElement(child)) {
// someone else's extension?
continue;
}
String tag = child.getName();
if (tag.equals("formID")) {
formId = XFormParser.getXMLText(child, true);
if (formId != null && formId.length() == 0) {
formId = null;
}
} else if (tag.equals("name")) {
formName = XFormParser.getXMLText(child, true);
if (formName != null && formName.length() == 0) {
formName = null;
}
} else if (tag.equals("version")) {
version = XFormParser.getXMLText(child, true);
if (version != null && version.length() == 0) {
version = null;
}
} else if (tag.equals("majorMinorVersion")) {
majorMinorVersion = XFormParser.getXMLText(child, true);
if (majorMinorVersion != null && majorMinorVersion.length() == 0) {
majorMinorVersion = null;
}
} else if (tag.equals("descriptionText")) {
description = XFormParser.getXMLText(child, true);
if (description != null && description.length() == 0) {
description = null;
}
} else if (tag.equals("downloadUrl")) {
downloadUrl = XFormParser.getXMLText(child, true);
if (downloadUrl != null && downloadUrl.length() == 0) {
downloadUrl = null;
}
} else if (tag.equals("manifestUrl")) {
manifestUrl = XFormParser.getXMLText(child, true);
if (manifestUrl != null && manifestUrl.length() == 0) {
manifestUrl = null;
}
}
}
if (formId == null || downloadUrl == null || formName == null) {
log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " is missing one or more tags: formId, name, or downloadUrl");
formList.clear();
throw new ParsingException(BAD_OPENROSA_FORMLIST);
}
String versionString = null;
if (version != null && version.length() != 0) {
versionString = version;
} else if (majorMinorVersion != null && majorMinorVersion.length() != 0) {
int idx = majorMinorVersion.indexOf(".");
if (idx == -1) {
versionString = majorMinorVersion;
} else {
versionString = majorMinorVersion.substring(0, idx);
}
}
try {
if (versionString != null) {
// verify that the version string is a long integer value...
Long.parseLong(versionString);
}
} catch (Exception e) {
log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " has an invalid version string: " + versionString, e);
formList.clear();
throw new ParsingException(BAD_OPENROSA_FORMLIST);
}
formList.add(new RemoteFormDefinition(formName, formId, versionString, downloadUrl, manifestUrl));
}
} else {
// Aggregate 0.9.x mode...
// populate HashMap with form names and urls
Element formsElement = formListDoc.getRootElement();
int formsCount = formsElement.getChildCount();
for (int i = 0; i < formsCount; ++i) {
if (formsElement.getType(i) != Element.ELEMENT) {
// whitespace
continue;
}
Element child = formsElement.getElement(i);
String tag = child.getName();
if (tag.equalsIgnoreCase("form")) {
String formName = XFormParser.getXMLText(child, true);
if (formName != null && formName.length() == 0) {
formName = null;
}
String downloadUrl = child.getAttributeValue(null, "url");
downloadUrl = downloadUrl.trim();
if (downloadUrl != null && downloadUrl.length() == 0) {
downloadUrl = null;
}
if (downloadUrl == null || formName == null) {
log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " is missing form name or url attribute");
formList.clear();
throw new ParsingException(BAD_LEGACY_FORMLIST);
}
// Since this is ODK Aggregate 0.9.8 or higher, we know that the
// formId is
// given as a parameter of the URL...
String formId = null;
try {
URL url = new URL(downloadUrl);
String qs = url.getQuery();
if (qs.startsWith(ODK_ID_PARAMETER_EQUALS)) {
formId = qs.substring(ODK_ID_PARAMETER_EQUALS.length());
}
} catch (MalformedURLException e) {
log.warn("bad download url", e);
}
if (formId == null) {
throw new ParsingException("Unable to extract formId from download URL of legacy 0.9.8 server");
}
formList.add(new RemoteFormDefinition(formName, formId, null, downloadUrl, null));
}
}
}
return formList;
}
use of org.kxml2.kdom.Element in project briefcase by opendatakit.
the class XmlManipulationUtils method updateSubmissionMetadata.
public static final String updateSubmissionMetadata(File submissionFile, Document doc) throws MetadataUpdateException {
Element root = doc.getRootElement();
Element metadata = root.getElement(NAMESPACE_ODK, "submissionMetadata");
// and get the instanceID and submissionDate from the metadata.
// we need to put that back into the instance file if not already present
String instanceID = metadata.getAttributeValue("", INSTANCE_ID_ATTRIBUTE_NAME);
String submissionDate = metadata.getAttributeValue("", SUBMISSION_DATE_ATTRIBUTE_NAME);
// read the original document...
Document originalDoc = null;
try {
FileInputStream fs = new FileInputStream(submissionFile);
InputStreamReader fr = new InputStreamReader(fs, "UTF-8");
originalDoc = new Document();
KXmlParser parser = new KXmlParser();
parser.setInput(fr);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
originalDoc.parse(parser);
fr.close();
fs.close();
} catch (IOException e) {
String msg = "Original submission file could not be opened";
log.error(msg, e);
throw new MetadataUpdateException(msg);
} catch (XmlPullParserException e) {
String msg = "Original submission file could not be parsed as XML file";
log.error(msg, e);
throw new MetadataUpdateException(msg);
}
// determine whether it has the attributes already added.
// if they are already there, they better match the values returned by
// Aggregate 1.0
boolean hasInstanceID = false;
boolean hasSubmissionDate = false;
root = originalDoc.getRootElement();
for (int i = 0; i < root.getAttributeCount(); ++i) {
String name = root.getAttributeName(i);
if (name.equals(INSTANCE_ID_ATTRIBUTE_NAME)) {
if (!root.getAttributeValue(i).equals(instanceID)) {
String msg = "Original submission file's instanceID does not match that on server!";
log.error(msg);
throw new MetadataUpdateException(msg);
} else {
hasInstanceID = true;
}
}
if (name.equals(SUBMISSION_DATE_ATTRIBUTE_NAME)) {
Date oldDate = WebUtils.parseDate(submissionDate);
String returnDate = root.getAttributeValue(i);
Date newDate = WebUtils.parseDate(returnDate);
// cross-platform datetime resolution is 1 second.
if (Math.abs(newDate.getTime() - oldDate.getTime()) > 1000L) {
String msg = "Original submission file's submissionDate does not match that on server!";
log.error(msg);
throw new MetadataUpdateException(msg);
} else {
hasSubmissionDate = true;
}
}
}
if (hasInstanceID && hasSubmissionDate) {
log.info("submission already has instanceID and submissionDate attributes: " + submissionFile.getAbsolutePath());
return instanceID;
}
if (!hasInstanceID) {
root.setAttribute("", INSTANCE_ID_ATTRIBUTE_NAME, instanceID);
}
if (!hasSubmissionDate) {
root.setAttribute("", SUBMISSION_DATE_ATTRIBUTE_NAME, submissionDate);
}
// and write out the changes...
// write the file out...
File revisedFile = new File(submissionFile.getParentFile(), "." + submissionFile.getName());
try {
FileOutputStream fos = new FileOutputStream(revisedFile, false);
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(fos, "UTF-8");
originalDoc.write(serializer);
serializer.flush();
fos.close();
// and swap files...
boolean restoreTemp = false;
File temp = new File(submissionFile.getParentFile(), ".back." + submissionFile.getName());
try {
if (temp.exists()) {
if (!temp.delete()) {
String msg = "Unable to remove temporary submission backup file";
log.error(msg);
throw new MetadataUpdateException(msg);
}
}
if (!submissionFile.renameTo(temp)) {
String msg = "Unable to rename submission to temporary submission backup file";
log.error(msg);
throw new MetadataUpdateException(msg);
}
// recovery is possible...
restoreTemp = true;
if (!revisedFile.renameTo(submissionFile)) {
String msg = "Original submission file could not be updated";
log.error(msg);
throw new MetadataUpdateException(msg);
}
// we're successful...
restoreTemp = false;
} finally {
if (restoreTemp) {
if (!temp.renameTo(submissionFile)) {
String msg = "Unable to restore submission from temporary submission backup file";
log.error(msg);
throw new MetadataUpdateException(msg);
}
}
}
} catch (FileNotFoundException e) {
String msg = "Temporary submission file could not be opened";
log.error(msg, e);
throw new MetadataUpdateException(msg);
} catch (IOException e) {
String msg = "Temporary submission file could not be written";
log.error(msg, e);
throw new MetadataUpdateException(msg);
}
return instanceID;
}
Aggregations