1414import java .io .IOException ;
1515import java .io .OutputStream ;
1616import java .nio .charset .Charset ;
17- import java .util .Iterator ;
1817import java .util .List ;
1918import java .util .Vector ;
2019
@@ -26,6 +25,7 @@ public class AttlistDecl implements XMLNode {
2625 public AttlistDecl (String declaration ) {
2726 attributes = new Vector <>();
2827 int i = "<!ATTLIST" .length ();
28+ declaration = declaration .trim ();
2929 char c = declaration .charAt (i );
3030 while (XMLUtils .isXmlSpace (c )) {
3131 i ++;
@@ -38,44 +38,159 @@ public AttlistDecl(String declaration) {
3838 c = declaration .charAt (i );
3939 }
4040 listName = sb .toString ();
41- // TODO this. parseAttributes(declaration.substring(i).trim());
41+ parseAttributes (declaration .substring (i , declaration . lastIndexOf ( ">" ) ).trim ());
4242 }
4343
4444 private void parseAttributes (String declaration ) {
4545 int i = 0 ;
46- char c = declaration .charAt (i );
47- while (XMLUtils .isXmlSpace (c )) {
48- i ++;
49- c = declaration .charAt (i );
50- }
51- StringBuilder nameBuilder = new StringBuilder ();
52- while (!XMLUtils .isXmlSpace (c )) {
53- nameBuilder .append (c );
54- i ++;
55- c = declaration .charAt (i );
56- }
57- String name = nameBuilder .toString ();
58- while (XMLUtils .isXmlSpace (c )) {
59- i ++;
60- c = declaration .charAt (i );
61- }
62- StringBuilder typeBuilder = new StringBuilder ();
63- if (c == '(' ) {
64- // it is an ennumeration
65- while (c != ')' ) {
66- typeBuilder .append (c );
46+ while (i < declaration .length ()) {
47+ char c = declaration .charAt (i );
48+
49+ // Skip whitespace
50+ while (i < declaration .length () && XMLUtils .isXmlSpace (c )) {
6751 i ++;
68- c = declaration .charAt (i );
52+ if (i < declaration .length ()) {
53+ c = declaration .charAt (i );
54+ }
6955 }
70- typeBuilder .append (')' );
71- } else {
72- while (!XMLUtils .isXmlSpace (c ) || c == '(' ) {
73- typeBuilder .append (c );
56+
57+ // Parse attribute name
58+ StringBuilder nameBuilder = new StringBuilder ();
59+ while (i < declaration .length () && !XMLUtils .isXmlSpace (c )) {
60+ nameBuilder .append (c );
61+ i ++;
62+ if (i < declaration .length ()) {
63+ c = declaration .charAt (i );
64+ }
65+ }
66+ String name = nameBuilder .toString ();
67+
68+ if (name .startsWith ("%" ) && name .endsWith (";" )) {
69+ // It is a parameter entity reference
70+ AttributeDecl parameterEntity = new AttributeDecl (name , null , null , false );
71+ parameterEntity .setParameterEntity (true );
72+ attributes .add (parameterEntity );
73+ continue ;
74+ }
75+ // Skip whitespace
76+ while (i < declaration .length () && XMLUtils .isXmlSpace (c )) {
77+ i ++;
78+ if (i < declaration .length ()) {
79+ c = declaration .charAt (i );
80+ }
81+ }
82+
83+ // Parse attribute type, it can be:
84+ // StringType: 'CDATA'
85+ // TokenizedType: 'ID','IDREF','IDREFS','ENTITY','ENTITIES','NMTOKEN' or
86+ // 'NMTOKENS'
87+ // or an enumeration od string values
88+
89+ StringBuilder typeBuilder = new StringBuilder ();
90+ if (c == '(' ) {
91+ // It is an enumeration
92+ while (i < declaration .length () && c != ')' ) {
93+ typeBuilder .append (c );
94+ i ++;
95+ if (i < declaration .length ()) {
96+ c = declaration .charAt (i );
97+ }
98+ }
99+ if (c == ')' ) {
100+ typeBuilder .append (c );
101+ i ++;
102+ c = declaration .charAt (i );
103+ }
104+ } else {
105+ while (i < declaration .length () && !XMLUtils .isXmlSpace (c )) {
106+ typeBuilder .append (c );
107+ i ++;
108+ if (i < declaration .length ()) {
109+ c = declaration .charAt (i );
110+ }
111+ }
112+ }
113+ String type = typeBuilder .toString ();
114+
115+ // Skip whitespace
116+ while (i < declaration .length () && XMLUtils .isXmlSpace (c )) {
117+ i ++;
118+ if (i < declaration .length ()) {
119+ c = declaration .charAt (i );
120+ }
121+ }
122+
123+ // Parse defaultDecl section
124+ // DefaultDecl can be:
125+ // #IMPLIED, #REQUIRED, #FIXED or a quoted string
126+
127+ if (c == '#' ) {
128+ // Parse #IMPLIED, #REQUIRED, or #FIXED
129+ StringBuilder keywordBuilder = new StringBuilder ();
130+ while (i < declaration .length () && !XMLUtils .isXmlSpace (c )) {
131+ keywordBuilder .append (c );
132+ i ++;
133+ if (i < declaration .length ()) {
134+ c = declaration .charAt (i );
135+ }
136+ }
137+ String keyword = keywordBuilder .toString ();
138+ if ("#FIXED" .equals (keyword )) {
139+ StringBuilder defaultValueBuilder = new StringBuilder ();
140+
141+ // Skip whitespace after #FIXED
142+ while (i < declaration .length () && XMLUtils .isXmlSpace (c )) {
143+ i ++;
144+ if (i < declaration .length ()) {
145+ c = declaration .charAt (i );
146+ }
147+ }
148+
149+ // Parse the fixed default value
150+ if (c == '"' || c == '\'' ) {
151+ char quote = c ;
152+ i ++;
153+ if (i < declaration .length ()) {
154+ c = declaration .charAt (i );
155+ }
156+ while (i < declaration .length () && c != quote ) {
157+ defaultValueBuilder .append (c );
158+ i ++;
159+ if (i < declaration .length ()) {
160+ c = declaration .charAt (i );
161+ }
162+ }
163+ if (c == quote ) {
164+ i ++;
165+ }
166+ } else {
167+ throw new IllegalArgumentException ("Expected quoted default value after #FIXED." );
168+ }
169+ attributes .add (new AttributeDecl (name , type , defaultValueBuilder .toString (), true ));
170+ } else {
171+ attributes .add (new AttributeDecl (name , type , keyword , false ));
172+ }
173+ } else if (c == '"' || c == '\'' ) {
174+ StringBuilder defaultValueBuilder = new StringBuilder ();
175+ // Default value is quoted
176+ char quote = c ;
74177 i ++;
75- c = declaration .charAt (i );
178+ if (i < declaration .length ()) {
179+ c = declaration .charAt (i );
180+ }
181+ while (i < declaration .length () && c != quote ) {
182+ defaultValueBuilder .append (c );
183+ i ++;
184+ if (i < declaration .length ()) {
185+ c = declaration .charAt (i );
186+ }
187+ }
188+ if (c == quote ) {
189+ i ++;
190+ }
191+ attributes .add (new AttributeDecl (name , type , defaultValueBuilder .toString (), false ));
76192 }
77193 }
78- String type = typeBuilder .toString ();
79194 }
80195
81196 public String getListName () {
@@ -93,18 +208,17 @@ public short getNodeType() {
93208
94209 @ Override
95210 public String toString () {
96- StringBuilder sb = new StringBuilder ("<!ATTLIST" );
97- Iterator <AttributeDecl > it = attributes .iterator ();
98- while (it .hasNext ()) {
99- sb .append ("\n " );
100- sb .append (it .next ().toString ());
211+ StringBuilder sb = new StringBuilder ("<!ATTLIST " );
212+ sb .append (listName );
213+ for (AttributeDecl attr : attributes ) {
214+ sb .append ("\n " ).append (attr .toString ());
101215 }
102- sb .append ("\n >\n " );
216+ sb .append ("\n >" );
103217 return sb .toString ();
104218 }
105219
106220 @ Override
107221 public void writeBytes (OutputStream output , Charset charset ) throws IOException {
108222 output .write (toString ().getBytes (charset ));
109223 }
110- }
224+ }
0 commit comments