practicalxml-commits Mailing List for Practical XML (Page 7)
Brought to you by:
kdgregory
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(6) |
Nov
(4) |
Dec
(35) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(5) |
Feb
|
Mar
|
Apr
(7) |
May
|
Jun
|
Jul
(12) |
Aug
(24) |
Sep
(39) |
Oct
(16) |
Nov
(4) |
Dec
(7) |
2010 |
Jan
(10) |
Feb
|
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(4) |
Dec
(3) |
2011 |
Jan
(1) |
Feb
|
Mar
(1) |
Apr
(1) |
May
(3) |
Jun
|
Jul
|
Aug
(1) |
Sep
(10) |
Oct
(1) |
Nov
(1) |
Dec
(7) |
2012 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
(9) |
Jun
|
Jul
(5) |
Aug
(6) |
Sep
|
Oct
(1) |
Nov
|
Dec
|
2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(16) |
Jul
|
Aug
(6) |
Sep
(10) |
Oct
|
Nov
(2) |
Dec
|
2014 |
Jan
(5) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
(6) |
Nov
|
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(5) |
2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-24 19:13:37
|
Revision: 160 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=160&view=rev Author: kdgregory Date: 2009-09-24 19:13:30 +0000 (Thu, 24 Sep 2009) Log Message: ----------- JsonConverter: add method to convert to JSON using existing buffer Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java 2009-09-24 17:52:00 UTC (rev 159) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java 2009-09-24 19:13:30 UTC (rev 160) @@ -94,7 +94,25 @@ */ public static String convertToJson(Element root, Xml2JsonOptions... options) { - return new Xml2JsonConverter().convert(root, new StringBuilder(256)) - .toString(); + return convertToJson(root, new StringBuilder(256), options).toString(); } + + + /** + * Creates a new JSON string from the the passed <code>Element</code>, and + * appends that string to the passed buffer (the buffer is actually passed + * into the JSON construction code). + * + * @param dom The source element -- this may or may not be the + * root element of its document. + * @param buf A buffer to which the JSON is appended. + * @param options Conversion options. + * + * @return The buffer, as a convenience for chained calls. + */ + public static StringBuilder convertToJson( + Element root, StringBuilder buf, Xml2JsonOptions... options) + { + return new Xml2JsonConverter(options).convert(root,buf); + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-24 17:52:15
|
Revision: 159 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=159&view=rev Author: kdgregory Date: 2009-09-24 17:52:00 +0000 (Thu, 24 Sep 2009) Log Message: ----------- xml -> json: make quoted fieldnames the default Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-24 17:52:00 UTC (rev 159) @@ -142,11 +142,12 @@ String next = nextToken(); if (atEndOfSequence(next, "}", false)) return; - if (next.equals("\"")) - next = parseString(); while (true) { + if (next.equals("\"")) + next = parseString(); + Element child = appendChild(parent, next); expect(":"); Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 17:52:00 UTC (rev 159) @@ -167,12 +167,16 @@ private StringBuilder appendFieldName(StringBuilder buf, String name) { - if (_options.contains(Xml2JsonOptions.QUOTE_FIELD_NAMES)) + if (_options.contains(Xml2JsonOptions.UNQUOTED_FIELD_NAMES)) + { + buf.append(name); + } + else + { buf.append('"') .append(name) .append('"'); - else - buf.append(name); + } buf.append(": "); return buf; Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 17:52:00 UTC (rev 159) @@ -21,12 +21,15 @@ public enum Xml2JsonOptions { /** - * If enabled, field names will be quoted. This is required by the - * <a href="http://www.json.org/">JSON spec</a>, so should be used - * if you expect to use the result anywhere but in a browser. It is - * not required by <code>eval()</code>, nor for explicit scripting. + * If enabled, field names will not be quoted. This violates the + * <a href="http://www.json.org/">JSON spec</a>, which defines the + * production "pair" as "string : value" (and "string" is quoted). + * However, literal Java objects do not quote the field names, so + * if you use this converter to create explicit scripts, you won't + * want to follow the spec (and, not surprisingly, <code>eval()</code> + * doesn't require quoted names either). */ - QUOTE_FIELD_NAMES, + UNQUOTED_FIELD_NAMES, /** * If enabled, the entire string is wrapped by parentheses. This is Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-24 17:52:00 UTC (rev 159) @@ -255,6 +255,27 @@ } + // regression test! + public void testConvertTwoElementWithQuotedFieldNames() throws Exception + { + String src = "{\"foo\": 123, \"bar\": 456}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(2, root.getChildNodes().getLength()); + + Element child1 = (Element)root.getFirstChild(); + assertEquals("foo", child1.getNodeName()); + assertEquals("123", DomUtil.getText(child1)); + assertEquals(0, DomUtil.getChildren(child1).size()); + + Element child2 = (Element)child1.getNextSibling(); + assertEquals("bar", child2.getNodeName()); + assertEquals("456", DomUtil.getText(child2)); + assertEquals(0, DomUtil.getChildren(child2).size()); + } + + public void testFailObjectMissingCommaBetweenTerms() throws Exception { String src = "{foo: 123 bar: 456}"; Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java 2009-09-24 17:52:00 UTC (rev 159) @@ -111,6 +111,20 @@ } + public void testUnquotedFieldnames() throws Exception + { + Element src = element("data", + element("foo", text("bar")), + element("argle", text("bargle"))) + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src, Xml2JsonOptions.UNQUOTED_FIELD_NAMES); + Element dst = JsonConverter.convertToXml(json, "test") + .getDocumentElement(); + + assertChildren(src, dst); + } + + public void testRepeatedElements() throws Exception { Element src = element("data", Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 17:05:17 UTC (rev 158) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 17:52:00 UTC (rev 159) @@ -59,7 +59,7 @@ public void testSingleChild() throws Exception { convertAndAssert( - "{foo: \"bar\"}", + "{\"foo\": \"bar\"}", element("data", element("foo", text("bar")))); } @@ -68,7 +68,7 @@ public void testTwoChildren() throws Exception { convertAndAssert( - "{foo: \"bar\", argle: \"bargle\"}", + "{\"foo\": \"bar\", \"argle\": \"bargle\"}", element("data", element("foo", text("bar")), element("argle", text("bargle")))); @@ -78,7 +78,7 @@ public void testChildAndGrandchildren() throws Exception { convertAndAssert( - "{foo: \"bar\", argle: {biz: \"baz\", fizz: \"buzz\"}}", + "{\"foo\": \"bar\", \"argle\": {\"biz\": \"baz\", \"fizz\": \"buzz\"}}", element("data", element("foo", text("bar")), element("argle", @@ -91,7 +91,7 @@ { // note that "argle" elements are not adjacent, must become adjacent convertAndAssert( - "{foo: \"bar\", argle: [\"bargle\", \"wargle\"], baz: \"bar\"}", + "{\"foo\": \"bar\", \"argle\": [\"bargle\", \"wargle\"], \"baz\": \"bar\"}", element("data", element("foo", text("bar")), element("argle", text("bargle")), @@ -103,7 +103,7 @@ public void testArrayWithNestedObject() throws Exception { convertAndAssert( - "{foo: \"bar\", argle: [\"bargle\", {foo: \"bar\", bar: \"baz\"}]}", + "{\"foo\": \"bar\", \"argle\": [\"bargle\", {\"foo\": \"bar\", \"bar\": \"baz\"}]}", element("data", element("foo", text("bar")), element("argle", text("bargle")), @@ -117,7 +117,7 @@ public void testMixedContentWithWhitespace() throws Exception { convertAndAssert( - "{foo: \"bar\"}", + "{\"foo\": \"bar\"}", element("data", text(" "), element("foo", text("bar")), @@ -128,26 +128,26 @@ public void testWhitespace() throws Exception { convertAndAssert( - "{foo: \" \"}", + "{\"foo\": \" \"}", element("data", element("foo", text(" ")))); } - public void testQuotedFieldnames() throws Exception + public void testUnquotedFieldnames() throws Exception { convertAndAssert( - "{\"foo\": \"bar\"}", + "{foo: \"bar\"}", element("data", element("foo", text("bar"))), - Xml2JsonOptions.QUOTE_FIELD_NAMES); + Xml2JsonOptions.UNQUOTED_FIELD_NAMES); } public void testWrapWithParens() throws Exception { convertAndAssert( - "({foo: \"bar\"})", + "({\"foo\": \"bar\"})", element("data", element("foo", text("bar"))), Xml2JsonOptions.WRAP_WITH_PARENS); @@ -156,6 +156,8 @@ public void testStringEscaping() throws Exception { + // I'm using unquoted field names here because there are already + // far too many escape sequences for the test to be readable convertAndAssert( "{backslash: \"\\\\\", " + "quote: \"\\\"\", " @@ -165,6 +167,7 @@ element("backslash", text("\\")), element("quote", text("\"")), element("nonprint", text("\b\f\n\r\t")), - element("unicode", text("b\u00e4r")))); + element("unicode", text("b\u00e4r"))), + Xml2JsonOptions.UNQUOTED_FIELD_NAMES); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-24 17:05:30
|
Revision: 158 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=158&view=rev Author: kdgregory Date: 2009-09-24 17:05:17 +0000 (Thu, 24 Sep 2009) Log Message: ----------- xml -> json: add option to wrap output in parens Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 16:58:59 UTC (rev 157) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 17:05:17 UTC (rev 158) @@ -63,7 +63,15 @@ */ public StringBuilder convert(Element elem, StringBuilder buf) { - return append(buf, elem); + if (_options.contains(Xml2JsonOptions.WRAP_WITH_PARENS)) + { + buf.append("("); + append(buf, elem); + buf.append(")"); + } + else + append(buf, elem); + return buf; } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 16:58:59 UTC (rev 157) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 17:05:17 UTC (rev 158) @@ -26,5 +26,13 @@ * if you expect to use the result anywhere but in a browser. It is * not required by <code>eval()</code>, nor for explicit scripting. */ - QUOTE_FIELD_NAMES + QUOTE_FIELD_NAMES, + + /** + * If enabled, the entire string is wrapped by parentheses. This is + * needed for strings that will be passed to <code>eval()</code>. + * Note that the resulting string is not acceptable to {@link + * Json2XmlConverter}. + */ + WRAP_WITH_PARENS } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 16:58:59 UTC (rev 157) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 17:05:17 UTC (rev 158) @@ -144,6 +144,16 @@ } + public void testWrapWithParens() throws Exception + { + convertAndAssert( + "({foo: \"bar\"})", + element("data", + element("foo", text("bar"))), + Xml2JsonOptions.WRAP_WITH_PARENS); + } + + public void testStringEscaping() throws Exception { convertAndAssert( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-24 16:59:08
|
Revision: 157 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=157&view=rev Author: kdgregory Date: 2009-09-24 16:58:59 +0000 (Thu, 24 Sep 2009) Log Message: ----------- xml -> json: support quoted fieldnames Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-24 01:21:05 UTC (rev 156) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-24 16:58:59 UTC (rev 157) @@ -29,6 +29,8 @@ * only once (thus thread-safety is not an issue). * <p> * See <a href="http://www.json.org/">json.org</a> for the JSON grammar. + * This implementation will also accept strings that do not quote their + * field names. * <p> * The current implementation creates a child element for each element * of an array, producing output similar to that from the Bean->XML @@ -140,6 +142,8 @@ String next = nextToken(); if (atEndOfSequence(next, "}", false)) return; + if (next.equals("\"")) + next = parseString(); while (true) { Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 01:21:05 UTC (rev 156) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-24 16:58:59 UTC (rev 157) @@ -31,12 +31,12 @@ */ public class Xml2JsonConverter { - private EnumSet<Json2XmlOptions> _options = EnumSet.noneOf(Json2XmlOptions.class); + private EnumSet<Xml2JsonOptions> _options = EnumSet.noneOf(Xml2JsonOptions.class); - public Xml2JsonConverter(Json2XmlOptions... options) + public Xml2JsonConverter(Xml2JsonOptions... options) { - for (Json2XmlOptions option : options) + for (Xml2JsonOptions option : options) _options.add(option); } @@ -85,15 +85,6 @@ } - private StringBuilder appendText(StringBuilder buf, String text) - { - buf.append('"') - .append(JsonUtil.escape(text)) - .append('"'); - return buf; - } - - private StringBuilder appendObject(StringBuilder buf, List<Element> children) { List<String> names = new ArrayList<String>(); @@ -105,7 +96,7 @@ for (Iterator<String> itx = names.iterator() ; itx.hasNext() ; ) { String name = itx.next(); - buf.append(name).append(": "); + appendFieldName(buf, name); if (arrays.containsKey(name)) appendArray(buf, arrays.get(name)); else @@ -164,4 +155,27 @@ } } } + + + private StringBuilder appendFieldName(StringBuilder buf, String name) + { + if (_options.contains(Xml2JsonOptions.QUOTE_FIELD_NAMES)) + buf.append('"') + .append(name) + .append('"'); + else + buf.append(name); + + buf.append(": "); + return buf; + } + + + private StringBuilder appendText(StringBuilder buf, String text) + { + buf.append('"') + .append(JsonUtil.escape(text)) + .append('"'); + return buf; + } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 01:21:05 UTC (rev 156) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-24 16:58:59 UTC (rev 157) @@ -20,5 +20,11 @@ */ public enum Xml2JsonOptions { - // nothing here right now + /** + * If enabled, field names will be quoted. This is required by the + * <a href="http://www.json.org/">JSON spec</a>, so should be used + * if you expect to use the result anywhere but in a browser. It is + * not required by <code>eval()</code>, nor for explicit scripting. + */ + QUOTE_FIELD_NAMES } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-24 01:21:05 UTC (rev 156) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-24 16:58:59 UTC (rev 157) @@ -168,6 +168,21 @@ } + public void testConvertSingleElementWithQuotedFieldname() throws Exception + { + String src = "{\"foo\": 123}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertEquals("123", DomUtil.getText(child)); + assertEquals(0, DomUtil.getChildren(child).size()); + } + + public void testFailUnterminatedString() throws Exception { String src = "{foo: \"bar}"; Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 01:21:05 UTC (rev 156) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-24 16:58:59 UTC (rev 157) @@ -34,10 +34,12 @@ // Support Code //---------------------------------------------------------------------------- - public void convertAndAssert(String expected, ElementNode rootNode) + public void convertAndAssert( + String expected, ElementNode rootNode, + Xml2JsonOptions... options) { Element root = rootNode.toDOM().getDocumentElement(); - String json = new Xml2JsonConverter().convert(root); + String json = new Xml2JsonConverter(options).convert(root); assertEquals(expected, json); } @@ -132,6 +134,16 @@ } + public void testQuotedFieldnames() throws Exception + { + convertAndAssert( + "{\"foo\": \"bar\"}", + element("data", + element("foo", text("bar"))), + Xml2JsonOptions.QUOTE_FIELD_NAMES); + } + + public void testStringEscaping() throws Exception { convertAndAssert( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-24 01:21:23
|
Revision: 156 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=156&view=rev Author: kdgregory Date: 2009-09-24 01:21:05 +0000 (Thu, 24 Sep 2009) Log Message: ----------- update BeanConverter package docs Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/package.html Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/package.html =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/package.html 2009-09-23 23:42:59 UTC (rev 155) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/package.html 2009-09-24 01:21:05 UTC (rev 156) @@ -29,51 +29,83 @@ <p> Additional conversion rules are as follows: -<table border="1"> +<table border="1" > <tr><th>Java Object Type - <th>{@link #convertToXml} - <th>{@link #convertToJava} + <th>Java to XML + <th>XML to Java +<tr><td>Null Values + <td>By default, any field containing a null value is ignored and not + written to the output. + <td>By default, any element that does not contain a Text child is treated + as <code>null</code>, and ignored (because bean fields should already + be null at construction). Optionally requires an <code>xsi:nil</code> + attribute for values that are legally null, and throws if an empty + element appears without it. <tr><td>Primitives, Wrapper objects, and String - <td> - <td> + <td>By default, calls <code>toString()</code> on the object; optionally + uses a Schema-compliant formatter (only applies to dates and floating + point numbers). + <td>Uses the built-in parsers for the destination type, except where + instructed to use Schema-compliant parsing. <tr><td>Arrays - <td>Elements of the array are written in sequence to the DOM, using the - element name "<code>data</code>". Elements are given an attribute - named "<code>index</code>", which contains the element's position - within the array. - <td>Elements of the array are processed in sequence, ignoring both - element name and "index" attribute. + <td>By default, arrays are converted using one "container" element to + represent the array, and multiple children of that container to + represent the elements in the array. The container element is named + after the field being converted. By default, the child elements are + named "data", but optionally may be named after the field or a + depluralized version of the field (eg, if the field is named "widgets" + the child elements may be named "widgets" or "widget" depending on + options). + <p> + An alternate option is to output the array's elements directly, as + repeated elements named after the field, without a "container" element + (eg, if a bean has a field named "widgets" with 3 elements, then the + XML produced from that bean will have three Elements named "widgets", + each of which contains the data from the corresponding array element). + <p> + Elements may also be given an "index" attribute, holding their index + within the array (numbered from 0). This attribute is not output by + default, as its chief use is self-documenting data. + <td>The DOM must have a "container" element; the children of this element + become the elements of the array. The names of the children are ignored, + as is any "index" attribute. The children are converted according to the + base element type of the array. <tr><td>Lists and Sets - <td>The collection is iterated, and elements are written in sequence to - the DOM, using the element name "<code>data</code>". Elements are - given an attribute named "<code>index</code>", which contains the - element's position within the iteration (meaningful only for lists). - <td>Elements of the are processed in sequence, ignoring both element - name and "index" attribute. + <td>The collection is written as if it were an array (qv). Child elements are + output in iterator order. + <td>The collection is processed as it if were an array (qv), with one (major) + difference: since all collections inherently contain Objects, there is no + type information to drive conversion. If an <code>xsi:type</code> attribute + is present, it will be used to drive conversion. Otherwise, the element will + be converted as a <code>String</code> (which will fail for complex types, + because string conversion assumes a single text node). <p> - If an <code>xsi:type</code> attribute is present, it will be used - to drive conversion of the element. Otherwise, the element will be - converted as a <code>String</code> (which will fail for complex - types, because string conversion assumes a single text node). - <p> Where the caller specifies an interface as the conversion class, the converter will choose an appropriate implementation class: <ul> <li> <code>ArrayList</code> for <code>List</code> or <code>Collection</code> <li> <code>TreeSet</code> for <code>SortedSet</code> - <li> <code>HashSet</code> for <code>Set</code> + <li> <code>HashSet</code> for all other <code>Set</code>s </ul> <tr><td>Maps - <td>The collection is iterated, and elements are written in sequence to - the DOM. Depending on the output options, either the entry key will - be used as the element name, or the name will be "<code>data</code>" - and the key stored in an attribute named "<code>key</code>". The - former option is only permitted if all keys in the map are valid - XML element names; otherwise the converter will throw. - <td>Elements are processed in sequence. The converter first looks for - a "<code>key</code>" attribute, and will use it as the entry key - if found. Otherwise, it will use the element name. If your maps - are being reduced to a single entry, look for a missing attribute. + <td>The map itself is represented by a "container" element, which holds one + child per map entry. The map's entry-set is iterated, and children are + emitted in the order of this iteration. + <p> + By default, child elements have the name "<code>data</code>", with an + attribute "<code>key</code>" that contains the key used to reference + the item in the map. Optionally, the map key may be used as the element + name, meaning that the output of a map is indistinguishable from that + of a bean. However, if this option is used, all map keys must be valid + XML element names, or the converter will throw. + <td>The converter expects a "container" element with one child per map + entry. Elements are processed in sequence, which means that later + elements with the same key value will overwrite earlier elements. + <p> + When processing an element, the converter first looks for an attribute + named "<code>key</code>", and will use it as the entry key if found. + Otherwise, it will use the element name. If your maps are being reduced + to a single entry, look for a missing attribute. <p> If an <code>xsi:type</code> attribute is present, it will be used to drive conversion of the element. Otherwise, the element will be @@ -82,11 +114,21 @@ <p> Where the caller specifies an interface as the conversion class, the converter will choose an appropriate implementation class: - <code>TreeMap</code> for <code>SortedMap</code>, and <code>HashMap - </code> for <code>Map</code>. + <ul> + <li> <code>TreeMap</code> for <code>SortedMap</code> + <li> <code>HashMap</code> for all other <code>Map</code>s + </ul> <tr><td>Bean-structured Objects <td>The object is introspected, and properties are written in the order - provided by the <code>Introspector</code>. + provided by the <code>Introspector</code>. Note that this means you + can't validate beans against a schema, as the order of elements may + change. + <p> + <strong>Warning</strong>: + Bean-to-XML conversion uses <code>java.beans.Introspector</code>, which + holds a cache of introspected objects. If you use this conversion in an + app-server you should call <code>Introspector.flushCaches()</code> during + deploy. <td>The bean class must provide a no-argument constructor (otherwise it doesn't follow the bean spec, and we can't use it). <p> @@ -109,11 +151,5 @@ <td>not supported </table> -<strong>Warning</strong>: -Bean-to-XML conversion uses <code>java.beans.Introspector</code>, which -holds a cache of introspected objects. If you use this conversion in an -app-server you should call <code>Introspector.flushCaches()</code> during -deploy. - </body> </html> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 23:43:13
|
Revision: 155 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=155&view=rev Author: kdgregory Date: 2009-09-23 23:42:59 +0000 (Wed, 23 Sep 2009) Log Message: ----------- bean->xml conversion now supports writing arrays/lists/sets as repeated siblings Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 21:46:18 UTC (rev 154) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 23:42:59 UTC (rev 155) @@ -167,11 +167,15 @@ if (!array.getClass().isArray()) return false; - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(array)); - Appender childAppender = new IndexedAppender(parent, _options); String childName = determineChildNameForSequence(name); + Appender childAppender = appender; + if (!_options.contains(Bean2XmlOptions.SEQUENCE_AS_REPEATED_ELEMENTS)) + { + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(array)); + childAppender = new IndexedAppender(parent, _options); + } + int length = Array.getLength(array); - for (int idx = 0 ; idx < length ; idx++) { Object value = Array.get(array, idx); @@ -201,10 +205,14 @@ if (!(obj instanceof Collection)) return false; - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); - Appender childAppender = new IndexedAppender(parent, _options); String childName = determineChildNameForSequence(name); - + Appender childAppender = appender; + if (!_options.contains(Bean2XmlOptions.SEQUENCE_AS_REPEATED_ELEMENTS)) + { + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); + childAppender = new IndexedAppender(parent, _options); + } + for (Object value : (Collection<?>)obj) { convert(value, childName, childAppender); @@ -255,18 +263,22 @@ else convert(value, name, appender); } - + private String determineChildNameForSequence(String parentName) { if (StringUtils.isEmpty(parentName)) return ConversionStrings.EL_COLLECTION_ITEM; - + + if (_options.contains(Bean2XmlOptions.SEQUENCE_AS_REPEATED_ELEMENTS)) + return parentName; + if (!_options.contains(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT)) - return ConversionStrings.EL_COLLECTION_ITEM; - + return ConversionStrings.EL_COLLECTION_ITEM; + if (parentName.endsWith("s") || parentName.endsWith("S")) return parentName.substring(0, parentName.length() - 1); + return parentName; } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 21:46:18 UTC (rev 154) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 23:42:59 UTC (rev 155) @@ -28,7 +28,17 @@ */ INTROSPECT_MAPS, + /** + * Will create sequences (arrays, lists, and sets) as repeated elements + * rather than a parent-children construct. This option is invalid when + * converting an array as the top-level object, as it would cause the + * creation of multiple root elements. It also produces output that can + * not, at this time, be processed correctly by {@link Xml2BeanConverter}. + */ + SEQUENCE_AS_REPEATED_ELEMENTS, + + /** * Will add an <code>index</code> attribute to the child elements of * sequences (arrays, lists, sets); the value of this attribute is the * element's position in the sequence (numbered from 0). This index is Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 21:46:18 UTC (rev 154) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 23:42:59 UTC (rev 155) @@ -651,16 +651,15 @@ public void testConvertCompoundBeanDefault() throws Exception { - // at this point, I'm convinced the type output works, so we'll do default - // output and then use XPath for all assertions ... but note nulls in data - Bean2XmlConverter driver = new Bean2XmlConverter(); - - CompoundBean bean = new CompoundBean( + CompoundBean data = new CompoundBean( new SimpleBean("zippy", 123, null, true), new int[] { 1, 2, 3 }, Arrays.asList("foo", null, "baz")); - Element root = driver.convert(bean, "test"); + // at this point, I'm convinced the type output works, so we'll do default + // output and then use XPath for all assertions ... but note nulls in data + Element root = new Bean2XmlConverter() + .convert(data, "test"); // System.out.println(OutputUtil.compactString(root.getOwnerDocument())); DomAsserts.assertEquals("zippy", root, "/test/simple/sval"); @@ -676,6 +675,48 @@ } + public void testConvertSequenceAsRepeatedElements() throws Exception + { + // since we can't just pass an array into this conversion (because it + // would try to make multiple root elements), we'll use a compound bean + // and validate its components (and we'll leave a null in to verify + // that we ignore it) + + CompoundBean data = new CompoundBean( + null, + new int[] { 1, 2, 3 }, + Arrays.asList("foo", null, "baz")); + + Element root = new Bean2XmlConverter( + Bean2XmlOptions.SEQUENCE_AS_REPEATED_ELEMENTS) + .convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + DomAsserts.assertEquals("1", root, "/test/primArray[1]"); + DomAsserts.assertEquals("2", root, "/test/primArray[2]"); + DomAsserts.assertEquals("3", root, "/test/primArray[3]"); + + DomAsserts.assertEquals("foo", root, "/test/stringList[1]"); + DomAsserts.assertEquals("baz", root, "/test/stringList[2]"); + } + + + public void testFailSequenceAsRepeatedElementsAtRoot() throws Exception + { + int[] data = new int[] { 1, 2, 3 }; + + try + { + new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_AS_REPEATED_ELEMENTS) + .convert(data, "test"); + } + catch (ConversionException ee) + { + // success + } + } + + public void testNamespacedConversion() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 21:46:31
|
Revision: 154 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=154&view=rev Author: kdgregory Date: 2009-09-23 21:46:18 +0000 (Wed, 23 Sep 2009) Log Message: ----------- change child naming code for sequences (bugfix) Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 21:25:10 UTC (rev 153) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 21:46:18 UTC (rev 154) @@ -157,24 +157,17 @@ extends BasicAppender { private int _index = 0; - private String _elementName = ConversionStrings.EL_COLLECTION_ITEM; public IndexedAppender(Element parent, EnumSet<Bean2XmlOptions> options) { super(parent, options); - if (options.contains(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT)) - { - _elementName = DomUtil.getLocalName(parent); - if (_elementName.endsWith("s") || _elementName.endsWith("S")) - _elementName = _elementName.substring(0, _elementName.length() - 1); - } } @Override public Element appendValue(String name, String type, String value) { - Element child = super.appendValue(_elementName, type, value); + Element child = super.appendValue(name, type, value); if ((child != null) && isOptionSet(Bean2XmlOptions.SEQUENCE_INDEXES)) child.setAttribute(ConversionStrings.AT_ARRAY_INDEX, String.valueOf(_index++)); return child; Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 21:25:10 UTC (rev 153) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 21:46:18 UTC (rev 154) @@ -32,6 +32,7 @@ import net.sf.practicalxml.converter.internal.ConversionStrings; import net.sf.practicalxml.converter.internal.DomUtilToo; import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; +import net.sf.practicalxml.internal.StringUtils; /** @@ -77,7 +78,7 @@ { Element root = DomUtil.newDocument(nsUri, rootName); doXsiNamespaceHack(root); - convert(obj, "", new DirectAppender(root, _options)); + convert(obj, rootName, new DirectAppender(root, _options)); return root; } @@ -168,11 +169,13 @@ Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(array)); Appender childAppender = new IndexedAppender(parent, _options); + String childName = determineChildNameForSequence(name); int length = Array.getLength(array); + for (int idx = 0 ; idx < length ; idx++) { Object value = Array.get(array, idx); - convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); + convert(value, childName, childAppender); } return true; } @@ -200,9 +203,11 @@ Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); Appender childAppender = new IndexedAppender(parent, _options); + String childName = determineChildNameForSequence(name); + for (Object value : (Collection<?>)obj) { - convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); + convert(value, childName, childAppender); } return true; } @@ -250,4 +255,18 @@ else convert(value, name, appender); } + + + private String determineChildNameForSequence(String parentName) + { + if (StringUtils.isEmpty(parentName)) + return ConversionStrings.EL_COLLECTION_ITEM; + + if (!_options.contains(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT)) + return ConversionStrings.EL_COLLECTION_ITEM; + + if (parentName.endsWith("s") || parentName.endsWith("S")) + return parentName.substring(0, parentName.length() - 1); + return parentName; + } } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java 2009-09-23 21:25:10 UTC (rev 153) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java 2009-09-23 21:46:18 UTC (rev 154) @@ -160,8 +160,6 @@ { Element root = DomUtil.newDocument("root"); - // note: index shouldn't increment on null value, so put the - // null entry between not-null entries Appender appender = new IndexedAppender(root, useOptions()); Element child0 = appender.appendValue("foo", "bar", "baz"); Element childX = appender.appendValue("bing", "bang", null); @@ -174,10 +172,7 @@ assertNull(childX); assertNameTypeValue(child0, "foo", "", "baz"); - assertEquals("0", child0.getAttribute("index")); - assertNameTypeValue(child1, "argle", "", "wargle"); - assertEquals("1", child1.getAttribute("index")); } @@ -201,10 +196,34 @@ assertXsiNil(child2, true); assertNameTypeValue(child2, "bing", "", null); - assertEquals("2", child2.getAttribute("index")); } + public void testIndexedAppenderWithIndexOption() throws Exception + { + Element root = DomUtil.newDocument("root"); + + // note: index shouldn't increment on null value, so put the + // null entry between not-null entries + Appender appender = new IndexedAppender(root, useOptions(Bean2XmlOptions.SEQUENCE_INDEXES)); + Element child0 = appender.appendValue("foo", "bar", "baz"); + Element childX = appender.appendValue("bing", "bang", null); + Element child1 = appender.appendValue("argle", "bargle", "wargle"); + + List<Element> children = DomUtil.getChildren(root); + assertEquals(2, children.size()); + assertSame(child0, children.get(0)); + assertSame(child1, children.get(1)); + assertNull(childX); + + assertNameTypeValue(child0, "foo", "", "baz"); + assertEquals("0", child0.getAttribute("index")); + + assertNameTypeValue(child1, "argle", "", "wargle"); + assertEquals("1", child1.getAttribute("index")); + } + + public void testMapAppenderDefault() throws Exception { Element root = DomUtil.newDocument("root"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 21:25:41
|
Revision: 153 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=153&view=rev Author: kdgregory Date: 2009-09-23 21:25:10 +0000 (Wed, 23 Sep 2009) Log Message: ----------- Bean2XmlOptions: renames Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 21:25:10 UTC (rev 153) @@ -93,7 +93,7 @@ protected void setType(Element elem, String type) { - if (isOptionSet(Bean2XmlOptions.ADD_XSI_TYPE)) + if (isOptionSet(Bean2XmlOptions.XSI_TYPE)) DomUtilToo.setXsiType(elem, type); } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-23 21:25:10 UTC (rev 153) @@ -114,7 +114,7 @@ private boolean shouldUseXsdFormatting() { return _options.contains(Bean2XmlOptions.XSD_FORMAT) - || _options.contains(Bean2XmlOptions.ADD_XSI_TYPE); + || _options.contains(Bean2XmlOptions.XSI_TYPE); } @@ -137,7 +137,7 @@ private void doXsiNamespaceHack(Element root) { if (_options.contains(Bean2XmlOptions.XSI_NIL) - && !_options.contains(Bean2XmlOptions.ADD_XSI_TYPE)) + && !_options.contains(Bean2XmlOptions.XSI_TYPE)) { DomUtilToo.setXsiNil(root, false); } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 21:25:10 UTC (rev 153) @@ -22,17 +22,6 @@ public enum Bean2XmlOptions { /** - * Will add an <code>xsi:type</code> attribute to each element. For values - * covered by the XML Schema simple types, this attribute's value will be - * "<code>xsd:TYPE</code>", where TYPE is the XSD type name. For complex - * types, this attribute's value will be "<code>java:TYPE</code>", where - * TYPE is the fully-qualified classname. - * <p> - * <em>This option implies {@link #XSD_FORMAT} for simple types</em>. - */ - ADD_XSI_TYPE, - - /** * Output maps in an "introspected" format, where the name of each item * is the map key (rather than "data"), and the "key" attribute is omitted. * If any key is not a valid XML identifier, the converter will throw. @@ -57,6 +46,14 @@ SEQUENCE_NAMED_BY_PARENT, /** + * Outputs values using formats defined by XML Schema, rather than Java's + * <code>String.valueOf()</code> method. Note that these formats are not + * flagged in the element, so sender and receiver will have to agree on + * the format. + */ + XSD_FORMAT, + + /** * Add null values into the tree, as an element without content, with the * attribute <code>xsi:nil</code> set to "true". If not present, null * values are ignored, and not added to DOM tree. @@ -64,10 +61,13 @@ XSI_NIL, /** - * Outputs values using formats defined by XML Schema, rather than Java's - * <code>String.valueOf()</code> method. Note that these formats are not - * flagged in the element, so sender and receiver will have to agree on - * the format. + * Will add an <code>xsi:type</code> attribute to each element. For values + * covered by the XML Schema simple types, this attribute's value will be + * "<code>xsd:TYPE</code>", where TYPE is the XSD type name. For complex + * types, this attribute's value will be "<code>java:TYPE</code>", where + * TYPE is the fully-qualified classname. + * <p> + * <em>This option implies {@link #XSD_FORMAT} for simple types</em>. */ - XSD_FORMAT + XSI_TYPE } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlAppenders.java 2009-09-23 21:25:10 UTC (rev 153) @@ -72,7 +72,7 @@ { Element root = DomUtil.newDocument("root"); - Appender appender = new BasicAppender(root, useOptions(Bean2XmlOptions.ADD_XSI_TYPE)); + Appender appender = new BasicAppender(root, useOptions(Bean2XmlOptions.XSI_TYPE)); Element child = appender.appendValue("foo", "bar", "baz"); assertNull(child.getNamespaceURI()); @@ -128,7 +128,7 @@ { Element root = DomUtil.newDocument("root"); - Appender appender = new BasicAppender(root, useOptions(Bean2XmlOptions.ADD_XSI_TYPE)); + Appender appender = new BasicAppender(root, useOptions(Bean2XmlOptions.XSI_TYPE)); Element child0 = appender.appendContainer("foo", "bar"); Element child1 = appender.appendContainer("argle", "bargle"); @@ -297,7 +297,7 @@ { Element root = DomUtil.newDocument("root"); - Appender appender = new DirectAppender(root, useOptions(Bean2XmlOptions.ADD_XSI_TYPE)); + Appender appender = new DirectAppender(root, useOptions(Bean2XmlOptions.XSI_TYPE)); Element child = appender.appendValue("foo", "bar", "baz"); assertSame(root, child); @@ -361,7 +361,7 @@ { Element root = DomUtil.newDocument("root"); - Appender appender = new DirectAppender(root, useOptions(Bean2XmlOptions.ADD_XSI_TYPE)); + Appender appender = new DirectAppender(root, useOptions(Bean2XmlOptions.XSI_TYPE)); Element child0 = appender.appendContainer("foo", "bar"); assertSame(root, child0); Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 21:25:10 UTC (rev 153) @@ -142,7 +142,7 @@ public void testConvertPrimitivesWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); for (int idx = 0 ; idx < PRIMITIVE_VALUES.length ; idx++) { PrimitiveValue value = PRIMITIVE_VALUES[idx]; @@ -198,7 +198,7 @@ public void testConvertArrayWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); Object[] data = new Object[] { Integer.valueOf(1), new BigDecimal("2"), "3" }; Element root = driver.convert(data, "test"); @@ -297,7 +297,7 @@ public void testConvertListWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); List<String> data = Arrays.asList("foo", "bar", "baz"); @@ -409,7 +409,7 @@ public void testConvertSetWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); // TreeSet will order output Set<String> data = new TreeSet<String>(); @@ -481,7 +481,7 @@ public void testConvertMapDefaultWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); // TreeMap means that the data will be re-ordered Map<String,Integer> data = new TreeMap<String,Integer>(); @@ -506,7 +506,7 @@ public void testConvertMapIntrospectWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.INTROSPECT_MAPS, Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.INTROSPECT_MAPS, Bean2XmlOptions.XSI_TYPE); // TreeMap means that the data will be re-ordered Map<String,Integer> data = new TreeMap<String,Integer>(); @@ -560,7 +560,7 @@ public void testConvertSimpleBeanWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); SimpleBean bean = new SimpleBean("zippy", 123, new BigDecimal("456.78"), true); Element root = driver.convert(bean, "test"); @@ -608,7 +608,7 @@ public void testConvertSimpleBeanXsiNilAndXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_NIL, Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_NIL, Bean2XmlOptions.XSI_TYPE); SimpleBean bean = new SimpleBean(null, 123, null, true); Element root = driver.convert(bean, "test"); @@ -624,7 +624,7 @@ public void testConvertBeanArrayWithXsiType() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.XSI_TYPE); SimpleBean bean1 = new SimpleBean("foo", 123, new BigDecimal("456.789"), true); SimpleBean bean2 = new SimpleBean("bar", 456, new BigDecimal("0.0"), false); Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java 2009-09-23 18:58:50 UTC (rev 152) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java 2009-09-23 21:25:10 UTC (rev 153) @@ -202,7 +202,7 @@ List<Integer> data = Arrays.asList(1, 2, 3); assertTrue(data.get(0) instanceof Integer); - Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.ADD_XSI_TYPE); + Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.XSI_TYPE); // System.out.println(OutputUtil.compactString(dom)); List<?> result = BeanConverter.convertToJava(dom, List.class); @@ -306,7 +306,7 @@ { SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); - Document valid = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.ADD_XSI_TYPE); + Document valid = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.XSI_TYPE); // System.out.println(OutputUtil.compactString(valid)); SimpleBean result = BeanConverter.convertToJava(valid, SimpleBean.class, Xml2BeanOptions.REQUIRE_XSI_TYPE); @@ -327,7 +327,7 @@ SimpleBean bean2 = new SimpleBean("zyx", 987, null, false); List<SimpleBean> data = Arrays.asList(bean1, bean2); - Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.ADD_XSI_TYPE); + Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.XSI_TYPE); // System.out.println(OutputUtil.compactString(dom)); List<SimpleBean> result = BeanConverter.convertToJava(dom, List.class); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 18:59:02
|
Revision: 152 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=152&view=rev Author: kdgregory Date: 2009-09-23 18:58:50 +0000 (Wed, 23 Sep 2009) Log Message: ----------- Sequence conversion: indexes are optional, child elements may be named after parent Tests: minor renames Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 15:19:55 UTC (rev 151) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-23 18:58:50 UTC (rev 152) @@ -156,19 +156,26 @@ public static class IndexedAppender extends BasicAppender { - int _index = 0; + private int _index = 0; + private String _elementName = ConversionStrings.EL_COLLECTION_ITEM; public IndexedAppender(Element parent, EnumSet<Bean2XmlOptions> options) { super(parent, options); + if (options.contains(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT)) + { + _elementName = DomUtil.getLocalName(parent); + if (_elementName.endsWith("s") || _elementName.endsWith("S")) + _elementName = _elementName.substring(0, _elementName.length() - 1); + } } @Override public Element appendValue(String name, String type, String value) { - Element child = super.appendValue(name, type, value); - if (child != null) + Element child = super.appendValue(_elementName, type, value); + if ((child != null) && isOptionSet(Bean2XmlOptions.SEQUENCE_INDEXES)) child.setAttribute(ConversionStrings.AT_ARRAY_INDEX, String.valueOf(_index++)); return child; } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 15:19:55 UTC (rev 151) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlOptions.java 2009-09-23 18:58:50 UTC (rev 152) @@ -40,6 +40,23 @@ INTROSPECT_MAPS, /** + * Will add an <code>index</code> attribute to the child elements of + * sequences (arrays, lists, sets); the value of this attribute is the + * element's position in the sequence (numbered from 0). This index is + * not terribly useful, so is no longer default behavior. + */ + SEQUENCE_INDEXES, + + /** + * Sequences (arrays, lists, sets) will name their elements according to + * the parent element, with any trailing "s" removed. For example, if the + * parent is named "products", each child will be named "product", rather + * than the default "data". If the parent is named "foo", each child will + * also be named "foo" (since there's no "s" to remove). + */ + SEQUENCE_NAMED_BY_PARENT, + + /** * Add null values into the tree, as an element without content, with the * attribute <code>xsi:nil</code> set to "true". If not present, null * values are ignored, and not added to DOM tree. Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 15:19:55 UTC (rev 151) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java 2009-09-23 18:58:50 UTC (rev 152) @@ -15,7 +15,6 @@ package net.sf.practicalxml.converter.bean; import java.math.BigDecimal; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -171,17 +170,37 @@ assertNameTypeValue("child 2", children.get(1), "data", "", "2"); assertNameTypeValue("child 3", children.get(2), "data", "", "3"); + assertEquals("", children.get(0).getAttribute("index")); + assertEquals("", children.get(1).getAttribute("index")); + assertEquals("", children.get(2).getAttribute("index")); + } + + + public void testConvertArrayWithSequenceNumbers() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_INDEXES); + + int[] data = new int[] { 1, 2, 3 }; + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + assertNameTypeValue("child 1", children.get(0), "data", "", "1"); + assertNameTypeValue("child 2", children.get(1), "data", "", "2"); + assertNameTypeValue("child 3", children.get(2), "data", "", "3"); + assertEquals("0", children.get(0).getAttribute("index")); assertEquals("1", children.get(1).getAttribute("index")); assertEquals("2", children.get(2).getAttribute("index")); } - public void testConvertPrimitiveArrayWithXsiType() throws Exception + public void testConvertArrayWithXsiType() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); - int[] data = new int[] { 1, 2, 3 }; + Object[] data = new Object[] { Integer.valueOf(1), new BigDecimal("2"), "3" }; Element root = driver.convert(data, "test"); // System.out.println(OutputUtil.compactString(root.getOwnerDocument())); @@ -191,21 +210,97 @@ assertEquals("child count", 3, children.size()); assertNameTypeValue("child 1", children.get(0), "data", "xsd:int", "1"); + assertNameTypeValue("child 2", children.get(1), "data", "xsd:decimal", "2"); + assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "3"); + } + + + public void testConvertArrayWithSimpleParentName() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); + + String[] data = new String[] {"foo", "bar", "baz"}; + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "test", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "test", "", "baz"); + } + + + public void testConvertArrayWithDepluralizedParentName() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); + + String[] data = new String[] {"foo", "bar", "baz"}; + + Element root = driver.convert(data, "tests"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "test", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "test", "", "baz"); + } + + + public void testConvertListDefault() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(); + + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "data", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "data", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "data", "", "baz"); + + assertEquals("", children.get(0).getAttribute("index")); + assertEquals("", children.get(1).getAttribute("index")); + assertEquals("", children.get(2).getAttribute("index")); + } + + + public void testConvertListWithSequenceNumbers() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_INDEXES); + + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "data", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "data", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "data", "", "baz"); + assertEquals("0", children.get(0).getAttribute("index")); - - assertNameTypeValue("child 2", children.get(1), "data", "xsd:int", "2"); assertEquals("1", children.get(1).getAttribute("index")); - - assertNameTypeValue("child 3", children.get(2), "data", "xsd:int", "3"); assertEquals("2", children.get(2).getAttribute("index")); } - public void testConvertStringArrayWithXsiType() throws Exception + public void testConvertListWithXsiType() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); - String[] data = new String[] { "foo", "bar", "baz" }; + List<String> data = Arrays.asList("foo", "bar", "baz"); + Element root = driver.convert(data, "test"); // System.out.println(OutputUtil.compactString(root.getOwnerDocument())); @@ -215,21 +310,57 @@ assertEquals("child count", 3, children.size()); assertNameTypeValue("child 1", children.get(0), "data", "xsd:string", "foo"); - assertEquals("0", children.get(0).getAttribute("index")); - assertNameTypeValue("child 2", children.get(1), "data", "xsd:string", "bar"); - assertEquals("1", children.get(1).getAttribute("index")); + assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "baz"); - assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "baz"); - assertEquals("2", children.get(2).getAttribute("index")); + assertEquals("", children.get(0).getAttribute("index")); + assertEquals("", children.get(1).getAttribute("index")); + assertEquals("", children.get(2).getAttribute("index")); } - public void testConvertStringListWithXsiType() throws Exception + public void testConvertListWithSimpleParentName() throws Exception { - Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); - List<String> data = new ArrayList<String>(); + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "test", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "test", "", "baz"); + } + + + public void testConvertListWithDepluralizedParentName() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); + + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Element root = driver.convert(data, "tests"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "foo"); + assertNameTypeValue("child 2", children.get(1), "test", "", "bar"); + assertNameTypeValue("child 3", children.get(2), "test", "", "baz"); + } + + + public void testConvertSetDefault() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(); + + // TreeSet will order output + Set<String> data = new TreeSet<String>(); data.add("foo"); data.add("bar"); data.add("baz"); @@ -237,27 +368,50 @@ Element root = driver.convert(data, "test"); // System.out.println(OutputUtil.compactString(root.getOwnerDocument())); - assertJavaXsiType("root", root, data); + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + assertNameTypeValue("child 1", children.get(0), "data", "", "bar"); + assertNameTypeValue("child 2", children.get(1), "data", "", "baz"); + assertNameTypeValue("child 3", children.get(2), "data", "", "foo"); + + assertEquals("", children.get(0).getAttribute("index")); + assertEquals("", children.get(1).getAttribute("index")); + assertEquals("", children.get(2).getAttribute("index")); + } + + + public void testConvertSetWithSequenceNumbers() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_INDEXES); + + // TreeSet will order output + Set<String> data = new TreeSet<String>(); + data.add("foo"); + data.add("bar"); + data.add("baz"); + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + List<Element> children = DomUtil.getChildren(root); assertEquals("child count", 3, children.size()); - assertNameTypeValue("child 1", children.get(0), "data", "xsd:string", "foo"); + assertNameTypeValue("child 1", children.get(0), "data", "", "bar"); + assertNameTypeValue("child 2", children.get(1), "data", "", "baz"); + assertNameTypeValue("child 3", children.get(2), "data", "", "foo"); + assertEquals("0", children.get(0).getAttribute("index")); - - assertNameTypeValue("child 2", children.get(1), "data", "xsd:string", "bar"); assertEquals("1", children.get(1).getAttribute("index")); - - assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "baz"); assertEquals("2", children.get(2).getAttribute("index")); } - public void testConvertStringSetWithXsiType() throws Exception + public void testConvertSetWithXsiType() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); - // TreeSet means that the data will be re-ordered + // TreeSet will order output Set<String> data = new TreeSet<String>(); data.add("foo"); data.add("bar"); @@ -272,16 +426,59 @@ assertEquals("child count", 3, children.size()); assertNameTypeValue("child 1", children.get(0), "data", "xsd:string", "bar"); - assertEquals("0", children.get(0).getAttribute("index")); - assertNameTypeValue("child 2", children.get(1), "data", "xsd:string", "baz"); - assertEquals("1", children.get(1).getAttribute("index")); + assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "foo"); - assertNameTypeValue("child 3", children.get(2), "data", "xsd:string", "foo"); - assertEquals("2", children.get(2).getAttribute("index")); + assertEquals("", children.get(0).getAttribute("index")); + assertEquals("", children.get(1).getAttribute("index")); + assertEquals("", children.get(2).getAttribute("index")); } + public void testConvertSetWithSimpleParentName() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); + + // TreeSet will order output + Set<String> data = new TreeSet<String>(); + data.add("foo"); + data.add("bar"); + data.add("baz"); + + Element root = driver.convert(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "bar"); + assertNameTypeValue("child 2", children.get(1), "test", "", "baz"); + assertNameTypeValue("child 3", children.get(2), "test", "", "foo"); + } + + + public void testConvertSetWithDepluralizedParentName() throws Exception + { + Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); + + // TreeSet will order output + Set<String> data = new TreeSet<String>(); + data.add("foo"); + data.add("bar"); + data.add("baz"); + + Element root = driver.convert(data, "tests"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<Element> children = DomUtil.getChildren(root); + assertEquals("child count", 3, children.size()); + + assertNameTypeValue("child 1", children.get(0), "test", "", "bar"); + assertNameTypeValue("child 2", children.get(1), "test", "", "baz"); + assertNameTypeValue("child 3", children.get(2), "test", "", "foo"); + } + + public void testConvertMapDefaultWithXsiType() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.ADD_XSI_TYPE); @@ -332,7 +529,7 @@ } - public void testConvertMapIntrospectWithInvalidKey() throws Exception + public void testFailMapIntrospectWithInvalidKey() throws Exception { Bean2XmlConverter driver = new Bean2XmlConverter(Bean2XmlOptions.INTROSPECT_MAPS); @@ -452,7 +649,7 @@ } - public void testDispatchCompoundBeanDefault() throws Exception + public void testConvertCompoundBeanDefault() throws Exception { // at this point, I'm convinced the type output works, so we'll do default // output and then use XPath for all assertions ... but note nulls in data @@ -474,10 +671,6 @@ DomAsserts.assertEquals("2", root, "/test/primArray/data[2]"); DomAsserts.assertEquals("3", root, "/test/primArray/data[3]"); - DomAsserts.assertEquals("0", root, "/test/primArray/data[1]/@index"); - DomAsserts.assertEquals("1", root, "/test/primArray/data[2]/@index"); - DomAsserts.assertEquals("2", root, "/test/primArray/data[3]/@index"); - DomAsserts.assertEquals("foo", root, "/test/stringList/data[1]"); DomAsserts.assertEquals("baz", root, "/test/stringList/data[2]"); } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java 2009-09-23 15:19:55 UTC (rev 151) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java 2009-09-23 18:58:50 UTC (rev 152) @@ -144,7 +144,7 @@ } - public void testConvertNullFailureRequireXsiNil() throws Exception + public void testFailNullRequireXsiNil() throws Exception { Document dom = BeanConverter.convertToXml(null, "test"); // System.out.println(OutputUtil.compactString(dom)); @@ -181,7 +181,7 @@ // demonstrates that the list will be read as List<String> even though // it was written as List<Integer> - public void testIntegerListDefault() throws Exception + public void testListDefault() throws Exception { List<Integer> data = Arrays.asList(1, 2, 3); assert(data.get(0) instanceof Integer); @@ -195,11 +195,12 @@ } - // demonstrates that you don't need to require xsi:type to use it - public void testIntegerListWithXsiType() throws Exception + // demonstrates that xsi:type will be used when available, even if + // not required -- otherwise we'd translate back as String + public void testListWithXsiType() throws Exception { List<Integer> data = Arrays.asList(1, 2, 3); - assert(data.get(0) instanceof Integer); + assertTrue(data.get(0) instanceof Integer); Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.ADD_XSI_TYPE); // System.out.println(OutputUtil.compactString(dom)); @@ -209,8 +210,32 @@ } + public void testListWithSequenceNumbers() throws Exception + { + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.SEQUENCE_INDEXES); +// System.out.println(OutputUtil.compactString(dom)); + + List<?> result = BeanConverter.convertToJava(dom, List.class); + assertEquals(data, result); + } + + + public void testListWithElementsNamedByParent() throws Exception + { + List<String> data = Arrays.asList("foo", "bar", "baz"); + + Document dom = BeanConverter.convertToXml(data, "test", Bean2XmlOptions.SEQUENCE_NAMED_BY_PARENT); +// System.out.println(OutputUtil.compactString(dom)); + + List<?> result = BeanConverter.convertToJava(dom, List.class); + assertEquals(data, result); + } + + // demonstrates that the caller drives the inbound conversion - public void testConvertListToSortedSet() throws Exception + public void testListToSortedSet() throws Exception { List<String> data = Arrays.asList("foo", "bar", "baz", "bar"); @@ -277,7 +302,7 @@ } - public void testSimpleBeanRequireXsiType() throws Exception + public void testFailSimpleBeanRequireXsiType() throws Exception { SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 15:20:04
|
Revision: 151 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=151&view=rev Author: kdgregory Date: 2009-09-23 15:19:55 +0000 (Wed, 23 Sep 2009) Log Message: ----------- AbstractConversionTestCase wasn't marked abstract, was causing test suite to fail Modified Paths: -------------- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java 2009-09-23 15:03:04 UTC (rev 150) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java 2009-09-23 15:19:55 UTC (rev 151) @@ -26,7 +26,7 @@ /** * A place to put common code for the conversion tests. */ -public class AbstractConversionTestCase +public abstract class AbstractConversionTestCase extends AbstractTestCase { public AbstractConversionTestCase(String testName) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-23 15:03:12
|
Revision: 150 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=150&view=rev Author: kdgregory Date: 2009-09-23 15:03:04 +0000 (Wed, 23 Sep 2009) Log Message: ----------- remove println()s from testcases Modified Paths: -------------- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java 2009-09-22 21:13:56 UTC (rev 149) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java 2009-09-23 15:03:04 UTC (rev 150) @@ -20,8 +20,6 @@ import org.w3c.dom.Element; import net.sf.practicalxml.DomUtil; -import net.sf.practicalxml.OutputUtil; -import net.sf.practicalxml.XmlUtil; import net.sf.practicalxml.converter.AbstractConversionTestCase; import net.sf.practicalxml.converter.JsonConverter; @@ -95,7 +93,6 @@ Element dst = JsonConverter.convertToXml(json, "test") .getDocumentElement(); - System.out.println(json); assertChildren(src, dst); } @@ -139,7 +136,6 @@ Element dst = JsonConverter.convertToXml(json, "test") .getDocumentElement(); - System.out.println(json); assertChildren(src, dst); assertChildren((Element)src.getFirstChild(), (Element)dst.getFirstChild()); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 21:14:04
|
Revision: 149 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=149&view=rev Author: kdgregory Date: 2009-09-22 21:13:56 +0000 (Tue, 22 Sep 2009) Log Message: ----------- add JsonConverter as facade for Xml2JsonConverter / Json2XmlConverter Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/JsonConverter.java 2009-09-22 21:13:56 UTC (rev 149) @@ -0,0 +1,100 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import net.sf.practicalxml.converter.json.Json2XmlConverter; +import net.sf.practicalxml.converter.json.Json2XmlOptions; +import net.sf.practicalxml.converter.json.Xml2JsonConverter; +import net.sf.practicalxml.converter.json.Xml2JsonOptions; + + +/** + * Converts between XML DOMs and JSON (Javascript Object Notation) strings. + * See the {@link net.sf.practicalxml.converter.json package docs} for + * details. + * <p> + * This class provides static facade methods for + * {@link net.sf.practicalxml.converter.json.Json2XmlConverter} and + * {@link net.sf.practicalxml.converter.json.Xml2JsonConverter}. If static + * methods and throwaway objects offend you then use those classes directly. + */ +public class JsonConverter +{ + /** + * Creates a new DOM document from the passed JSON string, in which all + * elements are members of the specified namespace and will inherit the + * root's prefix (if any). + * + * @param json The source object. + * @param nsUri The namespace of the root element. This will be + * inherited by all child elements. + * @param rootName The qualified name given to the root element of the + * generated document. If a qualified name, all child + * elements will inherit its prefix. + * @param options Conversion options. + */ + public static Document convertToXml( + String json, String nsUri, String rootName, Json2XmlOptions... options) + { + return new Json2XmlConverter(json, options).convert().getOwnerDocument(); + } + + + /** + * Creates a new DOM document from the passed bean, without namespace. + * + * @param json The source object. + * @param rootName The name given to the root element of the produced + * document. + * @param options Conversion options. + */ + public static Document convertToXml( + String json, String rootName, Json2XmlOptions... options) + { + return new Json2XmlConverter(json, options).convert().getOwnerDocument(); + } + + + /** + * Creates a new JSON string from the root of the passed <code>Document + * </code>. + * + * @param dom The source document. + * @param options Conversion options. + */ + public static String convertToJson(Document dom, Xml2JsonOptions... options) + { + return convertToJson(dom.getDocumentElement(), options); + } + + + /** + * Creates a new JSON string from the the passed <code>Element</code>. + * This is useful when a DOM contains a tree of objects and you just + * want to convert one of them. + * + * @param dom The source element -- this may or may not be the + * root element of its document. + * @param options Conversion options. + */ + public static String convertToJson(Element root, Xml2JsonOptions... options) + { + return new Xml2JsonConverter().convert(root, new StringBuilder(256)) + .toString(); + } +} Added: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java (rev 0) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonConverter.java 2009-09-22 21:13:56 UTC (rev 149) @@ -0,0 +1,164 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter.json; + +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Element; + +import net.sf.practicalxml.DomUtil; +import net.sf.practicalxml.OutputUtil; +import net.sf.practicalxml.XmlUtil; +import net.sf.practicalxml.converter.AbstractConversionTestCase; +import net.sf.practicalxml.converter.JsonConverter; + +import static net.sf.practicalxml.builder.XmlBuilder.*; + + +/** + * These testcases all try "out and back" conversions, starting from XML. + */ +public class TestJsonConverter +extends AbstractConversionTestCase +{ + public TestJsonConverter(String testName) + { + super(testName); + } + + +//---------------------------------------------------------------------------- +// Support Code +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// Assertions +//---------------------------------------------------------------------------- + + /** + * Asserts that the two passed elements have the same number of children, + * that those children have the same local name (in document order), and + * that they have the same text values. + * <p> + * This should probably move into <code>DomAsserts</code> + */ + private void assertChildren(Element expected, Element actual) + { + List<Element> expectedChildren = DomUtil.getChildren(expected); + List<Element> actualChildren = DomUtil.getChildren(actual); + + assertEquals("child count", expectedChildren.size(), actualChildren.size()); + + int idx = 0; + Iterator<Element> expectedItx = expectedChildren.iterator(); + Iterator<Element> actualItx = actualChildren.iterator(); + while (expectedItx.hasNext()) + { + Element expectedElement = expectedItx.next(); + Element actualElement = actualItx.next(); + assertEquals("element " + idx + " local name", + DomUtil.getLocalName(expectedElement), + DomUtil.getLocalName(actualElement)); + assertEquals("element " + idx + " content", + DomUtil.getText(expectedElement), + DomUtil.getText(actualElement)); + assertEquals("element " + idx + " child count", + DomUtil.getChildren(expectedElement).size(), + DomUtil.getChildren(actualElement).size()); + } + } + + +//---------------------------------------------------------------------------- +// Test Cases +//---------------------------------------------------------------------------- + + public void testEmptyDocument() throws Exception + { + Element src = element("data") + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src); + Element dst = JsonConverter.convertToXml(json, "test") + .getDocumentElement(); + + System.out.println(json); + assertChildren(src, dst); + } + + + public void testTwoChildrenOfRoot() throws Exception + { + Element src = element("data", + element("foo", text("bar")), + element("argle", text("bargle"))) + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src); + Element dst = JsonConverter.convertToXml(json, "test") + .getDocumentElement(); + + assertChildren(src, dst); + } + + + public void testRepeatedElements() throws Exception + { + Element src = element("data", + element("foo", text("bar")), + element("foo", text("baz"))) + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src); + Element dst = JsonConverter.convertToXml(json, "test", Json2XmlOptions.ARRAYS_AS_REPEATED_ELEMENTS) + .getDocumentElement(); + + assertChildren(src, dst); + } + + + public void testNestedElements() throws Exception + { + Element src = element("data", + element("foo", + element("argle", text("bargle"))), + element("bar", text("baz"))) + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src); + Element dst = JsonConverter.convertToXml(json, "test") + .getDocumentElement(); + + System.out.println(json); + assertChildren(src, dst); + assertChildren((Element)src.getFirstChild(), (Element)dst.getFirstChild()); + } + + + public void testNamespaces() throws Exception + { + Element src = element("urn:foo", "argle:bargle", + element("urn:bar", "foo", + element("argle", text("bargle"))), + element("bar", text("baz"))) + .toDOM().getDocumentElement(); + String json = JsonConverter.convertToJson(src); + Element dst = JsonConverter.convertToXml(json, "test") + .getDocumentElement(); + + assertNull(dst.getNamespaceURI()); + assertNull(dst.getPrefix()); + assertChildren(src, dst); + assertChildren((Element)src.getFirstChild(), (Element)dst.getFirstChild()); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 21:07:12
|
Revision: 148 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=148&view=rev Author: kdgregory Date: 2009-09-22 21:07:06 +0000 (Tue, 22 Sep 2009) Log Message: ----------- support namespaces for JSON->XML Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 20:01:27 UTC (rev 147) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 21:07:06 UTC (rev 148) @@ -61,7 +61,30 @@ */ public Element convert() { - Element root = DomUtil.newDocument("data"); + return convert("data"); + } + + + /** + * Creates a new XML <code>Document</code> from the passed JSON string + * (which must contain an object definition and nothing else). The root + * element will have the given name, but no namespace. + */ + public Element convert(String localName) + { + return convert(null, localName); + } + + + /** + * Creates a new XML <code>Document</code> from the passed JSON string + * (which must contain an object definition and nothing else). The root + * element will have the given name and namespace, and all child elements + * will inherit the namespace (and prefix, if it exists). + */ + public Element convert(String nsUri, String qname) + { + Element root = DomUtil.newDocument(nsUri, qname); parse(root); return root; } @@ -155,7 +178,7 @@ while (true) { - Element child = DomUtil.appendChild(parent, childName); + Element child = appendChild(parent, childName); next = valueDispatch(next, child); if (atEndOfSequence(next, "]", true)) return; @@ -284,7 +307,7 @@ throw new ConversionException(commonExceptionText("invalid token")); try { - return DomUtil.appendChild(parent, name); + return DomUtil.appendChildInheritNamespace(parent, name); } catch (Exception e) { Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-22 20:01:27 UTC (rev 147) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-22 21:07:06 UTC (rev 148) @@ -502,4 +502,28 @@ } } + + public void testConvertWithNamespace() throws Exception + { + String src = "{foo: {bar: 123}}"; + + Element root = new Json2XmlConverter(src).convert("urn:argle", "argle:bargle"); + assertEquals("urn:argle", root.getNamespaceURI()); + assertEquals("argle", root.getPrefix()); + assertEquals("bargle", root.getLocalName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("urn:argle", child.getNamespaceURI()); + assertEquals("argle", child.getPrefix()); + assertEquals("foo", child.getLocalName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element grandchild = (Element)child.getFirstChild(); + assertEquals("urn:argle", grandchild.getNamespaceURI()); + assertEquals("argle", grandchild.getPrefix()); + assertEquals("bar", grandchild.getLocalName()); + assertEquals("123", DomUtil.getText(grandchild)); + assertEquals(0, DomUtil.getChildren(grandchild).size()); + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 20:01:35
|
Revision: 147 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=147&view=rev Author: kdgregory Date: 2009-09-22 20:01:27 +0000 (Tue, 22 Sep 2009) Log Message: ----------- remove Xml2JsonOptions.USE_XSI_TYPE Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-22 19:21:25 UTC (rev 146) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-22 20:01:27 UTC (rev 147) @@ -20,10 +20,5 @@ */ public enum Xml2JsonOptions { - /** - * Examines the XML element for an <code>xsi:type</code> attribute; if - * present, will only quote-delimit character data (<code>xsd:string</code>, - * <code>xsd:char</code>, and the like). - */ - USE_XSI_TYPE + // nothing here right now } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html 2009-09-22 19:21:25 UTC (rev 146) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html 2009-09-22 20:01:27 UTC (rev 147) @@ -22,8 +22,7 @@ <dd> JSON supports numbers and boolean literals in addition to quote-delimited strings. The JSON to XML conversion will handle these values transparently. The default XML to JSON conversion writes all content as quote-delimited - strings, but there is a conversion option to recognize a limited set of - non-string elements based on the <code>xsi:type</code> attribute. + strings (although this may change). <dt> Arrays, XML to JSON <dd> XML does not have a defined array construct, but may repeat elements; JSON has a defined array construct, and repeated elements will overwrite the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 19:21:38
|
Revision: 146 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=146&view=rev Author: kdgregory Date: 2009-09-22 19:21:25 +0000 (Tue, 22 Sep 2009) Log Message: ----------- testcase refactoring Modified Paths: -------------- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/AbstractBeanConverterTestCase.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanConverter.java Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java 2009-09-22 19:06:46 UTC (rev 145) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractConversionTestCase.java 2009-09-22 19:21:25 UTC (rev 146) @@ -14,6 +14,12 @@ package net.sf.practicalxml.converter; +import static net.sf.practicalxml.builder.XmlBuilder.attribute; + +import javax.xml.XMLConstants; + +import org.w3c.dom.Element; + import net.sf.practicalxml.AbstractTestCase; @@ -32,8 +38,45 @@ // Support Code //---------------------------------------------------------------------------- + protected static net.sf.practicalxml.builder.Node xsiType(String typeName) + { + return attribute(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, + "type", + typeName); + } + + protected static net.sf.practicalxml.builder.Node xsiNil(boolean isNil) + { + return attribute(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, + "nil", + isNil ? "true" : "false"); + } + + //---------------------------------------------------------------------------- // Assertions //---------------------------------------------------------------------------- + + protected void assertXsiType(String message, Element elem, String expectedType) + { + String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type"); + assertEquals(message, expectedType, attr); + } + + + protected void assertXsiNil(Element elem, boolean expected) + { + String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); + boolean isNil = attr.equals("true"); + assertEquals("xsi:nil (\"" + attr + "\")", expected, isNil); + } + + + protected void assertXsiNil(String message, Element elem, boolean expected) + { + String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); + boolean isNil = attr.equals("true"); + assertEquals(message, expected, isNil); + } } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/AbstractBeanConverterTestCase.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/AbstractBeanConverterTestCase.java 2009-09-22 19:06:46 UTC (rev 145) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/AbstractBeanConverterTestCase.java 2009-09-22 19:21:25 UTC (rev 146) @@ -20,8 +20,6 @@ import java.util.Date; import java.util.List; -import javax.xml.XMLConstants; - import org.w3c.dom.Element; import junit.framework.Assert; @@ -222,27 +220,4 @@ { assertEquals(message, expectedValue, DomUtil.getText(elem)); } - - - protected void assertXsiType(String message, Element elem, String expectedType) - { - String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type"); - assertEquals(message, expectedType, attr); - } - - - protected void assertXsiNil(Element elem, boolean expected) - { - String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); - boolean isNil = attr.equals("true"); - assertEquals("xsi:nil (\"" + attr + "\")", expected, isNil); - } - - - protected void assertXsiNil(String message, Element elem, boolean expected) - { - String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); - boolean isNil = attr.equals("true"); - assertEquals(message, expected, isNil); - } } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanConverter.java 2009-09-22 19:06:46 UTC (rev 145) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanConverter.java 2009-09-22 19:21:25 UTC (rev 146) @@ -24,7 +24,6 @@ import java.util.SortedMap; import java.util.SortedSet; -import javax.xml.XMLConstants; import org.w3c.dom.Element; import net.sf.practicalxml.converter.ConversionException; @@ -55,22 +54,6 @@ } - private static net.sf.practicalxml.builder.Node xsiType(String typeName) - { - return attribute(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, - "type", - typeName); - } - - - private static net.sf.practicalxml.builder.Node xsiNil(boolean isNil) - { - return attribute(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, - "nil", - isNil ? "true" : "false"); - } - - private static void assertConversionFailure( String message, Xml2BeanConverter driver, Element elem, Class<?> klass) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 19:07:02
|
Revision: 145 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=145&view=rev Author: kdgregory Date: 2009-09-22 19:06:46 +0000 (Tue, 22 Sep 2009) Log Message: ----------- implement Json2XmlOptions.ARRAYS_AS_REPEATED_ELEMENTS Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 17:32:02 UTC (rev 144) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 19:06:46 UTC (rev 145) @@ -17,6 +17,7 @@ import java.util.EnumSet; import org.w3c.dom.Element; +import org.w3c.dom.Node; import net.sf.practicalxml.DomUtil; import net.sf.practicalxml.converter.ConversionException; @@ -72,15 +73,22 @@ /** * Top-level parser entry: expects the string to be a single object - * definition, without anything before or after the outer brace pair. + * or array definition, without anything before or after the outer + * brace/bracket pair. */ private void parse(Element parent) { - expect("{"); - parseObject(parent); + String first = nextToken(); + if (first.equals("{")) + parseObject(parent); + else if (first.equals("[")) + parseArray(parent); + else + throw new ConversionException(commonExceptionText( + "unexpected content start of line")); if (nextToken().length() > 0) throw new ConversionException(commonExceptionText( - "unexpected content after closing brace")); + "unexpected content at end of line")); } @@ -125,13 +133,29 @@ private void parseArray(Element parent) { + String childName = "data"; + if (_options.contains(Json2XmlOptions.ARRAYS_AS_REPEATED_ELEMENTS)) + { + // we come in here with the assumption that array elements will + // be created as children of "parent" ... but now we learn that + // they're actually siblings, and the passed parent will disappear + // ... so here's an ugly little hack to make that happen + Node realParent = parent.getParentNode(); + if (!(realParent instanceof Element)) + throw new ConversionException(commonExceptionText( + "cannot convert top-level array as repeated elements")); + childName = DomUtil.getLocalName(parent); + realParent.removeChild(parent); + parent = (Element)realParent; + } + String next = nextToken(); if (atEndOfSequence(next, "]", false)) return; while (true) { - Element child = DomUtil.appendChild(parent, "data"); + Element child = DomUtil.appendChild(parent, childName); next = valueDispatch(next, child); if (atEndOfSequence(next, "]", true)) return; Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-22 17:32:02 UTC (rev 144) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-22 19:06:46 UTC (rev 145) @@ -402,6 +402,58 @@ } + public void testConvertTopLevelArray() throws Exception + { + String src = "[123, 456]"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(2, root.getChildNodes().getLength()); + + Element child1 = (Element)root.getFirstChild(); + assertEquals("data", child1.getNodeName()); + assertEquals("123", DomUtil.getText(child1)); + assertEquals(0, DomUtil.getChildren(child1).size()); + + Element child2 = (Element)child1.getNextSibling(); + assertEquals("data", child2.getNodeName()); + assertEquals("456", DomUtil.getText(child2)); + assertEquals(0, DomUtil.getChildren(child2).size()); + } + + + public void testConvertArrayAsRepeatedElements() throws Exception + { + // leading and trailing elements to ensure sibling order + String src = "{foo: \"abc\", bar: [123, 456], baz: \"def\"}"; + + Element root = new Json2XmlConverter(src, Json2XmlOptions.ARRAYS_AS_REPEATED_ELEMENTS) + .convert(); + assertEquals("data", root.getNodeName()); + assertEquals(4, root.getChildNodes().getLength()); + + Element child1 = (Element)root.getFirstChild(); + assertEquals("foo", child1.getNodeName()); + assertEquals("abc", DomUtil.getText(child1)); + assertEquals(0, DomUtil.getChildren(child1).size()); + + Element child2 = (Element)child1.getNextSibling(); + assertEquals("bar", child2.getNodeName()); + assertEquals("123", DomUtil.getText(child2)); + assertEquals(0, DomUtil.getChildren(child2).size()); + + Element child3 = (Element)child2.getNextSibling(); + assertEquals("bar", child3.getNodeName()); + assertEquals("456", DomUtil.getText(child3)); + assertEquals(0, DomUtil.getChildren(child3).size()); + + Element child4 = (Element)child3.getNextSibling(); + assertEquals("baz", child4.getNodeName()); + assertEquals("def", DomUtil.getText(child4)); + assertEquals(0, DomUtil.getChildren(child4).size()); + } + + public void testFailConvertUnterminatedArray() throws Exception { String src = "{foo: [123, 456"; @@ -432,4 +484,22 @@ // success } } + + + public void testFailConvertArrayAsRootUsingRepeatedElements() throws Exception + { + String src = "[123, 456]"; + + try + { + new Json2XmlConverter(src, Json2XmlOptions.ARRAYS_AS_REPEATED_ELEMENTS) + .convert(); + fail("able to create XML with multiple root elements"); + } + catch (ConversionException ee) + { + // success + } + } + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 18:05:30
|
Revision: 144 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=144&view=rev Author: kdgregory Date: 2009-09-22 17:32:02 +0000 (Tue, 22 Sep 2009) Log Message: ----------- xml->json: support arrays Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-22 15:27:06 UTC (rev 143) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-22 17:32:02 UTC (rev 144) @@ -14,9 +14,12 @@ package net.sf.practicalxml.converter.json; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import net.sf.practicalxml.DomUtil; @@ -43,16 +46,24 @@ //---------------------------------------------------------------------------- /** - * Appends the contents of the specified element to an existing buffer. + * Converts the subtree rooted at <code>elem</code> to a JSON string. + */ + public String convert(Element elem) + { + return convert(elem, new StringBuilder(256)).toString(); + } + + + /** + * Converts the subtree rooted at <code>elem</code> to a JSON string, + * appending to an existing buffer. This is useful when building a + * JSON assignment statment (eg: "var x = OBJECT"). + * <p> * Returns the buffer as a convenience. */ public StringBuilder convert(Element elem, StringBuilder buf) { - String text = DomUtil.getText(elem); - if (text != null) - return appendText(text, buf); - else - return appendChildren(elem, buf); + return append(buf, elem); } @@ -60,8 +71,22 @@ // Internals //---------------------------------------------------------------------------- - private StringBuilder appendText(String text, StringBuilder buf) + // yes, this method is just a restatement of convert(Element,StringBuilder) + // I want all the internal appenders named "append". + private StringBuilder append(StringBuilder buf, Element elem) { + List<Element> children = DomUtil.getChildren(elem); + String text = DomUtil.getText(elem); + + if ((children.size() > 0) || (text == null)) + return appendObject(buf, children); + else + return appendText(buf, text); + } + + + private StringBuilder appendText(StringBuilder buf, String text) + { buf.append('"') .append(JsonUtil.escape(text)) .append('"'); @@ -69,20 +94,74 @@ } - private StringBuilder appendChildren(Element elem, StringBuilder buf) + private StringBuilder appendObject(StringBuilder buf, List<Element> children) { + List<String> names = new ArrayList<String>(); + Map<String,List<Element>> arrays = new HashMap<String,List<Element>>(); + Map<String,Element> nonArrays = new HashMap<String,Element>(); + categorizeChildren(children, names, arrays, nonArrays); + buf.append("{"); - List<Element> children = DomUtil.getChildren(elem); - for (Iterator<Element> childItx = children.iterator() ; childItx.hasNext() ; ) + for (Iterator<String> itx = names.iterator() ; itx.hasNext() ; ) { - Element child = childItx.next(); - buf.append(DomUtil.getLocalName(child)) - .append(": "); - convert(child, buf); - if (childItx.hasNext()) + String name = itx.next(); + buf.append(name).append(": "); + if (arrays.containsKey(name)) + appendArray(buf, arrays.get(name)); + else + append(buf, nonArrays.get(name)); + if (itx.hasNext()) buf.append(", "); } buf.append("}"); return buf; } + + + private StringBuilder appendArray(StringBuilder buf, List<Element> values) + { + buf.append("["); + for (Iterator<Element> itx = values.iterator() ; itx.hasNext() ; ) + { + Element child = itx.next(); + append(buf, child); + if (itx.hasNext()) + buf.append(", "); + } + buf.append("]"); + return buf; + } + + + /** + * Examines the children of the passed element and categorizes them as + * "array" or "not array", while tracking the first appearance of the + * element name in document order. + */ + private void categorizeChildren( + List<Element> children, List<String> names, + Map<String,List<Element>> arrays, Map<String,Element> nonArrays) + { + for (Element child : children) + { + String name = DomUtil.getLocalName(child); + if (arrays.containsKey(name)) + { + arrays.get(name).add(child); + } + else if (nonArrays.containsKey(name)) + { + Element prev = nonArrays.remove(name); + List<Element> list = new ArrayList<Element>(2); + list.add(prev); + list.add(child); + arrays.put(name, list); + } + else + { + nonArrays.put(name, child); + names.add(name); + } + } + } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html 2009-09-22 15:27:06 UTC (rev 143) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html 2009-09-22 17:32:02 UTC (rev 144) @@ -2,36 +2,39 @@ <body> This package contains classes to convert JSON (JavaScript Object Notation) -strings (as defined <a href="http://www.json.org/">json.org</a> ) to and +strings (as defined <a href="http://www.json.org/">json.org</a> ) to and from an XML DOM. Although both XML and JSON are textual representations of hierarchical data, there are some peculiarities in the conversion: <dl> <dt> Container Element <dd> Although elements within a JSON object are named, the object itself is - not. XML requires a named root element, so the JSON->XML conversion - creates a root element named "data", and the XML->JSON conversion ignores - the passed root element. + not. XML requires a named root element, so the JSON to XML conversion + creates a root element named "data", and the XML to JSON conversion + ignores the passed root element. <dt> Document Order <dd> In XML, document order is important and may be validated; in JSON, the order of elements within an object is not important. To support arrays - (qv), the XML->JSON conversion intentionally breaks document order. And + the XML to JSON conversion intentionally breaks document order (qv). And as JSON has no intrinsic order, you'll need to explicitly re-arrange the - result of a JSON->XML conversion prior to any validation. + result of a JSON to XML conversion prior to any validation. <dt> Non-String Data <dd> JSON supports numbers and boolean literals in addition to quote-delimited - strings. The JSON->XML conversion will handle these values transparently. - The default XML->JSON conversion writes all content as quote-delimited + strings. The JSON to XML conversion will handle these values transparently. + The default XML to JSON conversion writes all content as quote-delimited strings, but there is a conversion option to recognize a limited set of - non-string elements based on the <code>xsi:type</code> attribute. -<dt> Arrays + non-string elements based on the <code>xsi:type</code> attribute. +<dt> Arrays, XML to JSON <dd> XML does not have a defined array construct, but may repeat elements; JSON has a defined array construct, and repeated elements will overwrite the - former definition. To avoid this problem, the XML->JSON conversion will - identify all repeated elements and create an array construct. The default - JSON->XML conversion creates a parent-children construct (which is more - palatable to subsequent XML->Java conversion), but a conversion option - allows conversion to a repeated element. + former definition. To avoid this problem, the XML to JSON converter will + create a JSON array construct from all siblings with the same localname. +<dt> Arrays, JSON to XML +<dd> By default, arrays are converted into a single parent element, with one + child named "data" for each element of the array; this is similar to the + Java to XML conversion. Optionally, you may convert an array into a series + of repeated elements (siblings), all with the same name. When using this + option, conversion will fail if presented with a top-level JSON array. </dl> </body> Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-22 15:27:06 UTC (rev 143) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-22 17:32:02 UTC (rev 144) @@ -37,9 +37,8 @@ public void convertAndAssert(String expected, ElementNode rootNode) { Element root = rootNode.toDOM().getDocumentElement(); - StringBuilder buf = new Xml2JsonConverter() - .convert(root, new StringBuilder(256)); - assertEquals(expected, buf.toString()); + String json = new Xml2JsonConverter().convert(root); + assertEquals(expected, json); } @@ -86,6 +85,53 @@ } + public void testArray() throws Exception + { + // note that "argle" elements are not adjacent, must become adjacent + convertAndAssert( + "{foo: \"bar\", argle: [\"bargle\", \"wargle\"], baz: \"bar\"}", + element("data", + element("foo", text("bar")), + element("argle", text("bargle")), + element("baz", text("bar")), + element("argle", text("wargle")))); + } + + + public void testArrayWithNestedObject() throws Exception + { + convertAndAssert( + "{foo: \"bar\", argle: [\"bargle\", {foo: \"bar\", bar: \"baz\"}]}", + element("data", + element("foo", text("bar")), + element("argle", text("bargle")), + element("argle", + element("foo", text("bar")), + element("bar", text("baz"))))); + } + + + // this covers documents parsed with "ignorable whitespace" + public void testMixedContentWithWhitespace() throws Exception + { + convertAndAssert( + "{foo: \"bar\"}", + element("data", + text(" "), + element("foo", text("bar")), + text("\n"))); + } + + + public void testWhitespace() throws Exception + { + convertAndAssert( + "{foo: \" \"}", + element("data", + element("foo", text(" ")))); + } + + public void testStringEscaping() throws Exception { convertAndAssert( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 15:27:17
|
Revision: 143 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=143&view=rev Author: kdgregory Date: 2009-09-22 15:27:06 +0000 (Tue, 22 Sep 2009) Log Message: ----------- add conversion options to ctors Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 15:05:25 UTC (rev 142) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-22 15:27:06 UTC (rev 143) @@ -14,6 +14,8 @@ package net.sf.practicalxml.converter.json; +import java.util.EnumSet; + import org.w3c.dom.Element; import net.sf.practicalxml.DomUtil; @@ -33,17 +35,24 @@ */ public class Json2XmlConverter { + private EnumSet<Json2XmlOptions> _options = EnumSet.noneOf(Json2XmlOptions.class); private String _src; // we pull substrings from the base string private int _curPos; // position of current token (start of substring) private int _nextPos; // position of next token (end of substring) - public Json2XmlConverter(String src) + public Json2XmlConverter(String src, Json2XmlOptions... options) { _src = src; + for (Json2XmlOptions option : options) + _options.add(option); } +//---------------------------------------------------------------------------- +// Public Methods +//---------------------------------------------------------------------------- + /** * Creates a new XML <code>Document</code> from the passed JSON string * (which must contain an object definition and nothing else). The root Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-22 15:05:25 UTC (rev 142) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-22 15:27:06 UTC (rev 143) @@ -14,6 +14,7 @@ package net.sf.practicalxml.converter.json; +import java.util.EnumSet; import java.util.Iterator; import java.util.List; @@ -27,6 +28,20 @@ */ public class Xml2JsonConverter { + private EnumSet<Json2XmlOptions> _options = EnumSet.noneOf(Json2XmlOptions.class); + + + public Xml2JsonConverter(Json2XmlOptions... options) + { + for (Json2XmlOptions option : options) + _options.add(option); + } + + +//---------------------------------------------------------------------------- +// Public Methods +//---------------------------------------------------------------------------- + /** * Appends the contents of the specified element to an existing buffer. * Returns the buffer as a convenience. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 15:05:43
|
Revision: 142 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=142&view=rev Author: kdgregory Date: 2009-09-22 15:05:25 +0000 (Tue, 22 Sep 2009) Log Message: ----------- add conversion options, package docs Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlOptions.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlOptions.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlOptions.java 2009-09-22 15:05:25 UTC (rev 142) @@ -0,0 +1,31 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter.json; + + +/** + * Options to control conversion from JSON strings to XML documents. + */ +public enum Json2XmlOptions +{ + /** + * Convert JSON arrays to repeated XML elements with the same name. + * Default behavior is to create a parent-children construct, in which + * the parent has the given element name, while each child is named + * "data" (this approach can be subsequently passed to the XML->Java + * converter). + */ + ARRAYS_AS_REPEATED_ELEMENTS +} Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonOptions.java 2009-09-22 15:05:25 UTC (rev 142) @@ -0,0 +1,29 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter.json; + + +/** + * Options to control conversion from XML documents to JSON strings + */ +public enum Xml2JsonOptions +{ + /** + * Examines the XML element for an <code>xsi:type</code> attribute; if + * present, will only quote-delimit character data (<code>xsd:string</code>, + * <code>xsd:char</code>, and the like). + */ + USE_XSI_TYPE +} Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/package.html 2009-09-22 15:05:25 UTC (rev 142) @@ -0,0 +1,38 @@ +<html> +<body> + +This package contains classes to convert JSON (JavaScript Object Notation) +strings (as defined <a href="http://www.json.org/">json.org</a> ) to and +from an XML DOM. Although both XML and JSON are textual representations of +hierarchical data, there are some peculiarities in the conversion: + +<dl> +<dt> Container Element +<dd> Although elements within a JSON object are named, the object itself is + not. XML requires a named root element, so the JSON->XML conversion + creates a root element named "data", and the XML->JSON conversion ignores + the passed root element. +<dt> Document Order +<dd> In XML, document order is important and may be validated; in JSON, the + order of elements within an object is not important. To support arrays + (qv), the XML->JSON conversion intentionally breaks document order. And + as JSON has no intrinsic order, you'll need to explicitly re-arrange the + result of a JSON->XML conversion prior to any validation. +<dt> Non-String Data +<dd> JSON supports numbers and boolean literals in addition to quote-delimited + strings. The JSON->XML conversion will handle these values transparently. + The default XML->JSON conversion writes all content as quote-delimited + strings, but there is a conversion option to recognize a limited set of + non-string elements based on the <code>xsi:type</code> attribute. +<dt> Arrays +<dd> XML does not have a defined array construct, but may repeat elements; JSON + has a defined array construct, and repeated elements will overwrite the + former definition. To avoid this problem, the XML->JSON conversion will + identify all repeated elements and create an array construct. The default + JSON->XML conversion creates a parent-children construct (which is more + palatable to subsequent XML->Java conversion), but a conversion option + allows conversion to a repeated element. +</dl> + +</body> +</html> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-22 15:04:54
|
Revision: 141 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=141&view=rev Author: kdgregory Date: 2009-09-22 15:04:28 +0000 (Tue, 22 Sep 2009) Log Message: ----------- replace StringBuffer by StringBuilder Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-18 18:45:53 UTC (rev 140) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Xml2JsonConverter.java 2009-09-22 15:04:28 UTC (rev 141) @@ -31,7 +31,7 @@ * Appends the contents of the specified element to an existing buffer. * Returns the buffer as a convenience. */ - public StringBuffer convert(Element elem, StringBuffer buf) + public StringBuilder convert(Element elem, StringBuilder buf) { String text = DomUtil.getText(elem); if (text != null) @@ -45,7 +45,7 @@ // Internals //---------------------------------------------------------------------------- - private StringBuffer appendText(String text, StringBuffer buf) + private StringBuilder appendText(String text, StringBuilder buf) { buf.append('"') .append(JsonUtil.escape(text)) @@ -54,7 +54,7 @@ } - private StringBuffer appendChildren(Element elem, StringBuffer buf) + private StringBuilder appendChildren(Element elem, StringBuilder buf) { buf.append("{"); List<Element> children = DomUtil.getChildren(elem); Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-18 18:45:53 UTC (rev 140) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestXml2JsonConverter.java 2009-09-22 15:04:28 UTC (rev 141) @@ -37,8 +37,8 @@ public void convertAndAssert(String expected, ElementNode rootNode) { Element root = rootNode.toDOM().getDocumentElement(); - StringBuffer buf = new Xml2JsonConverter() - .convert(root, new StringBuffer()); + StringBuilder buf = new Xml2JsonConverter() + .convert(root, new StringBuilder(256)); assertEquals(expected, buf.toString()); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-18 18:46:45
|
Revision: 140 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=140&view=rev Author: kdgregory Date: 2009-09-18 18:45:53 +0000 (Fri, 18 Sep 2009) Log Message: ----------- BeanConverter now contains only static methods, is a facade Renamed Bean2XmlDriver and Xml2BeanDriver to XXXConverter Moved conversion docs into package Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBeanConverter.java Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/package.html branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanConverter.java Removed Paths: ------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestBean2XmlDriver.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/bean/TestXml2BeanDriver.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java 2009-09-18 15:51:32 UTC (rev 139) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java 2009-09-18 18:45:53 UTC (rev 140) @@ -17,175 +17,32 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; -import net.sf.practicalxml.converter.bean.Bean2XmlDriver; +import net.sf.practicalxml.converter.bean.Bean2XmlConverter; import net.sf.practicalxml.converter.bean.Bean2XmlOptions; -import net.sf.practicalxml.converter.bean.Xml2BeanDriver; +import net.sf.practicalxml.converter.bean.Xml2BeanConverter; import net.sf.practicalxml.converter.bean.Xml2BeanOptions; /** * Converts Java objects (not just beans) to or from an XML representation. * Originally developed to support simple web services, without the overhead - * (schema definitions and/or annotations) required by JAXB. + * (schema definitions and/or annotations) required by JAXB. See the {@link + * net.sf.practicalxml.converter.bean package docs} for specifics. * <p> - * A single instance is intended for conversions in one direction only. This - * is a consequence of specifying options as varargs, but fits well with - * "normal" application design, in which input and output are handled by - * different parts of the code. You won't get an error if you try to convert - * the "wrong" way, you'll simply get default behavior. Note that, depending - * on options settings, output generated by one converter may not be valid - * input for another. + * This class provides static facade methods for + * {@link net.sf.practicalxml.converter.bean.Bean2XmlConverter} and + * {@link net.sf.practicalxml.converter.bean.Xml2BeanConverter}. If static + * methods and throwaway objects offend you then use those classes directly. * <p> - * The basic structure of XML produced/consumed by this class is that the - * root element represents the object being converted, and its child nodes - * represent the elements/properties of the object. Nodes representing complex - * objects have child elements, those representing simple (primitive) objects - * have a single text child. Objects are processed recursively, and cycles are - * <em>not</em> detected (although this may change). - * <p> - * A namespace and qualified name may be provided to {@link #convertToXml}, - * and all elements will inherit the namespace and prefix. Namespaces are - * ignored on input; all property matches uses the element's local name. - * <p> - * Each element may have an <code>xsi:type</code> attribute (where <code>xsi - * </code> references to the XML Schema instance namespace). This attribute - * is optional for both output and input; if used for output, it is merely - * informational, but for input will be examined to validate that the XML is - * appropriate for the desired object type. For primitive types, wrappers, - * and strings, it takes the form "<code>xsd:TYPE</code>", where <code>TYPE - * </code> is one of the simple types defined by XML schema. For other Java - * types, it takes the form "<code>java:TYPE</code>", where <code>TYPE</code> - * is the fully qualified Java classname. - * <p> - * On input, the desired type is specified by the caller or by introspection - * (except in the case of collection elements; see below). The <code>xsi:type - * </code> value, if any, is ignored except for validation. - * <p> - * Additional conversion rules are as follows: - * - * <table border="1"> - * <tr><th>Java Object Type - * <th>{@link #convertToXml} - * <th>{@link #convertToJava} - * <tr><td>Primitives, Wrapper objects, and String - * <td> - * <td> - * <tr><td>Arrays - * <td>Elements of the array are written in sequence to the DOM, using the - * element name "<code>data</code>". Elements are given an attribute - * named "<code>index</code>", which contains the element's position - * within the array. - * <td>Elements of the array are processed in sequence, ignoring both - * element name and "index" attribute. - * <tr><td>Lists and Sets - * <td>The collection is iterated, and elements are written in sequence to - * the DOM, using the element name "<code>data</code>". Elements are - * given an attribute named "<code>index</code>", which contains the - * element's position within the iteration (meaningful only for lists). - * <td>Elements of the are processed in sequence, ignoring both element - * name and "index" attribute. - * <p> - * If an <code>xsi:type</code> attribute is present, it will be used - * to drive conversion of the element. Otherwise, the element will be - * converted as a <code>String</code> (which will fail for complex - * types, because string conversion assumes a single text node). - * <p> - * Where the caller specifies an interface as the conversion class, the - * converter will choose an appropriate implementation class: - * <ul> - * <li> <code>ArrayList</code> for <code>List</code> or <code>Collection</code> - * <li> <code>TreeSet</code> for <code>SortedSet</code> - * <li> <code>HashSet</code> for <code>Set</code> - * </ul> - * <tr><td>Maps - * <td>The collection is iterated, and elements are written in sequence to - * the DOM. Depending on the output options, either the entry key will - * be used as the element name, or the name will be "<code>data</code>" - * and the key stored in an attribute named "<code>key</code>". The - * former option is only permitted if all keys in the map are valid - * XML element names; otherwise the converter will throw. - * <td>Elements are processed in sequence. The converter first looks for - * a "<code>key</code>" attribute, and will use it as the entry key - * if found. Otherwise, it will use the element name. If your maps - * are being reduced to a single entry, look for a missing attribute. - * <p> - * If an <code>xsi:type</code> attribute is present, it will be used - * to drive conversion of the element. Otherwise, the element will be - * converted as a <code>String</code> (which will fail for complex - * types, because string conversion assumes a single text node). - * <p> - * Where the caller specifies an interface as the conversion class, - * the converter will choose an appropriate implementation class: - * <code>TreeMap</code> for <code>SortedMap</code>, and <code>HashMap - * </code> for <code>Map</code>. - * <tr><td>Bean-structured Objects - * <td>The object is introspected, and properties are written in the order - * provided by the <code>Introspector</code>. - * <td>The bean class must provide a no-argument constructor (otherwise it - * doesn't follow the bean spec, and we can't use it). - * <p> - * The converter relies on <code>java.beans.Introspector</code> to find - * property setter methods for an object. If the object provides - * multiple methods for the property, the converter will use whichever - * one the introspector provides. - * <p> - * Elements are processed in order, and the element's localname is used - * to find the associated object property. If the XML does not contain - * an element corresponding to a bean property, that property is left - * with its default value (ie, we don't try to find an element based - * on property name). - * <p> - * If the XML contains an element that does not correspond to any bean - * property, the converter will either throw or ignore the element, - * depending on options settings. - * <tr><td>Other Objects - * <td>not supported - * <td>not supported - * </table> - * * <strong>Warning</strong>: - * <code>java.beans.Introspector</code> holds a cache of introspected objects. - * If you use this converter in an app-server you should call - * <code>Introspector.flushCaches()</code> during deploy. + * Bean-to-XML conversion uses <code>java.beans.Introspector</code>, which + * holds a cache of introspected objects. If you use this conversion in an + * app-server you should call <code>Introspector.flushCaches()</code> during + * deploy. */ public class BeanConverter { - private Bean2XmlDriver _outputDriver; - private Xml2BeanDriver _inputDriver; - - /** - * Creates an instance with all options disabled. This can be used for - * conversions in either direction, and is meant primarily for testing. - */ - public BeanConverter() - { - _outputDriver = new Bean2XmlDriver(); - _inputDriver = new Xml2BeanDriver(); - } - - - /** - * Creates an instance to be used for Bean -> XML conversion, - */ - public BeanConverter(Bean2XmlOptions... options) - { - _outputDriver = new Bean2XmlDriver(options); - _inputDriver = new Xml2BeanDriver(); - } - - - /** - * Creates an instance to be used for XML -> Bean conversion. - */ - public BeanConverter(Xml2BeanOptions options) - { - _outputDriver = new Bean2XmlDriver(); - _inputDriver = new Xml2BeanDriver(options); - } - - - /** * Creates a new DOM document from the passed bean, in which all elements * are members of the specified namespace and will inherit the root's * prefix (if any). @@ -197,10 +54,13 @@ * @param rootName The qualified name given to the root element of the * generated document. If a qualified name, all child * elements will inherit its prefix. + * @param options Conversion options. */ - public Document convertToXml(Object bean, String nsUri, String rootName) + public static Document convertToXml( + Object bean, String nsUri, String rootName, Bean2XmlOptions... options) { - return _outputDriver.convert(bean, nsUri, rootName) + return new Bean2XmlConverter(options) + .convert(bean, nsUri, rootName) .getOwnerDocument(); } @@ -212,10 +72,13 @@ * bean, collection, or simple type. * @param rootName The name given to the root element of the produced * document. + * @param options Conversion options. */ - public Document convertToXml(Object bean, String rootName) + public static Document convertToXml( + Object bean, String rootName, Bean2XmlOptions... options) { - return _outputDriver.convert(bean, rootName) + return new Bean2XmlConverter(options) + .convert(bean, rootName) .getOwnerDocument(); } @@ -227,10 +90,12 @@ * @param dom The source document. * @param klass The desired class to instantiate and fill from this * document. + * @param options Conversion options. */ - public <T> T convertToJava(Document dom, Class<T> klass) + public static <T> T convertToJava( + Document dom, Class<T> klass, Xml2BeanOptions... options) { - return convertToJava(dom.getDocumentElement(), klass); + return convertToJava(dom.getDocumentElement(), klass, options); } @@ -243,9 +108,11 @@ * root element of its document. * @param klass The desired class to instantiate and fill from this * document. + * @param options Conversion options. */ - public <T> T convertToJava(Element root, Class<T> klass) + public static <T> T convertToJava( + Element root, Class<T> klass, Xml2BeanOptions... options) { - return _inputDriver.convert(root, klass); + return new Xml2BeanConverter(options).convert(root, klass); } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-18 15:51:32 UTC (rev 139) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-09-18 18:45:53 UTC (rev 140) @@ -25,7 +25,7 @@ /** * Packaging class used for XML output appenders. This class is a temporary - * hack, as I move intelligence into {@link Bean2XmlDriver}; the contained + * hack, as I move intelligence into {@link Bean2XmlConverter}; the contained * classes will end up in a new package, once I figure out what the package * structure should be. */ Copied: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java (from rev 130, branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java) =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlConverter.java 2009-09-18 18:45:53 UTC (rev 140) @@ -0,0 +1,253 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter.bean; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Map; + +import org.w3c.dom.Element; + +import net.sf.practicalxml.DomUtil; +import net.sf.practicalxml.converter.ConversionException; +import net.sf.practicalxml.converter.bean.Bean2XmlAppenders.*; +import net.sf.practicalxml.converter.internal.ConversionStrings; +import net.sf.practicalxml.converter.internal.DomUtilToo; +import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; + + +/** + * Driver class for converting a Java bean into an XML DOM. Normal usage is + * to create a single instance of this class with desired options, then use + * it for multiple conversions. This class is thread-safe. + */ +public class Bean2XmlConverter +{ + private PrimitiveConversionHelper _helper; + private EnumSet<Bean2XmlOptions> _options = EnumSet.noneOf(Bean2XmlOptions.class); + + public Bean2XmlConverter(Bean2XmlOptions... options) + { + for (Bean2XmlOptions option : options) + _options.add(option); + _helper = new PrimitiveConversionHelper(shouldUseXsdFormatting()); + } + + +//---------------------------------------------------------------------------- +// Public methods +//---------------------------------------------------------------------------- + + /** + * Creates an XML DOM with the specified root element name, and fills it + * by introspecting the passed object (see {@link #introspect} for + * treatment of simple objects). + */ + public Element convert(Object obj, String rootName) + { + return convert(obj, null, rootName); + } + + + /** + * Creates an XML DOM with the specified root element name and namespace + * URI, and fills it by introspecting the passed object (see {@link + * #introspect} for treatment of simple objects). The namespace URI (and + * prefix, if provided) will be used for all child elements. + */ + public Element convert(Object obj, String nsUri, String rootName) + { + Element root = DomUtil.newDocument(nsUri, rootName); + doXsiNamespaceHack(root); + convert(obj, "", new DirectAppender(root, _options)); + return root; + } + + + /** + * Introspects the passed object, and appends its contents to the output. + * This method is public to allow non-standard conversions, such as + * appending into an existing tree, or (in the future, if we introduce an + * appender factory) producing non-XML output. + */ + public void convert(Object obj, String name, Appender appender) + { + // these methods have side effects! + // empty blocks and comments are there to keep Eclipse happy + if (tryToConvertAsPrimitiveOrNull(obj, null, name, appender)) + { /* it was converted */ } + else if (tryToConvertAsArray(obj, name, appender)) + { /* it was converted */ } + else if (tryToConvertAsMap(obj, name, appender)) + { /* it was converted */ } + else if (tryToConvertAsCollection(obj, name, appender)) + { /* it was converted */ } + else if (tryToConvertAsBean(obj, name, appender)) + { /* it was converted */ } + else + throw new ConversionException("unable to convert: " + obj.getClass().getName()); + } + + +//---------------------------------------------------------------------------- +// Internals +//---------------------------------------------------------------------------- + + private boolean shouldUseXsdFormatting() + { + return _options.contains(Bean2XmlOptions.XSD_FORMAT) + || _options.contains(Bean2XmlOptions.ADD_XSI_TYPE); + } + + + /** + * Introduces the XML Schema Instance namespace into the DOM tree using a + * meaningless attribute. The Xerces serializer does not attempt to promote + * namespace definitions above the subtree in which they first appear, which + * means that the XSI definition could be repeated many times throughout the + * serialized tree, adding bulk to the serialized representation. + * <p> + * By putting "nil=false" at the root element, we will keep the serializer + * from inserting all these definitions. This has to happen <em>before</em> + * any actual conversion, in case some bozo passes <code>null</code> to + * the top-level conversion routine. + * <p> + * Note that we only do this if <code>xsi:nil</code> is enabled by itself. + * If <code>xsi:type</code> is enabled, the converter will attach that + * attribute to the root instead, thereby establishing the namespace context. + */ + private void doXsiNamespaceHack(Element root) + { + if (_options.contains(Bean2XmlOptions.XSI_NIL) + && !_options.contains(Bean2XmlOptions.ADD_XSI_TYPE)) + { + DomUtilToo.setXsiNil(root, false); + } + } + + + private boolean tryToConvertAsPrimitiveOrNull( + Object obj, Class<?> klass, String name, Appender appender) + { + if (obj != null) + klass = obj.getClass(); + + String objType = _helper.getXsdType(klass); + if ((obj == null) || (objType != null)) + { + appender.appendValue(name, objType, _helper.stringify(obj)); + return true; + } + + return false; + } + + + private boolean tryToConvertAsArray(Object array, String name, Appender appender) + { + if (!array.getClass().isArray()) + return false; + + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(array)); + Appender childAppender = new IndexedAppender(parent, _options); + int length = Array.getLength(array); + for (int idx = 0 ; idx < length ; idx++) + { + Object value = Array.get(array, idx); + convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); + } + return true; + } + + + private boolean tryToConvertAsMap(Object obj, String name, Appender appender) + { + if (!(obj instanceof Map)) + return false; + + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); + Appender childAppender = new MapAppender(parent, _options); + for (Map.Entry<?,?> entry : ((Map<?,?>)obj).entrySet()) + { + convert(entry.getValue(), String.valueOf(entry.getKey()), childAppender); + } + return true; + } + + + private boolean tryToConvertAsCollection(Object obj, String name, Appender appender) + { + if (!(obj instanceof Collection)) + return false; + + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); + Appender childAppender = new IndexedAppender(parent, _options); + for (Object value : (Collection<?>)obj) + { + convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); + } + return true; + } + + + private boolean tryToConvertAsBean(Object bean, String name, Appender appender) + { + Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(bean)); + Appender childAppender = new BasicAppender(parent, _options); + try + { + BeanInfo info = Introspector.getBeanInfo(bean.getClass(), Object.class); + PropertyDescriptor[] props = info.getPropertyDescriptors(); + for (int ii = 0 ; ii < props.length ; ii++) + convertBeanProperty(bean, props[ii], childAppender); + } + catch (IntrospectionException ee) + { + throw new ConversionException("introspection failure", ee); + } + return true; + } + + + private void convertBeanProperty( + Object bean, PropertyDescriptor propDesc, Appender appender) + { + String name = propDesc.getName(); + Class<?> type = propDesc.getPropertyType(); + Object value; + try + { + Method getter = propDesc.getReadMethod(); + if (getter == null) + return; + value = getter.invoke(bean); + } + catch (Exception ee) + { + throw new ConversionException("unable to retrieve bean value", ee); + } + + if (value == null) + tryToConvertAsPrimitiveOrNull(value, type, name, appender); + else + convert(value, name, appender); + } +} Deleted: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java 2009-09-18 15:51:32 UTC (rev 139) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java 2009-09-18 18:45:53 UTC (rev 140) @@ -1,253 +0,0 @@ -// Copyright 2008-2009 severally by the contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package net.sf.practicalxml.converter.bean; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; - -import org.w3c.dom.Element; - -import net.sf.practicalxml.DomUtil; -import net.sf.practicalxml.converter.ConversionException; -import net.sf.practicalxml.converter.bean.Bean2XmlAppenders.*; -import net.sf.practicalxml.converter.internal.ConversionStrings; -import net.sf.practicalxml.converter.internal.DomUtilToo; -import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; - - -/** - * Driver class for converting a Java bean into an XML DOM. Normal usage is - * to create a single instance of this class with desired options, then use - * it for multiple conversions. This class is thread-safe. - */ -public class Bean2XmlDriver -{ - private PrimitiveConversionHelper _helper; - private EnumSet<Bean2XmlOptions> _options = EnumSet.noneOf(Bean2XmlOptions.class); - - public Bean2XmlDriver(Bean2XmlOptions... options) - { - for (Bean2XmlOptions option : options) - _options.add(option); - _helper = new PrimitiveConversionHelper(shouldUseXsdFormatting()); - } - - -//---------------------------------------------------------------------------- -// Public methods -//---------------------------------------------------------------------------- - - /** - * Creates an XML DOM with the specified root element name, and fills it - * by introspecting the passed object (see {@link #introspect} for - * treatment of simple objects). - */ - public Element convert(Object obj, String rootName) - { - return convert(obj, null, rootName); - } - - - /** - * Creates an XML DOM with the specified root element name and namespace - * URI, and fills it by introspecting the passed object (see {@link - * #introspect} for treatment of simple objects). The namespace URI (and - * prefix, if provided) will be used for all child elements. - */ - public Element convert(Object obj, String nsUri, String rootName) - { - Element root = DomUtil.newDocument(nsUri, rootName); - doXsiNamespaceHack(root); - convert(obj, "", new DirectAppender(root, _options)); - return root; - } - - - /** - * Introspects the passed object, and appends its contents to the output. - * This method is public to allow non-standard conversions, such as - * appending into an existing tree, or (in the future, if we introduce an - * appender factory) producing non-XML output. - */ - public void convert(Object obj, String name, Appender appender) - { - // these methods have side effects! - // empty blocks and comments are there to keep Eclipse happy - if (tryToConvertAsPrimitiveOrNull(obj, null, name, appender)) - { /* it was converted */ } - else if (tryToConvertAsArray(obj, name, appender)) - { /* it was converted */ } - else if (tryToConvertAsMap(obj, name, appender)) - { /* it was converted */ } - else if (tryToConvertAsCollection(obj, name, appender)) - { /* it was converted */ } - else if (tryToConvertAsBean(obj, name, appender)) - { /* it was converted */ } - else - throw new ConversionException("unable to convert: " + obj.getClass().getName()); - } - - -//---------------------------------------------------------------------------- -// Internals -//---------------------------------------------------------------------------- - - private boolean shouldUseXsdFormatting() - { - return _options.contains(Bean2XmlOptions.XSD_FORMAT) - || _options.contains(Bean2XmlOptions.ADD_XSI_TYPE); - } - - - /** - * Introduces the XML Schema Instance namespace into the DOM tree using a - * meaningless attribute. The Xerces serializer does not attempt to promote - * namespace definitions above the subtree in which they first appear, which - * means that the XSI definition could be repeated many times throughout the - * serialized tree, adding bulk to the serialized representation. - * <p> - * By putting "nil=false" at the root element, we will keep the serializer - * from inserting all these definitions. This has to happen <em>before</em> - * any actual conversion, in case some bozo passes <code>null</code> to - * the top-level conversion routine. - * <p> - * Note that we only do this if <code>xsi:nil</code> is enabled by itself. - * If <code>xsi:type</code> is enabled, the converter will attach that - * attribute to the root instead, thereby establishing the namespace context. - */ - private void doXsiNamespaceHack(Element root) - { - if (_options.contains(Bean2XmlOptions.XSI_NIL) - && !_options.contains(Bean2XmlOptions.ADD_XSI_TYPE)) - { - DomUtilToo.setXsiNil(root, false); - } - } - - - private boolean tryToConvertAsPrimitiveOrNull( - Object obj, Class<?> klass, String name, Appender appender) - { - if (obj != null) - klass = obj.getClass(); - - String objType = _helper.getXsdType(klass); - if ((obj == null) || (objType != null)) - { - appender.appendValue(name, objType, _helper.stringify(obj)); - return true; - } - - return false; - } - - - private boolean tryToConvertAsArray(Object array, String name, Appender appender) - { - if (!array.getClass().isArray()) - return false; - - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(array)); - Appender childAppender = new IndexedAppender(parent, _options); - int length = Array.getLength(array); - for (int idx = 0 ; idx < length ; idx++) - { - Object value = Array.get(array, idx); - convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); - } - return true; - } - - - private boolean tryToConvertAsMap(Object obj, String name, Appender appender) - { - if (!(obj instanceof Map)) - return false; - - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); - Appender childAppender = new MapAppender(parent, _options); - for (Map.Entry<?,?> entry : ((Map<?,?>)obj).entrySet()) - { - convert(entry.getValue(), String.valueOf(entry.getKey()), childAppender); - } - return true; - } - - - private boolean tryToConvertAsCollection(Object obj, String name, Appender appender) - { - if (!(obj instanceof Collection)) - return false; - - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(obj)); - Appender childAppender = new IndexedAppender(parent, _options); - for (Object value : (Collection<?>)obj) - { - convert(value, ConversionStrings.EL_COLLECTION_ITEM, childAppender); - } - return true; - } - - - private boolean tryToConvertAsBean(Object bean, String name, Appender appender) - { - Element parent = appender.appendContainer(name, DomUtilToo.getXsiTypeForJavaObject(bean)); - Appender childAppender = new BasicAppender(parent, _options); - try - { - BeanInfo info = Introspector.getBeanInfo(bean.getClass(), Object.class); - PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int ii = 0 ; ii < props.length ; ii++) - convertBeanProperty(bean, props[ii], childAppender); - } - catch (IntrospectionException ee) - { - throw new ConversionException("introspection failure", ee); - } - return true; - } - - - private void convertBeanProperty( - Object bean, PropertyDescriptor propDesc, Appender appender) - { - String name = propDesc.getName(); - Class<?> type = propDesc.getPropertyType(); - Object value; - try - { - Method getter = propDesc.getReadMethod(); - if (getter == null) - return; - value = getter.invoke(bean); - } - catch (Exception ee) - { - throw new ConversionException("unable to retrieve bean value", ee); - } - - if (value == null) - tryToConvertAsPrimitiveOrNull(value, type, name, appender); - else - convert(value, name, appender); - } -} Copied: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanConverter.java (from rev 130, branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java) =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanConverter.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanConverter.java 2009-09-18 18:45:53 UTC (rev 140) @@ -0,0 +1,396 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.sf.practicalxml.converter.bean; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import net.sf.practicalxml.DomUtil; +import net.sf.practicalxml.converter.ConversionException; +import net.sf.practicalxml.converter.internal.ConversionStrings; +import net.sf.practicalxml.converter.internal.DomUtilToo; +import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; +import net.sf.practicalxml.internal.StringUtils; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * Driver class for converting an XML DOM into a Java bean. Normal usage is + * to create a single instance of this class with desired options, then use + * it for multiple conversions. This class is thread-safe. + */ +public class Xml2BeanConverter +{ + private EnumSet<Xml2BeanOptions> _options; + private PrimitiveConversionHelper _helper; + private Map<Class<?>,Map<String,Method>> _introspectedClasses; + + + public Xml2BeanConverter(Xml2BeanOptions... options) + { + _options = EnumSet.noneOf(Xml2BeanOptions.class); + for (Xml2BeanOptions option : options) + _options.add(option); + + _helper = new PrimitiveConversionHelper(_options.contains(Xml2BeanOptions.EXPECT_XSD_FORMAT)); + _introspectedClasses = new HashMap<Class<?>,Map<String,Method>>(); + } + + +//---------------------------------------------------------------------------- +// Public Methods +//---------------------------------------------------------------------------- + + /** + * Attempts to convert the passed DOM subtree into an object of the + * specified class. + */ + public <T> T convert(Element elem, Class<T> klass) + { + return klass.cast(convertWithoutCast(elem, klass)); + } + + +//---------------------------------------------------------------------------- +// Internal Conversion Methods +//---------------------------------------------------------------------------- + + /** + * Attempts to convert the passed DOM subtree into an object of the + * specified class. Note that this version does not use generics, + * and does not try to cast the result, whereas the public version + * does. Internally, we want to treat <code>Integer.TYPE</code> the + * same as <code>Integer.class</code>, and the cast prevents that. + */ + public Object convertWithoutCast(Element elem, Class<?> klass) + { + validateXsiType(elem, klass); + if (isAllowableNull(elem)) + return null; + + Object obj = tryConvertAsPrimitive(elem, klass); + if (obj == null) + obj = tryConvertAsArray(elem, klass); + if (obj == null) + obj = tryConvertAsSimpleCollection(elem, klass); + if (obj == null) + obj = tryConvertAsMap(elem, klass); + if (obj == null) + obj = tryConvertAsBean(elem, klass); + return obj; + } + + + private boolean isAllowableNull(Element elem) + { + String text = getText(elem); + if ((text != null) || hasElementChildren(elem)) + return false; + + if (_options.contains(Xml2BeanOptions.REQUIRE_XSI_NIL)) + { + if (!DomUtilToo.getXsiNil(elem)) + throw new ConversionException("missing/false xsi:nil", elem); + } + + return true; + } + + + private Object tryConvertAsPrimitive(Element elem, Class<?> klass) + { + if (_helper.getXsdType(klass) == null) + return null; + + if (hasElementChildren(elem)) + throw new ConversionException("expecting primitive; has children", elem); + + return _helper.parse(getText(elem), klass); + } + + + private Object tryConvertAsArray(Element elem, Class<?> klass) + { + Class<?> childKlass = klass.getComponentType(); + if (childKlass == null) + return null; + + List<Element> children = DomUtil.getChildren(elem); + Object result = Array.newInstance(childKlass, children.size()); + int idx = 0; + for (Element child : children) + { + Array.set(result, idx++, convertWithoutCast(child, childKlass)); + } + return result; + } + + + private Object tryConvertAsSimpleCollection(Element elem, Class<?> klass) + { + Collection<Object> result = instantiateCollection(klass); + if (result == null) + return null; + + List<Element> children = DomUtil.getChildren(elem); + for (Element child : children) + { + Class<?> childClass = getClassFromXsiType(child); + if (childClass == null) + childClass = String.class; + result.add(convertWithoutCast(child, childClass)); + } + return result; + } + + + private Object tryConvertAsMap(Element elem, Class<?> klass) + { + Map<Object,Object> result = instantiateMap(klass); + if (result == null) + return null; + + List<Element> children = DomUtil.getChildren(elem); + for (Element child : children) + { + String key = child.getAttribute(ConversionStrings.AT_MAP_KEY); + if (StringUtils.isEmpty(key)) + key = DomUtil.getLocalName(child); + Class<?> childClass = getClassFromXsiType(child); + if (childClass == null) + childClass = String.class; + result.put(key, convertWithoutCast(child, childClass)); + } + return result; + } + + + private Object tryConvertAsBean(Element elem, Class<?> klass) + { + Object bean = instantiateBean(elem, klass); + + List<Element> children = DomUtil.getChildren(elem); + for (Element child : children) + { + Method setter = getSetterMethod(klass, child); + if (setter == null) + continue; + + Class<?> childClass = setter.getParameterTypes()[0]; + Object childValue = convertWithoutCast(child, childClass); + invokeSetter(elem, bean, setter, childValue); + } + return bean; + } + + +//---------------------------------------------------------------------------- +// Other Internals +//---------------------------------------------------------------------------- + + /** + * Returns the text content of an element, applying appropriate options. + */ + private String getText(Element elem) + { + String text = DomUtil.getText(elem); + if (StringUtils.isBlank(text) + && _options.contains(Xml2BeanOptions.CONVERT_BLANK_AS_NULL)) + text = null; + return text; + } + + + /** + * Examines an element's <code>xsi:type</code> attribute, if any, and + * returns the Java class corresponding to it. Used when converting + * collection types, which don't have type information that can be + * introspected, and also to validate non-XSD types. + */ + private Class<?> getClassFromXsiType(Element elem) + { + String xsiType = DomUtilToo.getXsiType(elem); + if (xsiType == null) + return null; + + String javaType = DomUtilToo.getJavaClassFromXsiType(xsiType); + if (javaType != null) + { + try + { + return Class.forName(javaType); + } + catch (ClassNotFoundException ee) + { + throw new ConversionException( + "invalid Java type specification: " + javaType, elem, ee); + } + } + + return _helper.getJavaType(xsiType); + } + + + private void validateXsiType(Element elem, Class<?> klass) + { + if (!_options.contains(Xml2BeanOptions.REQUIRE_XSI_TYPE)) + return; + + String xsiType = DomUtilToo.getXsiType(elem); + if (xsiType == null) + throw new ConversionException("missing xsi:type", elem); + + if (xsiType.equals(_helper.getXsdType(klass))) + return; + + Class<?> xsiKlass = getClassFromXsiType(elem); + if (klass.isAssignableFrom(xsiKlass)) + return; + + throw new ConversionException( + "invalid xsi:type: \"" + xsiType + "\" for " + klass.getName(), + elem); + } + + + private boolean hasElementChildren(Element elem) + { + Node child = elem.getFirstChild(); + while (child != null) + { + if (child instanceof Element) + return true; + child = child.getNextSibling(); + } + return false; + } + + + private Method getSetterMethod(Class<?> beanKlass, Element child) + { + Map<String,Method> methodMap = _introspectedClasses.get(beanKlass); + if (methodMap == null) + methodMap = introspect(beanKlass); + + Method setter = methodMap.get(DomUtil.getLocalName(child)); + if ((setter == null) && !_options.contains(Xml2BeanOptions.IGNORE_MISSING_PROPERTIES)) + { + throw new ConversionException("can't find property setter", child); + } + + return setter; + } + + + private Map<String,Method> introspect(Class<?> klass) + { + Map<String,Method> methodMap = new HashMap<String,Method>(); + try + { + BeanInfo info = Introspector.getBeanInfo(klass, Object.class); + for (PropertyDescriptor propDesc : info.getPropertyDescriptors()) + { + Method setter = propDesc.getWriteMethod(); + if (setter != null) + methodMap.put(propDesc.getName(), setter); + } + } + catch (IntrospectionException ee) + { + throw new ConversionException("unable to introspect", ee); + } + + _introspectedClasses.put(klass, methodMap); + return methodMap; + } + + + /** + * Attempts to create a <code>Collection</code> instance appropriate for + * the passed class, returns <code>null</code> if unable. + */ + private Collection<Object> instantiateCollection(Class<?> klass) + { + if (SortedSet.class.isAssignableFrom(klass)) + return new TreeSet<Object>(); + else if (Set.class.isAssignableFrom(klass)) + return new HashSet<Object>(); + else if (List.class.isAssignableFrom(klass)) + return new ArrayList<Object>(); + else if (Collection.class.isAssignableFrom(klass)) + return new ArrayList<Object>(); + else + return null; + } + + + /** + * Attempts to create a <code>Map</code> instance appropriate for the + * passed class, returns <code>null</code> if unable. + */ + private Map<Object,Object> instantiateMap(Class<?> klass) + { + if (SortedMap.class.isAssignableFrom(klass)) + return new TreeMap<Object,Object>(); + else if (Map.class.isAssignableFrom(klass)) + return new HashMap<Object,Object>(); + else + return null; + } + + + private Object instantiateBean(Element elem, Class<?> klass) + { + try + { + return klass.newInstance(); + } + catch (Exception ee) + { + throw new ConversionException("unable to instantiate bean", elem, ee); + } + } + + + private void invokeSetter(Element elem, Object bean, Method setter, Object value) + { + try + { + setter.invoke(bean, value); + } + catch (Exception ee) + { + throw new ConversionException("unable to set property", elem, ee); + } + } +} Deleted: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-09-18 15:51:32 UTC (rev 139) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-09-18 18:45:53 UTC (rev 140) @@ -1,396 +0,0 @@ -// Copyright 2008-2009 severally by the contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package net.sf.practicalxml.converter.bean; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -import net.sf.practicalxml.DomUtil; -import net.sf.practicalxml.converter.ConversionException; -import net.sf.practicalxml.converter.internal.ConversionStrings; -import net.sf.practicalxml.converter.internal.DomUtilToo; -import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; -import net.sf.practicalxml.internal.StringUtils; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; - - -/** - * Driver class for converting an XML DOM into a Java bean. Normal usage is - * to create a single instance of this class with desired options, then use - * it for multiple conversions. This class is thread-safe. - */ -public class Xml2BeanDriver -{ - private EnumSet<Xml2BeanOptions> _options; - private PrimitiveConversionHelper _helper; - private Map<Class<?>,Map<String,Method>> _introspectedClasses; - - - public Xml2BeanDriver(Xml2BeanOptions... options) - { - _options = EnumSet.noneOf(Xml2BeanOptions.class); - for (Xml2BeanOptions option : options) - _options.add(option); - - _helper = new PrimitiveConversionHelper(_options.contains(Xml2BeanOptions.EXPECT_XSD_FORMAT)); - _introspectedClasses = new HashMap<Class<?>,Map<String,Method>>(); - } - - -//---------------------------------------------------------------------------- -// Public Methods -//---------------------------------------------------------------------------- - - /** - * Attempts to convert the passed DOM subtree into an object of the - * specified class. - */ - public <T> T convert(Element elem, Class<T> klass) - { - return klass.cast(convertWithoutCast(elem, klass)); - } - - -//---------------------------------------------------------------------------- -// Internal Conversion Methods -//---------------------------------------------------------------------------- - - /** - * Attempts to convert the passed DOM subtree into an object of the - * specified class. Note that this version does not use generics, - * and does not try to cast the result, whereas the public version - * does. Internally, we want to treat <code>Integer.TYPE</code> the - * same as <code>Integer.class</code>, and the cast prevents that. - */ - public Object convertWithoutCast(Element elem, Class<?> klass) - { - validateXsiType(elem, klass); - if (isAllowableNull(elem)) - return null; - - Object obj = tryConvertAsPrimitive(elem, klass); - if (obj == null) - obj = tryConvertAsArray(elem, klass); - if (obj == null) - obj = tryConvertAsSimpleCollection(elem, klass); - if (obj == null) - obj = tryConvertAsMap(elem, klass); - if (obj == null) - obj = tryConvertAsBean(elem, klass); - return obj; - } - - - private boolean isAllowableNull(Element elem) - { - String text = getText(elem); - if ((text != null) || hasElementChildren(elem)) - return false; - - if (_options.contains(Xml2BeanOptions.REQUIRE_XSI_NIL)) - { - if (!DomUtilToo.getXsiNil(elem)) - throw new ConversionException("missing/false xsi:nil", elem); - } - - return true; - } - - - private Object tryConvertAsPrimitive(Element elem, Class<?> klass) - { - if (_helper.getXsdType(klass) == null) - return null; - - if (hasElementChildren(elem)) - throw new ConversionException("expecting primitive; has children", elem); - - return _helper.parse(getText(elem), klass); - } - - - private Object tryConvertAsArray(Element elem, Class<?> klass) - { - Class<?> childKlass = klass.getComponentType(); - if (childKlass == null) - return null; - - List<Element> children = DomUtil.getChildren(elem); - Object result = Array.newInstance(childKlass, children.size()); - int idx = 0; - for (Element child : children) - { - Array.set(result, idx++, convertWithoutCast(child, childKlass)); - } - return result; - } - - - private Object tryConvertAsSimpleCollection(Element elem, Class<?> klass) - { - Collection<Object> result = instantiateCollection(klass); - if (result == null) - return null; - - List<Element> children = DomUtil.getChildren(elem); - for (Element child : children) - { - Class<?> childClass = getClassFromXsiType(child); - if (childClass == null) - childClass = String.class; - result.add(convertWithoutCast(child, childClass)); - } - return result; - } - - - private Object tryConvertAsMap(Element elem, Class<?> klass) - { - Map<Object,Object> result = instantiateMap(klass); - if (result == null) - return null; - - List<Element> children = DomUtil.getChildren(elem); - for (Element child : children) - { - String key = child.getAttribute(ConversionStrings.AT_MAP_KEY); - if (StringUtils.isEmpty(key)) - key = DomUtil.getLocalName(child); - Class<?> childClass = getClassFromXsiType(child); - if (childClass == null) - childClass = String.class; - result.put(key, convertWithoutCast(child, childClass)); - } - return result; - } - - - private Object tryConvertAsBean(Element elem, Class<?> klass) - { - Object bean = instantiateBean(elem, klass); - - List<Element> children = DomUtil.getChildren(elem); - for (Element child : children) - { - Method setter = getSetterMethod(klass, child); - if (setter == null) - continue; - - Class<?> childClass = setter.getParameterTypes()[0]; - Object childValue = convertWithoutCast(child, childClass); - invokeSetter(elem, bean, setter, childValue); - } - return bean; - } - - -//---------------------------------------------------------------------------- -// Other Internals -//---------------------------------------------------------------------------- - - /** - * Returns the text content of an element, applying appropriate options. - */ - private String getText(Element elem) - { - String text = DomUtil.getText(elem); - if (StringUtils.isBlank(text) - && _options.contains(Xml2BeanOptions.CONVERT_BLANK_AS_NULL)) - text = null; - return text; - } - - - /** - * Examines an element's <code>xsi:type</code> attribute, if any, and - * returns the Java class corresponding to it. Used when converting - * collection types, which don't have type information that can be - * introspected, and also to validate non-XSD types. - */ - private Class<?> getClassFromXsiType(Element elem) - { - String xsiType = DomUtilToo.getXsiType(elem); - if (xsiType == null) - return null; - - String javaType = DomUtilToo.getJavaClassFromXsiType(xsiType); - if (javaType != null) - { - try - { - return Class.forName(javaType); - } - catch (ClassNotFoundException ee) - { - throw new ConversionException( - "invalid Java type specification: " + javaType, elem, ee); - } - } - - return _helper.getJavaType(xsiType); - } - - - private void validateXsiType(Element elem, Class<?> klass) - { - if (!_options.contains(Xml2BeanOptions.REQUIRE_XSI_TYPE)) - return; - - String xsiType = DomUtilToo.getXsiType(elem); - if (xsiType == null) - throw new ConversionException("missing xsi:type", elem); - - if (xsiType.equals(_helper.getXsdType(klass))) - return; - - Class<?> xsiKlass = getClassFromXsiType(elem); - if (klass.isAssignableFrom(xsiKlass)) - return; - - throw new ConversionException( - "invalid xsi:type: \"" + xsiType + "\" for " + klass.getName(), - elem); - } - - - private boolean hasElementChildren(Element elem) - { - Node child = elem.getFirstChild(); - while (child != null) - { - if (child instanceof Element) - return true; - child = child.getNextSibling(); - } - return false; - } - - - private Method getSetterMethod(Class<?> beanKlass, Element child) - { - Map<String,Method> methodMap = _introspectedClasses.get(beanKlass); - if (methodMap == null) - methodMap = introspect(beanKlass); - - Method setter = methodMap.get(DomUtil.getLocalName(child)); - if ((setter == null) && !_options.contains(Xml2BeanOptions.IGNORE_MISSING_PROPERTIES)) - { - throw new ConversionException("can't find property setter", child); - } - - return setter; - } - - - private Map<String,Method> introspect(Class<?> klass) - { - Map<String,Method> methodMap = new HashMap<String,Method>(); - try - { - BeanInfo info = Introspector.getBeanInfo(klass, Object.class); - for (PropertyDescriptor propDesc : info.getPropertyDescriptors()) - { - Method setter = propDesc.getWriteMethod(); - if (setter != null) - methodMap.put(propDesc.getName(), setter); - } - } - catch (IntrospectionException ee) - { - throw new ConversionException("unable to introspect", ee); - } - - _introspectedClasses.put(klass, methodMap); - return methodMap; - } - - - /** - * Attempts to create a <code>Collection</code> instance appropriate for - * the passed class, returns <code>null</code> if unable. - */ - private Collection<Object> instantiateCollection(Class<?> klass) - { - if (SortedSet.class.isAssignableFrom(klass)) - return new TreeSet<Object>(); - else if (Set.class.isAssignableFrom(klass)) - return new HashSet<Object>(); - else if (List.class.isAssignableFrom(klass)) - return new ArrayList<Object>(); - else if (Collection.class.isAssignableFrom(klass)) - return new ArrayList<Object>(); - else - return null; - } - - - /** - * Attempts to create a <code>Map</code> instance appropriate for the - * passed class, returns <code>null</code> if unable. - */ - private Map<Object,Object> instantiateMap(Class<?> klass) - { - if (SortedMap.class.isAssignableFrom(klass)) - return new TreeMap<Object,Object>(); - else if (Map.class.isAssignableFrom(klass)) - return new HashMap<Object,Object>(); - else - return null; - } - - - private Object instantiateBean(Element elem, Class<?> klass) - { - try - { - return klass.newInstance(); - } - ... [truncated message content] |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-18 15:51:42
|
Revision: 139 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=139&view=rev Author: kdgregory Date: 2009-09-18 15:51:32 +0000 (Fri, 18 Sep 2009) Log Message: ----------- OutputUtil: add compact() and indented(), allowing arbitrary source and target objects Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/OutputUtil.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/OutputUtil.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/OutputUtil.java 2009-09-17 12:49:44 UTC (rev 138) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/OutputUtil.java 2009-09-18 15:51:32 UTC (rev 139) @@ -64,6 +64,29 @@ /** + * Serializes to a compact format, without prologue or whitespace between + * elements, using UTF-8 encoding. + */ + public static void compact(Source src, Result target) + { + new TransformHelper().transform(src, target); + } + + + /** + * Serializes to a human-readable format, with each element starting on a + * new line, and child elements indented a specified amount from their + * parent. + */ + public static void indented(Source src, Result target, int indent) + { + new TransformHelper() + .setIndent(indent) + .transform(src, target); + } + + + /** * Writes a DOM document to a simple string format, without a prologue or * whitespace between elements. * <p> @@ -75,8 +98,7 @@ public static String compactString(Document dom) { StringWriter out = new StringWriter(); - new TransformHelper() - .transform(new DOMSource(dom), new StreamResult(out)); + compact(new DOMSource(dom), new StreamResult(out)); return out.toString(); } @@ -102,8 +124,7 @@ public static String compactString(XMLReader reader) { StringWriter out = new StringWriter(); - new TransformHelper() - .transform(new SAXSource(reader, null), new StreamResult(out)); + compact(new SAXSource(reader, null), new StreamResult(out)); return out.toString(); } @@ -115,22 +136,20 @@ * Do not simply write this string to a file unless you use UTF-8 encoding * or attach a prologue that specifies the encoding. * - * @param dom The DOM tree to be output. - * @param indentSize The number of spaces to indent each level of the - * tree. Indentation is <em>best effort</em>: the - * <code>javax.transform</code> API does not provide - * any way to set indent level, so we use JDK-specific - * features to achieve this, <em>where available</em>. - * Note also that indenting will cause problems with - * elements that contain mixed content, particularly - * if the text elements cannot be trimmed. + * @param dom The DOM tree to be output. + * @param indent The number of spaces to indent each level of the + * tree. Indentation is <em>best effort</em>: the + * <code>javax.transform</code> API does not provide + * any way to set indent level, so we use JDK-specific + * features to achieve this, <em>where available</em>. + * Note also that indenting will cause problems with + * elements that contain mixed content, particularly + * if the text elements cannot be trimmed. */ - public static String indentedString(Document dom, int indentSize) + public static String indentedString(Document dom, int indent) { StringWriter out = new StringWriter(); - new TransformHelper() - .setIndent(indentSize) - .transform(new DOMSource(dom), new StreamResult(out)); + indented(new DOMSource(dom), new StreamResult(out), indent); return out.toString(); } @@ -151,29 +170,27 @@ * Do not simply write this string to a file unless you use UTF-8 encoding * or attach a prologue that specifies the encoding. * - * @param reader Provides a source of SAX events for the transformer. - * @param indentSize The number of spaces to indent each level of the - * tree. Indentation is <em>best effort</em>: the - * <code>javax.transform</code> API does not provide - * any way to set indent level, so we use JDK-specific - * features to achieve this, <em>where available</em>. - * Note also that indenting will cause problems with - * elements that contain mixed content, particularly - * if the text elements cannot be trimmed. + * @param reader Provides a source of SAX events for the transformer. + * @param indent The number of spaces to indent each level of the + * tree. Indentation is <em>best effort</em>: the + * <code>javax.transform</code> API does not provide + * any way to set indent level, so we use JDK-specific + * features to achieve this, <em>where available</em>. + * Note also that indenting will cause problems with + * elements that contain mixed content, particularly + * if the text elements cannot be trimmed. */ - public static String indentedString(XMLReader reader, int indentSize) + public static String indentedString(XMLReader reader, int indent) { StringWriter out = new StringWriter(); - new TransformHelper() - .setIndent(indentSize) - .transform(new SAXSource(reader, null), new StreamResult(out)); + indented(new SAXSource(reader, null), new StreamResult(out), indent); return out.toString(); } /** - * Writes a DOM document to a stream using UTF-8 encoding, without a prologue - * or whitespace between elements. + * Writes a DOM document to a stream using UTF-8 encoding, in a compact + * format without a prologue or whitespace between elements. * * @param dom The DOM tree to be output. * @param stream The output stream. This stream will be flushed by @@ -181,16 +198,15 @@ */ public static void compactStream(Document dom, OutputStream stream) { - new TransformHelper() - .transform(new DOMSource(dom), new StreamResult(stream)); + compact(new DOMSource(dom), new StreamResult(stream)); flushStream(stream); } /** - * Writes XML to a stream using UTF-8 encoding, without prologue or - * whitespace between elements, using the passed <code>XMLReader</code> - * to generate a stream of SAX events. + * Writes XML to a stream using UTF-8 encoding, in a compact format + * without prologue or whitespace between elements, using the passed + * <code>XMLReader</code> to generate a stream of SAX events. * <p> * The transformer will call the reader's <code>setContentHandler()</code> * method, followed by <code>parse()</code>. In the latter method, the @@ -206,8 +222,7 @@ */ public static void compactStream(XMLReader reader, OutputStream stream) { - new TransformHelper() - .transform(new SAXSource(reader, null), new StreamResult(stream)); + compact(new SAXSource(reader, null), new StreamResult(stream)); flushStream(stream); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-17 12:49:51
|
Revision: 138 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=138&view=rev Author: kdgregory Date: 2009-09-17 12:49:44 +0000 (Thu, 17 Sep 2009) Log Message: ----------- add more explanation about release numbering Modified Paths: -------------- trunk/README.txt Modified: trunk/README.txt =================================================================== --- trunk/README.txt 2009-09-16 22:10:04 UTC (rev 137) +++ trunk/README.txt 2009-09-17 12:49:44 UTC (rev 138) @@ -31,18 +31,37 @@ repository. Minor releases preserve backwards compatibility: code written for one minor release will work when linked with another minor release. - PATCH releases won't actually get released: the PATCH revision - number should be incremented with each checkin, in preference - to using a "-SNAPSHOT" of the next minor release. This will - lock users into keeping their build scripts and local repository - up-to-date, which is a Good Thing. + PATCH releases happen whenever a method or class gets added or + changed in a minor way. They will not be released to any + central repository, and will probably not be tagged either. Major and minor releases will be tagged in the Subversion repository, using the form "rel-X.Y", where X and Y are the major and minor release numbers. Patch releases may be tagged using the form "rel-X.Y.Z", if the maintainer decides that it's important to rebuild that particular release - (although making it a minor release might be a better idea). + (eg, as a dependency for another application). Major and minor releases will be available for download from Sourceforge ( http://sourceforge.net/project/showfiles.php?group_id=234884 ), and also from the Central Maven Repository. + + The whole "patch release" idea has caused some controversy. My thought with + these releases is that they're a step above "nightly development build," + and represent stable functionality. By giving fixed release numbers, your + build tool should call out any possible incompatibilities, such as "your + main project relies on 1.0.15, but your repository contains 1.0.17, why?" + I believe that long-lived "snapshot" builds on the trunk are a bad idea + (that said, if you're making a number of changes and want to check-in + increments, feel free to put "SNAPSHOT" on the revision number; but try + to finish within a day). + + As far as tagging goes, I don't think that it's necessary unless you rely + on a particular patch revision. Then go for it. Since Subversion revision + numbers apply to the entire repository, you can always create an tag for + some past point in time. Easiest way to do this is browse the history of + pom.xml. + + To clear up one last bit of confusion: the patch number should only be + incremented when the external API has changed. If you add comments, or + tests, or even completely rewrite the internals, the patch number stays + the same. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-16 22:10:10
|
Revision: 137 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=137&view=rev Author: kdgregory Date: 2009-09-16 22:10:04 +0000 (Wed, 16 Sep 2009) Log Message: ----------- update release number Modified Paths: -------------- trunk/pom.xml Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2009-09-16 22:05:24 UTC (rev 136) +++ trunk/pom.xml 2009-09-16 22:10:04 UTC (rev 137) @@ -5,7 +5,7 @@ <groupId>net.sf.practicalxml</groupId> <artifactId>practicalxml</artifactId> <packaging>jar</packaging> - <version>1.0.5-SNAPSHOT</version> + <version>1.0.5</version> <name>practicalxml</name> <url>http://sourceforge.net/projects/practicalxml/</url> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-16 22:05:36
|
Revision: 136 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=136&view=rev Author: kdgregory Date: 2009-09-16 22:05:24 +0000 (Wed, 16 Sep 2009) Log Message: ----------- fix JavaDoc complaints Modified Paths: -------------- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java trunk/src/main/java/net/sf/practicalxml/XmlUtil.java trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java =================================================================== --- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2009-09-16 21:31:05 UTC (rev 135) +++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2009-09-16 22:05:24 UTC (rev 136) @@ -68,7 +68,7 @@ * <p> * The caller is responsible for ordering the sources so that imported * schemas appear first. This method is unable to combine sources from - * the same target namespace; see {@link #combineSchema combineSchema()} + * the same target namespace; see {@link #combineSchemas combineSchemas()} * for explanation. * * @param sources The source schema documents. Note that these are @@ -93,7 +93,7 @@ * <p> * The caller is responsible for ordering the sources so that imported * schemas appear first. This method is unable to combine sources from - * the same target namespace; see {@link #combineSchema combineSchema()} + * the same target namespace; see {@link #combineSchemas combineSchemas()} * for explanation. * * @param factory Used to create the schema object. @@ -119,7 +119,7 @@ * <p> * The caller is responsible for ordering the documents so that imported * schemas appear first. This method is unable to combine sources from - * the same target namespace; see {@link #combineSchema combineSchema()} + * the same target namespace; see {@link #combineSchemas combineSchemas()} * for explanation. * * @param factory Used to create the schema object. Modified: trunk/src/main/java/net/sf/practicalxml/XmlUtil.java =================================================================== --- trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-09-16 21:31:05 UTC (rev 135) +++ trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-09-16 22:05:24 UTC (rev 136) @@ -91,7 +91,7 @@ * XML Schema for <code>dateTime</code> elements. Output is UTC time, and * omits timezone specifier. * - * @see http://www.w3.org/TR/xmlschema-2/#dateTime + * @see <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">XML Schema</a> */ public static String formatXsdDatetime(Date date) { Modified: trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java =================================================================== --- trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2009-09-16 21:31:05 UTC (rev 135) +++ trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2009-09-16 22:05:24 UTC (rev 136) @@ -444,22 +444,6 @@ * Processes a <code>null</code> argument — it's unclear whether * this can ever happen. The default implementation throws <code> * IllegalArgumentException</code>. - - - @Override - public boolean equals(Object obj) - { - // FIXME - implement - return super.equals(obj); - } - - - @Override - public int hashCode() - { - // FIXME - implement - return super.hashCode(); - } * * @param index Index of the argument, numbered from 0. * @param helper Helper object to preserve intermediate results. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |