1 #include "XmlUniformiser.h"
2 
3 
4 int
notEqualIndex(std::string expectedXml,std::string actualXml)5 notEqualIndex( std::string expectedXml,
6                std::string actualXml )
7 {
8   unsigned int index = 0;
9   while ( index < actualXml.length()  &&
10           index < expectedXml.length()  &&
11           actualXml[index] == expectedXml[index] )
12     ++index;
13 
14   return index;
15 }
16 
17 
18 /// Asserts that two XML string are equivalent.
19 void
checkXmlEqual(std::string expectedXml,std::string actualXml,CPPUNIT_NS::SourceLine sourceLine)20 checkXmlEqual( std::string expectedXml,
21                std::string actualXml,
22                CPPUNIT_NS::SourceLine sourceLine )
23 {
24   std::string expected = XmlUniformiser( expectedXml ).stripped();
25   std::string actual = XmlUniformiser( actualXml ).stripped();
26 
27   if ( expected == actual )
28     return;
29 
30   int index = notEqualIndex( expected, actual );
31   CPPUNIT_NS::OStringStream message;
32   message  <<  "differ at index: "  <<  index  << "\n"
33            <<  "expected: "  <<  expected.substr(index) << "\n"
34            <<  "but was : "  <<  actual.substr( index );
35   CPPUNIT_NS::Asserter::failNotEqual( expected,
36                                       actual,
37                                       sourceLine,
38                                       message.str() );
39 }
40 
41 
42 
XmlUniformiser(const std::string & xml)43 XmlUniformiser::XmlUniformiser( const std::string &xml ) :
44     m_index( 0 ),
45     m_xml( xml )
46 {
47 }
48 
49 
50 std::string
stripped()51 XmlUniformiser::stripped()
52 {
53   while ( isValidIndex() )
54   {
55     skipSpaces();
56     if ( startsWith( "<?" ) )
57       skipProcessed();
58     else if ( startsWith( "<!--" ) )
59       skipComment();
60     else if ( startsWith( "<" ) )
61       copyElement();
62     else
63       copyElementContent();
64   }
65   return m_stripped;
66 }
67 
68 
69 void
skipSpaces()70 XmlUniformiser::skipSpaces()
71 {
72   while ( isSpace() )
73     skipNext();
74 }
75 
76 
77 bool
isSpace(char c)78 XmlUniformiser::isSpace( char c )
79 {
80   return c < 33;
81 }
82 
83 
84 bool
isSpace()85 XmlUniformiser::isSpace()
86 {
87   return isValidIndex()  &&  isSpace( m_xml[m_index] );
88 }
89 
90 
91 bool
isValidIndex()92 XmlUniformiser::isValidIndex()
93 {
94   return m_index < m_xml.length();
95 }
96 
97 
98 void
skipNext(int count)99 XmlUniformiser::skipNext( int count )
100 {
101   while ( count-- > 0 )
102     ++m_index;
103 }
104 
105 
106 void
copyNext(int count)107 XmlUniformiser::copyNext( int count )
108 {
109   while ( count-- > 0  &&  isValidIndex() )
110     m_stripped += m_xml[ m_index++ ];
111 }
112 
113 
114 bool
startsWith(std::string expected)115 XmlUniformiser::startsWith( std::string expected )
116 {
117   std::string actual = m_xml.substr( m_index, expected.length() );
118   return actual == expected;
119 }
120 
121 
122 void
skipProcessed()123 XmlUniformiser::skipProcessed()
124 {
125   while ( isValidIndex()  &&  !startsWith( "?>" ) )
126     skipNext();
127   if ( isValidIndex() )
128     skipNext( 2 );
129 }
130 
131 
132 void
skipComment()133 XmlUniformiser::skipComment()
134 {
135   while ( isValidIndex()  &&  !startsWith( "-->" ) )
136     skipNext();
137   if ( isValidIndex() )
138     skipNext( 3 );
139 }
140 
141 
142 void
copyElement()143 XmlUniformiser::copyElement()
144 {
145   copyElementName();
146   copyElementAttributes();
147 }
148 
149 
150 void
copyElementName()151 XmlUniformiser::copyElementName()
152 {
153   while ( isValidIndex()  &&
154           !( isSpace()  ||  startsWith( ">" ) ) )
155     copyNext();
156 }
157 
158 
159 void
copyElementAttributes()160 XmlUniformiser::copyElementAttributes()
161 {
162   do
163   {
164     bool hadSpace = isSpace();
165     skipSpaces();
166     if ( startsWith( ">" ) )
167       break;
168 
169     if ( hadSpace )
170       m_stripped += ' ';
171 
172     copyAttributeName();
173     skipSpaces();
174     if ( startsWith( "=" ) )
175     {
176       copyNext();
177       copyAttributeValue();
178     }
179     else    // attribute should always be valued, ne ?
180       m_stripped += ' ';
181   }
182   while ( isValidIndex() );
183   copyNext();
184 }
185 
186 
187 void
copyAttributeName()188 XmlUniformiser::copyAttributeName()
189 {
190   while ( isValidIndex()  &&  !isEndOfAttributeName() )
191     copyNext();
192 }
193 
194 
195 bool
isEndOfAttributeName()196 XmlUniformiser::isEndOfAttributeName()
197 {
198   return isSpace()  ||  startsWith( ">" )  ||  startsWith( "=" );
199 }
200 
201 
202 void
copyAttributeValue()203 XmlUniformiser::copyAttributeValue()
204 {
205   skipSpaces();
206   copyUntilDoubleQuote();
207   copyUntilDoubleQuote();
208 }
209 
210 
211 void
copyUntilDoubleQuote()212 XmlUniformiser::copyUntilDoubleQuote()
213 {
214   while ( isValidIndex()  &&  !startsWith("\"") )
215     copyNext();
216   copyNext();   // '"'
217 }
218 
219 
220 void
copyElementContent()221 XmlUniformiser::copyElementContent()
222 {
223   while ( isValidIndex()  &&  !startsWith( "<" ) )
224     copyNext();
225   removeTrailingSpaces();
226 }
227 
228 
229 void
removeTrailingSpaces()230 XmlUniformiser::removeTrailingSpaces()
231 {
232   int index = m_stripped.length();
233   while ( index-1 > 0  &&  isSpace( m_stripped[index-1] ) )
234     --index;
235   m_stripped.resize( index );
236 }
237