Author: tomdz Date: Tue May 29 21:53:41 2007 New Revision: 542749 URL: http://svn.apache.org/viewvc?view=rev&rev=542749 Log: Fix for DDLUTILS-174
Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java?view=diff&rev=542749&r1=542748&r2=542749 ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java Tue May 29 21:53:41 2007 @@ -22,9 +22,11 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Writer; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.xml.stream.XMLOutputFactory; @@ -281,7 +283,7 @@ { // we create an attribute only if the text is not too long // and if it does not contain special characters - if ((valueAsText.length() > MAX_ATTRIBUTE_LENGTH) || containsSpecialCharacters(valueAsText)) + if ((valueAsText.length() > MAX_ATTRIBUTE_LENGTH) || analyzeText(valueAsText, null)) { // we defer writing the sub elements subElements.put(column.getName(), valueAsText); @@ -294,6 +296,8 @@ } if (!subElements.isEmpty()) { + List cutPoints = new ArrayList(); + for (Iterator it = subElements.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); @@ -304,15 +308,39 @@ _writer.writeStartElement(entry.getKey().toString()); // if the content contains special characters, we have to apply base64 encoding to it - // if the content is too short, then it has to contain special characters, otherwise we check - if ((content.length() <= MAX_ATTRIBUTE_LENGTH) || containsSpecialCharacters(content)) + // if the content is too short, then it has to contain special characters (otherwise + // it would have been written as an attribute already), otherwise we check + cutPoints.clear(); + + boolean writeBase64Encoded = analyzeText(content, cutPoints); + + if (writeBase64Encoded) { _writer.writeAttribute(DatabaseIO.BASE64_ATTR_NAME, "true"); _writer.writeCData(new String(Base64.encodeBase64(content.getBytes()))); } else { - _writer.writeCData(content); + if (cutPoints.isEmpty()) + { + _writer.writeCData(content); + } + else + { + int lastPos = 0; + + for (Iterator cutPointIt = cutPoints.iterator(); cutPointIt.hasNext();) + { + int curPos = ((Integer)cutPointIt.next()).intValue(); + + _writer.writeCData(content.substring(lastPos, curPos)); + lastPos = curPos; + } + if (lastPos < content.length()) + { + _writer.writeCData(content.substring(lastPos)); + } + } } _writer.writeEndElement(); @@ -335,14 +363,19 @@ /** * Determines whether the given string contains special characters that cannot - * be used in XML. + * be used in XML, and if not, finds the cut points where to split the text + * when writing it in a CDATA section. * - * @param text The text + * @param text The text + * @param cutPoints Will be filled with cut points to split the text when writing it + * in a CDATA section (only if the method returns <code>false</code>) * @return <code>true</code> if the text contains special characters */ - private boolean containsSpecialCharacters(String text) + private boolean analyzeText(String text, List cutPoints) { - int numChars = text.length(); + List tmpCutPoints = cutPoints == null ? null : new ArrayList(); + int numChars = text.length(); + int numFoundCDataEndChars = 0; for (int charPos = 0; charPos < numChars; charPos++) { @@ -352,6 +385,27 @@ { return true; } + else if (cutPoints != null) + { + if ((c == ']') && ((numFoundCDataEndChars == 0) || (numFoundCDataEndChars == 1))) + { + numFoundCDataEndChars++; + } + else if ((c == '>') && (numFoundCDataEndChars == 2)) + { + // we have to split the CDATA right here before the '>' (see DDLUTILS-174) + tmpCutPoints.add(new Integer(charPos)); + numFoundCDataEndChars = 0; + } + else + { + numFoundCDataEndChars = 0; + } + } + } + if (cutPoints != null) + { + cutPoints.addAll(tmpCutPoints); } return false; } Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java?view=diff&rev=542749&r1=542748&r2=542749 ============================================================================== --- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java (original) +++ db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java Tue May 29 21:53:41 2007 @@ -246,11 +246,15 @@ " <column name=\"value1\" type=\"VARCHAR\" size=\"50\" required=\"true\"/>\n"+ " <column name=\"value2\" type=\"VARCHAR\" size=\"4000\" required=\"true\"/>\n"+ " <column name=\"value3\" type=\"LONGVARCHAR\" size=\"4000\" required=\"true\"/>\n"+ + " <column name=\"value4\" type=\"LONGVARCHAR\" size=\"4000\" required=\"true\"/>\n"+ + " <column name=\"value5\" type=\"LONGVARCHAR\" size=\"4000\" required=\"true\"/>\n"+ " </table>\n"+ "</database>"; final String testedValue1 = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><test><![CDATA[some text]]></test>"; final String testedValue2 = StringUtils.repeat("a ", 1000) + testedValue1; final String testedValue3 = "<div>\n<h1><![CDATA[WfMOpen]]></h1>\n" + StringUtils.repeat("Make it longer\n", 99) + "</div>"; + final String testedValue4 = "<![CDATA[" + StringUtils.repeat("b \n", 1000) + "]]>"; + final String testedValue5 = "<<![CDATA[" + StringUtils.repeat("b \n", 500) + "]]>><![CDATA[" + StringUtils.repeat("c \n", 500) + "]]>"; DatabaseIO modelIO = new DatabaseIO(); @@ -266,6 +270,8 @@ bean.set("value1", testedValue1); bean.set("value2", testedValue2); bean.set("value3", testedValue3); + bean.set("value4", testedValue4); + bean.set("value5", testedValue5); dataWriter.writeDocumentStart(); dataWriter.write(bean); dataWriter.writeDocumentEnd(); @@ -305,5 +311,9 @@ obj.get("value2").toString()); assertEquals(testedValue3, obj.get("value3").toString()); + assertEquals(testedValue4, + obj.get("value4").toString()); + assertEquals(testedValue5, + obj.get("value5").toString()); } }