textwolf  0.2
xmlpathautomatonparse.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Patrick P. Frey
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  */
10 
11 #ifndef __TEXTWOLF_XML_PATH_AUTOMATON_PARSE_HPP__
12 #define __TEXTWOLF_XML_PATH_AUTOMATON_PARSE_HPP__
14 #include "textwolf/charset.hpp"
16 #include <limits>
17 #include <string>
18 #include <vector>
19 #include <cstring>
20 #include <cstddef>
21 #include <stdexcept>
22 
23 namespace textwolf {
24 
29 template <class SrcCharSet=charset::UTF8, class AtmCharSet=charset::UTF8>
31 {
32 public:
34  typedef typename ThisAutomaton::PathElement PathElement;
37 
38 public:
42 
43  int addExpression( int typeidx, const char* esrc, std::size_t esrcsize)
44  {
45  std::string idstrings;
46  CStringIterator pitr( esrc, esrcsize);
47  SrcScanner pp( m_srccharset, pitr);
48  std::vector<std::size_t> idref;
49  std::size_t id;
50 
51  char const* xx = (char const*)std::memchr( esrc, ':', esrcsize);
52  while (xx)
53  {
54  std::size_t xpos = xx - esrc;
55  if (xpos + 1 < esrcsize && xx[1] == ':')
56  {
57  return xpos+1;
58  }
59  xx = (char const*)std::memchr( xx+1, ':', esrcsize - (xpos+1));
60  }
61  for (; *pp; skipSpaces( pp))
62  {
63  switch (*pp)
64  {
65  case '/':
66  case '*':
67  case '@':
68  case '~':
69  case '=':
70  case '[':
71  case ']':
72  case ',':
73  ++pp;
74  continue;
75  case '"':
76  case '\'':
77  id = parseValue( pp, idstrings);
78  idref.push_back( id);
79  continue;
80  case '(':
81  while (*pp != 0 && *pp != ')') pp++;
82  if (*pp == 0) return pp.getPosition()+1;
83  ++pp;
84  continue;
85  default:
86  if (pp.control() == Undef || pp.control() == Any)
87  {
88  id = parseIdentifier( pp, idstrings);
89  idref.push_back( id);
90  }
91  else
92  {
93  return pp.getPosition()+1;
94  }
95  }
96  }
97  typename std::vector<std::size_t>::const_iterator di = idref.begin(), de = idref.end();
98 
99  CStringIterator itr( esrc, esrcsize);
100  SrcScanner src( m_srccharset, itr);
101  PathElement expr( this);
102  for (; *src; skipSpaces( src))
103  {
104  switch (*src)
105  {
106  case '@':
107  {
108  if (di == de) return src.getPosition()+1;
109  ++src;
110  skipIdentifier( src);
111  expr.selectAttribute( getIdentifier( *di++, idstrings));
112  continue;
113  }
114  case '/':
115  {
116  ++src;
117  if (*src == '/')
118  {
119  expr --;
120  ++src;
121  if (*src == '@')
122  {
123  ++src;
124  if (*src == '*')
125  {
126  ++src;
127  expr.selectAttribute( 0);
128  }
129  else
130  {
131  if (di == de) return src.getPosition()+1;
132  skipIdentifier( src);
133  expr.selectAttribute( getIdentifier( *di++, idstrings));
134  }
135  }
136  else if (*src == '(')
137  {
138  continue;
139  }
140  else
141  {
142  if (*src == '*')
143  {
144  ++src;
145  expr.selectTag( 0);
146  }
147  else
148  {
149  if (di == de) return src.getPosition()+1;
150  skipIdentifier( src);
151  expr.selectTag( getIdentifier( *di++, idstrings));
152  }
153  }
154  }
155  else
156  {
157  if (*src == '@')
158  {
159  ++src;
160  if (*src == '*')
161  {
162  ++src;
163  expr.selectAttribute( 0);
164  }
165  else
166  {
167  if (di == de) return src.getPosition()+1;
168  skipIdentifier( src);
169  expr.selectAttribute( getIdentifier( *di++, idstrings));
170  }
171  }
172  else if (*src == '(')
173  {
174  continue;
175  }
176  else
177  {
178  if (*src == '*')
179  {
180  ++src;
181  expr.selectTag( 0);
182  }
183  else
184  {
185  if (di == de) return src.getPosition()+1;
186  skipIdentifier( src);
187  expr.selectTag( getIdentifier( *di++, idstrings));
188  }
189  }
190  }
191  continue;
192  }
193  case '~':
194  {
195  ++src;
196  expr.selectCloseTag();
197  continue;
198  }
199  case '[':
200  {
201  ++src; skipSpaces( src);
202  if (*src == '@')
203  {
204  ++src; skipSpaces( src);
205  // Attribute condition:
206  skipIdentifier( src);
207  skipSpaces( src);
208  if (di == de) return src.getPosition()+1;
209  const char* attrname = getIdentifier( *di++, idstrings);
210  if (*src != '=') return src.getPosition()+1;
211  ++src; skipSpaces( src);
212  skipValue( src);
213  skipSpaces( src);
214  const char* attrval = getIdentifier( *di++, idstrings);
215  if (*src != ']') return src.getPosition()+1;
216  expr.ifAttribute( attrname, attrval);
217  ++src;
218  }
219  else
220  {
221  // Range
222  skipIdentifier( src);
223  skipSpaces( src);
224  if (di == de) return src.getPosition()+1;
225  const char* range_start_str = getIdentifier( *di++, idstrings);
226  int range_start = parseNum( range_start_str);
227  if (range_start < 0 || range_start_str[0]) return src.getPosition()+1;
228 
229  if (*src == ',')
230  {
231  ++src; skipSpaces( src);
232  if (*src == ']')
233  {
234  expr.FROM( range_start);
235  ++src;
236  }
237  else
238  {
239  skipIdentifier( src);
240  skipSpaces( src);
241  if (di == de) return src.getPosition()+1;
242  const char* range_end_str = getIdentifier( *di++, idstrings);
243  int range_end = parseNum( range_end_str);
244  if (range_end < 0 || range_end_str[0]) return src.getPosition()+1;
245  ++src; skipSpaces( src);
246  if (*src != ']') return src.getPosition()+1;
247  expr.RANGE( range_start, range_end);
248  ++src;
249  }
250  }
251  else if (*src == ']')
252  {
253  expr.INDEX( range_start);
254  ++src;
255  }
256  else
257  {
258  return src.getPosition()+1;
259  }
260  }
261  continue;
262  }
263  case '(':
264  ++src;
265  skipSpaces( src);
266  if (*src != ')') return src.getPosition()+1;
267  ++src;
268  expr.selectContent();
269  skipSpaces( src);
270  if (*src) return src.getPosition()+1;
271  continue;
272 
273  default:
274  return src.getPosition()+1;
275  }
276  }
277  expr.assignType( typeidx);
278  return 0;
279  }
280 
281 private:
282  static void skipSpaces( SrcScanner& src)
283  {
284  for (; src.control() == Space; ++src);
285  }
286 
287  static int parseNum( char const*& src)
288  {
289  std::string num;
290  for (; *src>='0' && *src<='9';++src) num.push_back( *src);
291  if (num.size() == 0 || num.size() > 8) return -1;
292  return std::atoi( num.c_str());
293  }
294 
295  static bool isIdentifierChar( SrcScanner& src)
296  {
297  if (src.control() == Undef || src.control() == Any)
298  {
299  if (*src == (unsigned char)'*') return false;
300  if (*src == (unsigned char)'~') return false;
301  if (*src == (unsigned char)'/') return false;
302  if (*src == (unsigned char)'(') return false;
303  if (*src == (unsigned char)')') return false;
304  if (*src == (unsigned char)'@') return false;
305  return true;
306  }
307  return false;
308  }
309 
310  std::size_t parseIdentifier( SrcScanner& src, std::string& idstrings)
311  {
312  std::size_t rt = idstrings.size();
313  for (; isIdentifierChar(src); ++src)
314  {
315  m_atmcharset.print( *src, idstrings);
316  }
317  m_atmcharset.print( 0, idstrings);
318  return rt;
319  }
320 
321  std::size_t parseValue( SrcScanner& src, std::string& idstrings)
322  {
323  std::size_t rt = idstrings.size();
324  if (*src == '"' || *src == '\'')
325  {
326  unsigned char eb = *src;
327  for (++src; *src && *src != eb; ++src)
328  {
329  m_atmcharset.print( *src, idstrings);
330  }
331  if (*src) ++src;
332  }
333  else
334  {
335  for (; isIdentifierChar(src); ++src)
336  {
337  m_atmcharset.print( *src, idstrings);
338  }
339  }
340  m_atmcharset.print( 0, idstrings);
341  return rt;
342  }
343 
344  static void skipIdentifier( SrcScanner& src)
345  {
346  for (; isIdentifierChar(src); ++src){}
347  }
348 
349  static void skipValue( SrcScanner& src)
350  {
351  if (*src == '"' || *src == '\'')
352  {
353  unsigned char eb = *src;
354  for (++src; *src && *src != eb; ++src){}
355  if (*src) ++src;
356  }
357  else
358  {
359  for (; isIdentifierChar(src); ++src){}
360  }
361  }
362 
363  const char* getIdentifier( std::size_t idx, const std::string& idstrings) const
364  {
365  return idstrings.c_str() + idx;
366  }
367 
368 private:
369  AtmCharSet m_atmcharset;
370  SrcCharSet m_srccharset;
371 };
372 
373 } //namespace
374 #endif
XMLPathSelectAutomaton< AtmCharSet > ThisAutomaton
Definition: xmlpathautomatonparse.hpp:33
Definition: char.hpp:80
ControlCharacter control()
Get the control character representation of the current character.
Definition: textscanner.hpp:218
virtual ~XMLPathSelectAutomatonParser()
Definition: xmlpathautomatonparse.hpp:41
Definition: char.hpp:84
std::size_t getPosition() const
Get the current source iterator position.
Definition: textscanner.hpp:154
Definition: char.hpp:97
Reader for scanning the input character by character.
Definition: textscanner.hpp:68
Input iterator on a constant string returning null characters after EOF as required by textwolf scann...
Definition: cstringiterator.hpp:23
XMLPathSelectAutomatonParser()
Constructor.
Definition: xmlpathautomatonparse.hpp:40
textwolf iterator on strings
Automaton to select path expressions from an XML iterator.
ThisAutomaton::PathElement PathElement
Definition: xmlpathautomatonparse.hpp:34
Automaton to define XML path expressions and assign types (int values) to them.
Definition: xmlpathautomatonparse.hpp:30
XMLPathSelectAutomatonParser This
Definition: xmlpathautomatonparse.hpp:35
int addExpression(int typeidx, const char *esrc, std::size_t esrcsize)
Definition: xmlpathautomatonparse.hpp:43
TextScanner< CStringIterator, SrcCharSet > SrcScanner
Definition: xmlpathautomatonparse.hpp:36
Automaton to define XML path expressions and assign types (int values) to them.
Definition: xmlpathautomaton.hpp:32
Character set encodings already implemented in textwolf.