* field names.
*/
public static final String XML_ATTRIBUTE_PREFIX = "@";
-
+
/**
* Prefix to prepend to XML namespace prefixes when converting to
* JSON field names.
*/
public static final String XML_NAMESPACE_PREFIX = XML_ATTRIBUTE_PREFIX + "xmlns:";
-
+
/**
* Converts an XML attribute name to a JSON field name.
- *
+ *
* @param xmlAttributeName the XML attribute name
* @return the JSON field name
*/
public static String xmlAttributeNameToJsonFieldName(String xmlAttributeName) {
return XML_ATTRIBUTE_PREFIX + xmlAttributeName;
}
-
+
/**
* Converts a JSON field name to an XML attribute name.
* The field name must be in the expected format, as determined by
* isXmlAttribute().
- *
+ *
* @param jsonFieldName the JSON field name
* @return the XML attribute name
*/
/**
* Converts an XML namespace prefix to a JSON field name.
- *
+ *
* @param xmlNamespacePrefix the XML namespace prefix
* @return the JSON field name
*/
public static String xmlNamespacePrefixToJsonFieldName(String xmlNamespacePrefix) {
return XML_NAMESPACE_PREFIX + xmlNamespacePrefix;
}
-
+
/**
* Converts a JSON field name to an XML namespace prefix.
* The field name must be in the expected format, as determined by
* isXmlNamespace().
- *
+ *
* @param jsonFieldName the JSON field name
* @return the XML namespace prefix
*/
/**
* Determines if a JSON field name represents an XML
* attribute.
- *
+ *
* @param jsonFieldName the field name to test
* @return true if the field name represents an XML attribute,
* false otherwise
public static boolean isXmlAttribute(String jsonFieldName) {
return jsonFieldName.startsWith(XML_ATTRIBUTE_PREFIX);
}
-
+
/**
* Determines if a JSON field name represents an XML
* namespace prefix.
- *
+ *
* @param jsonFieldName the field name to test
* @return true if the field name represents an XML namespace prefix,
* false otherwise
public static boolean isXmlNamespace(String jsonFieldName) {
return jsonFieldName.startsWith(XML_NAMESPACE_PREFIX);
}
-
+
+ /**
+ * Determines if a JSON field name represents XML element content.
+ *
+ * @param jsonFieldName the field name to test
+ * @return true if the field name represents XML element content,
+ * false otherwise
+ */
+ public static boolean isXmlContent(String jsonFieldName) {
+ return jsonFieldName.equals(".");
+ }
+
/**
* Converts an XML element QName to a JSON field name.
- *
+ *
* @param name the XML element QName
* @return the JSON field name
*/
public static String jsonFieldNameFromXMLQName(QName name) {
String prefix = name.getPrefix();
String localPart = name.getLocalPart();
-
+
if (StringUtils.isNotEmpty(prefix)) {
return prefix + ":" + localPart;
}
-
+
return localPart;
}
}
* <ul>
* <li>JSON fields starting with "@xmlns:" are converted XML namespace declarations.</li>
* <li>JSON fields starting with "@" are converted to XML attributes.</li>
+ * <li>JSON fields named "." are converted to XML element content. This is useful when the desired
+ * XML output is an element with one or more attributes, and some text content.<li>
* <li>Other JSON fields are converted to identically-named XML elements.</li>
* <li>The contents of JSON objects are converted to XML child elements.</li>
* <li>The contents of JSON arrays are expanded into multiple XML elements, each
xmlWriter.writeAttribute(localName, value);
}
}
+ else if (field.isScalar() && isXmlContent(name)) {
+ xmlWriter.writeCharacters(value);
+ }
else {
// It doesn't look like an XML attribute or namespace declaration.
// Output an XML element with the same name as the field, whose
public class JsonToXmlStreamConverterTest {
public final String FILE_PATH = "test-data/xmljson/";
-
+
@Test
public void testConvert() throws XMLStreamException, JsonParseException, IOException {
testConvert("record");
testConvert("numeric-json");
testConvert("boolean-json");
testConvert("single-list-item-json");
+ testConvert("export-invocation");
testConvertThrows("empty-json", XMLStreamException.class);
}
-
+
private void testConvert(String fileName) throws XMLStreamException, IOException {
System.out.println("---------------------------------------------------------");
System.out.println("Converting JSON to XML: " + fileName);
ClassLoader classLoader = getClass().getClassLoader();
File jsonFile = new File(classLoader.getResource(FILE_PATH + fileName + ".json").getFile());
File xmlFile = new File(classLoader.getResource(FILE_PATH + fileName + ".xml").getFile());
-
+
FileInputStream in = new FileInputStream(jsonFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
-
+
JsonToXmlStreamConverter converter = new JsonToXmlStreamConverter(in, out);
converter.convert();
-
+
System.out.println(out.toString("UTF-8"));
-
+
Diff diff = DiffBuilder
.compare(Input.fromStream(out.toInputStream()))
.withTest(Input.fromFile(xmlFile))
.ignoreComments()
.ignoreWhitespace()
.build();
-
+
System.out.println(diff.toString());
-
+
assertFalse(diff.hasDifferences());
}
-
+
private void testConvertThrows(String fileName, Class<?> exceptionClass) throws XMLStreamException, IOException {
boolean caught = false;
-
+
try {
testConvert(fileName);
}
catch(XMLStreamException|IOException e) {
if (e.getClass().isAssignableFrom(exceptionClass)) {
caught = true;
-
+
System.out.println(e.toString());
}
else {
throw e;
}
}
-
+
assertTrue(caught);
}
}
--- /dev/null
+{
+ "ns2:invocationContext": {
+ "@xmlns:ns2": "http://collectionspace.org/services/common/invocable",
+ "mode": "single",
+ "singleCSID": "dc929ede-081f-4eaa-a439-358b89887c91",
+ "docType": "CollectionObject",
+ "includeFields": {
+ "field": [
+ "collectionobjects_common:objectNumber",
+ {
+ "@name": "fieldCollectionDateGroup",
+ ".": "collectionobjects_common:fieldCollectionDateGroup/dateDisplayDate"
+ },
+ "collectionobjects_common:titleGroupList/titleGroup/title",
+ "collectionobjects_common:titleGroupList/titleGroup/titleLanguage",
+ "collectionobjects_common:titleGroupList/titleGroup/titleType",
+ "collectionobjects_common:titleGroupList/titleGroup/titleTranslationSubGroupList/titleTranslationSubGroup/titleTranslation",
+ "collectionobjects_common:titleGroupList/titleGroup/titleTranslationSubGroupList/titleTranslationSubGroup/titleTranslationLanguage"
+ ]
+ },
+ "outputMIME": "text/csv"
+ }
+}
--- /dev/null
+<ns2:invocationContext xmlns:ns2="http://collectionspace.org/services/common/invocable">
+ <mode>single</mode>
+ <singleCSID>dc929ede-081f-4eaa-a439-358b89887c91</singleCSID>
+ <docType>CollectionObject</docType>
+ <includeFields>
+ <field>collectionobjects_common:objectNumber</field>
+ <field name="fieldCollectionDateGroup">collectionobjects_common:fieldCollectionDateGroup/dateDisplayDate</field>
+ <field>collectionobjects_common:titleGroupList/titleGroup/title</field>
+ <field>collectionobjects_common:titleGroupList/titleGroup/titleLanguage</field>
+ <field>collectionobjects_common:titleGroupList/titleGroup/titleType</field>
+ <field>collectionobjects_common:titleGroupList/titleGroup/titleTranslationSubGroupList/titleTranslationSubGroup/titleTranslation</field>
+ <field>collectionobjects_common:titleGroupList/titleGroup/titleTranslationSubGroupList/titleTranslationSubGroup/titleTranslationLanguage</field>
+ </includeFields>
+ <outputMIME>text/csv</outputMIME>
+</ns2:invocationContext>