You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2009/01/26 20:33:48 UTC
svn commit: r737796 - in
/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src:
main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java
test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java
Author: veithen
Date: Mon Jan 26 19:33:48 2009
New Revision: 737796
URL: http://svn.apache.org/viewvc?rev=737796&view=rev
Log:
Some improvements and fixes in XMLFormatFilter.
Modified:
webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java
webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java
Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java?rev=737796&r1=737795&r2=737796&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilter.java Mon Jan 26 19:33:48 2009
@@ -18,45 +18,124 @@
/**
* Filter that reformats XML data so that it is properly indented.
+ * <p>
+ * Note that this filter only works if the stream is encoded in an
+ * ASCII compatible charset encoding (ASCII, UTF-8, ISO-8859-x, etc.).
*/
public class XmlFormatFilter implements StreamFilter {
+ private static final int STATE_WHITESPACE = 0;
+ private static final int STATE_START_TAG = 1;
+ private static final int STATE_END_TAG = 2;
+ private static final int STATE_PI = 3;
+ private static final int STATE_TEXT = 4;
+
private final int tabWidth;
+ private int state = STATE_TEXT;
private boolean firstIndent = true;
- private int nextIndent = -1;
- private int previousIndent = -1;
+ private boolean endTagRequiresIndent = false;
+ private int level = -1; // The current element level (root = 0)
public XmlFormatFilter(int tabWidth) {
this.tabWidth = tabWidth;
}
+ private static boolean isSpace(int b) {
+ return b == ' ' || b == '\r' || b == '\n' || b == '\t';
+ }
+
+ private static boolean isNameStartChar(int b) {
+ // This covers the ASCII subset of the NameStartChar production, minus the colon
+ return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || b == '_';
+ }
+
+ private void indent(Stream stream, int amount) {
+ if (firstIndent) {
+ firstIndent = false;
+ } else {
+ stream.insert((byte)'\n');
+ }
+ for (int i = 0; i < tabWidth * amount; i++) {
+ stream.insert((byte)' ');
+ }
+ }
+
public void invoke(Stream stream) {
try {
while (stream.available() > 0) {
- boolean doIndent = false;
- if (stream.get(0) == '<' && stream.get(1) != '/') {
- previousIndent = nextIndent++;
- doIndent = true;
- } else if (stream.get(0) == '<' && stream.get(1) == '/') {
- doIndent = previousIndent > nextIndent;
- previousIndent = nextIndent--;
- } else if ((stream.get(0) == '/' || stream.get(0) == '?')
- && stream.get(1) == '>') {
- previousIndent = nextIndent--;
- }
- if (doIndent) {
- if (firstIndent) {
- firstIndent = false;
- } else {
- stream.insert((byte) '\n');
+ switch (state) {
+ case STATE_WHITESPACE: {
+ int i = 0;
+ int c;
+ while (isSpace(c = stream.get(i))) {
+ i++;
+ }
+ if (c == '<') {
+ stream.discard(i);
+ } else {
+ stream.skip(i);
+ }
+ state = STATE_TEXT;
+ break;
}
- for (int i = tabWidth * nextIndent; i > 0; i--) {
- stream.insert((byte) ' ');
+ case STATE_TEXT: {
+ if (stream.get(0) == '<') {
+ int c = stream.get(1);
+ if (c == '/') {
+ if (endTagRequiresIndent) {
+ indent(stream, level);
+ }
+ stream.skip(2);
+ state = STATE_END_TAG;
+ } else if (c == '?') {
+ indent(stream, level+1);
+ stream.skip(2);
+ state = STATE_PI;
+ } else if (isNameStartChar(c)) {
+ indent(stream, ++level);
+ stream.skip(2);
+ state = STATE_START_TAG;
+ } else {
+ stream.skip(1);
+ }
+ } else {
+ stream.skip(1);
+ }
+ break;
+ }
+ case STATE_START_TAG: {
+ if (stream.get(0) == '/' && stream.get(1) == '>') {
+ stream.skip(2);
+ level--;
+ state = STATE_WHITESPACE;
+ endTagRequiresIndent = true;
+ } else if (stream.get(0) == '>') {
+ stream.skip(1);
+ state = STATE_WHITESPACE;
+ endTagRequiresIndent = false;
+ } else {
+ stream.skip(1);
+ }
+ break;
+ }
+ case STATE_END_TAG: {
+ if (stream.get(0) == '>') {
+ level--;
+ state = STATE_WHITESPACE;
+ endTagRequiresIndent = true;
+ }
+ stream.skip(1);
+ break;
+ }
+ case STATE_PI: {
+ if (stream.get(0) == '?' && stream.get(1) == '>') {
+ stream.skip(2);
+ state = STATE_WHITESPACE;
+ endTagRequiresIndent = true;
+ } else {
+ stream.skip(1);
+ }
+ break;
}
- }
- if (stream.get(0) != '\n' && stream.get(0) != '\r') {
- stream.skip();
- } else {
- stream.discard();
}
}
} catch (ArrayIndexOutOfBoundsException ex) {
Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java?rev=737796&r1=737795&r2=737796&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/test/java/org/apache/ws/commons/tcpmon/core/filter/XmlFormatFilterTest.java Mon Jan 26 19:33:48 2009
@@ -35,4 +35,14 @@
public void test3() {
assertFormat("<root>\n <a>test</a>\n</root>", "<root><a>test</a></root>");
}
+
+ public void test4() {
+ assertFormat("<root>\n <child>\n <a/>\n </child>\n</root>",
+ "<root><child><a/></child></root>");
+ }
+
+ public void test5() {
+ assertFormat("<root>\n <child>\n <a>test</a>\n </child>\n</root>",
+ "<root><child><a>test</a></child></root>");
+ }
}