Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : : *
5 : : * The contents of this file are subject to the Mozilla Public License Version
6 : : * 1.1 (the "License"); you may not use this file except in compliance with
7 : : * the License or as specified alternatively below. You may obtain a copy of
8 : : * the License at http://www.mozilla.org/MPL/
9 : : *
10 : : * Software distributed under the License is distributed on an "AS IS" basis,
11 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : : * for the specific language governing rights and limitations under the
13 : : * License.
14 : : *
15 : : * Major Contributor(s):
16 : : * Copyright (C) 2011 Lubos Lunak <l.lunak@suse.cz> (initial developer)
17 : : *
18 : : * All Rights Reserved.
19 : : *
20 : : * For minor contributions see the git repository.
21 : : *
22 : : * Alternatively, the contents of this file may be used under the terms of
23 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 : : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 : : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 : : * instead of those above.
27 : : */
28 : : #ifndef _STARMATHIMPORTUTILS_HXX
29 : : #define _STARMATHIMPORTUTILS_HXX
30 : :
31 : : #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
32 : : #include <oox/token/tokens.hxx>
33 : : #include <map>
34 : : #include <vector>
35 : :
36 : : #include <oox/dllapi.h>
37 : :
38 : : namespace oox
39 : : {
40 : :
41 : : namespace formulaimport
42 : : {
43 : :
44 : : // used to differentiate between tags that opening or closing
45 : : const int TAG_OPENING = 1 << 29;
46 : : const int TAG_CLOSING = 1 << 30;
47 : :
48 : : // you probably want to #define these to something shorter in the .cxx file,
49 : : // but they must be done as macros, otherwise they wouldn't be usable for case values,
50 : : // and macros cannot be namespaced
51 : : #define XML_STREAM_OPENING( token ) ( TAG_OPENING | token )
52 : : #define XML_STREAM_CLOSING( token ) ( TAG_CLOSING | token )
53 : :
54 : : /**
55 : : Class for storing a stream of xml tokens.
56 : :
57 : : A part of an XML file can be parsed and stored in this stream, from which it can be read
58 : : as if parsed linearly. The purpose of this class is to allow simpler handling of XML
59 : : files, unlike the usual LO way of using callbacks, context handlers and similar needlesly
60 : : complicated stuff (YMMV).
61 : :
62 : : The advantages of this approach is easy to read and debug code (as it is just functions
63 : : reading tokens one by one and calling other functions, compared to having to use callbacks
64 : : and temporary storage). The disadvantage is that the XML structure needs to be handled
65 : : manually by the code.
66 : :
67 : : Note that tag identifiers are simply int values and the API does not care besides matching
68 : : their values to XML stream contents and requiring that the values are not as high as TAG_OPENING.
69 : : Be prepared for the fact that some of the functions may throw exceptions if the input
70 : : stream does not match the required token (TBD).
71 : :
72 : : The API tries to make the common idioms as simple as possible, see the following examples.
73 : :
74 : : Parse <tagone attr="value"><tagtwo>text</tagtwo></tagone> , where tagtwo is optional:
75 : : @code
76 : : XmlStream::Tag tagoneTag = stream.ensureOpeningTag( tagone );
77 : : if( attributeTag.hasAttribute( attr ))
78 : : ... = attributeTag.attribute( attr, defaultValueOfTheRightType );
79 : : if( XmlStream::Tag tagtwoTag = stream.checkOpeningTag( tagtwo ))
80 : : {
81 : : ... = tagtwoTag.text;
82 : : stream.ensureClosingTag( tagtwo );
83 : : }
84 : : stream.ensureClosingTag( tagone );
85 : : @endcode
86 : :
87 : : Parse an element that may contain several sub-elements of different types in random order:
88 : : @code
89 : : stream.ensureOpeningTag( element );
90 : : while( !stream.atEnd() && stream.currentToken() != CLOSING( element ))
91 : : {
92 : : switch( stream.currentToken())
93 : : {
94 : : case OPENING( subelement1 ):
95 : : handleSubElement1();
96 : : break;
97 : : case OPENING( subelement2 ):
98 : : ... process subelement2;
99 : : break;
100 : : default:
101 : : stream.handleUnexpectedTag();
102 : : break;
103 : : }
104 : : stream.ensureClosingTag( element );
105 : : @endcode
106 : :
107 : : If there may not be a zero number of sub-elements, use a helper bool variable or use a do-while loop.
108 : :
109 : : Parse an element that may contain an unknown number of sub-elements of the same type:
110 : : @code
111 : : stream.ensureOpeningTag( element );
112 : : while( !stream.atEnd() && stream.findTag( OPENING( subelement )))
113 : : {
114 : : handleSubelement();
115 : : }
116 : : stream.ensureClosingTag( element );
117 : : @endcode
118 : :
119 : : If there may not be a zero number of sub-elements, use a helper bool variable or use a do-while loop.
120 : :
121 : : @since 3.5
122 : : */
123 : 939 : class OOX_DLLPUBLIC XmlStream
124 : : {
125 : : public:
126 : : XmlStream();
127 : : /**
128 : : Structure representing a list of attributes.
129 : : */
130 : : // One could theoretically use oox::AttributeList, but that complains if the passed reference is empty,
131 : : // which would be complicated to avoid here. Also, parsers apparently reuse the same instance of XFastAttributeList,
132 : : // which means using oox::AttributeList would make them all point to the one instance.
133 : 335304 : struct OOX_DLLPUBLIC AttributeList
134 : : {
135 : : bool hasAttribute( int token ) const;
136 : : OUString& operator[] (int token);
137 : : rtl::OUString attribute( int token, const rtl::OUString& def = rtl::OUString()) const;
138 : : bool attribute( int token, bool def ) const;
139 : : sal_Unicode attribute( int token, sal_Unicode def ) const;
140 : : // when adding more attribute() overloads, add also to XmlStream itself
141 : : protected:
142 : : std::map< int, rtl::OUString > attrs;
143 : : };
144 : : /**
145 : : Structure representing a tag, including its attributes and content text immediatelly following it.
146 : : */
147 : 247662 : struct OOX_DLLPUBLIC Tag
148 : : {
149 : : Tag( int token = XML_TOKEN_INVALID,
150 : : const com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >& attributes = com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >(),
151 : : const rtl::OUString& text = rtl::OUString());
152 : : Tag( int token,
153 : : const AttributeList& attribs);
154 : : int token; ///< tag type, or XML_TOKEN_INVALID
155 : : AttributeList attributes;
156 : : rtl::OUString text;
157 : : /**
158 : : This function returns value of the given attribute, or the passed default value if not found.
159 : : The type of the default value selects the return type (OUString here).
160 : : */
161 : : rtl::OUString attribute( int token, const rtl::OUString& def = rtl::OUString()) const;
162 : : /**
163 : : @overload
164 : : */
165 : : bool attribute( int token, bool def ) const;
166 : : /**
167 : : @overload
168 : : */
169 : : sal_Unicode attribute( int token, sal_Unicode def ) const;
170 : : // when adding more attribute() overloads, add also to XmlStream::AttributeList and inline below
171 : : /**
172 : : Converts to true if the tag has a valid token, false otherwise. Allows simple
173 : : usage in if(), for example 'if( XmlStream::Tag foo = stream.checkOpeningTag( footoken ))'.
174 : : */
175 : : operator bool() const;
176 : : };
177 : : /**
178 : : @return true if current position is at the end of the XML stream
179 : : */
180 : : bool atEnd() const;
181 : : /**
182 : : @return data about the current tag
183 : : */
184 : : Tag currentTag() const;
185 : : /**
186 : : @return the token for the current tag
187 : : */
188 : : int currentToken() const;
189 : : /**
190 : : Moves position to the next tag.
191 : : */
192 : : void moveToNextTag();
193 : : /**
194 : : Ensures that an opening tag with the given token is read. If the current tag does not match,
195 : : writes out a warning and tries to recover by skipping tags until found (or until the current element would end).
196 : : If found, the position in the stream is afterwards moved to the next tag.
197 : : @return the matching found opening tag, or empty tag if not found
198 : : */
199 : : Tag ensureOpeningTag( int token );
200 : : /**
201 : : Tries to find an opening tag with the given token. Works similarly like ensureOpeningTag(),
202 : : but if a matching tag is not found, the position in the stream is not altered. The primary
203 : : use of this function is to check for optional elements.
204 : : @return the matching found opening tag, or empty tag if not found
205 : : */
206 : : Tag checkOpeningTag( int token );
207 : : /**
208 : : Ensures that a closing tag with the given token is read. Like ensureOpeningTag(),
209 : : if not, writes out a warning and tries to recover by skiping tags until found (or until the current element would end).
210 : : If found, the position in the stream is afterwards moved to the next tag.
211 : : */
212 : : void ensureClosingTag( int token );
213 : : /**
214 : : Tries to find the given token, until either found (returns true) or end of current element.
215 : : Position in the stream is set to make the tag current (i.e. it will be the next one read).
216 : : */
217 : : bool findTag( int token );
218 : : /**
219 : : Handle the current (unexpected) tag.
220 : : */
221 : : void handleUnexpectedTag();
222 : : protected:
223 : : Tag checkTag( int token, bool optional );
224 : : bool findTagInternal( int token, bool silent );
225 : : void skipElementInternal( int token, bool silent );
226 : : std::vector< Tag > tags;
227 : : unsigned int pos;
228 : : };
229 : :
230 : : /**
231 : : This class is used for creating XmlStream.
232 : :
233 : : Simply use this class and then pass it as XmlStream to the consumer.
234 : :
235 : : @since 3.5.0
236 : : */
237 : 1704 : class OOX_DLLPUBLIC XmlStreamBuilder
238 : : : public XmlStream
239 : : {
240 : : public:
241 : : void appendOpeningTag( int token,
242 : : const com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >& attributes = com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >());
243 : : void appendOpeningTag( int token,
244 : : const AttributeList& attribs );
245 : : void appendClosingTag( int token );
246 : : // appends the characters after the last appended token
247 : : void appendCharacters( const rtl::OUString& characters );
248 : : };
249 : :
250 : : inline
251 : 3342 : rtl::OUString XmlStream::Tag::attribute( int t, const rtl::OUString& def ) const
252 : : {
253 : 3342 : return attributes.attribute( t, def );
254 : : }
255 : :
256 : : inline
257 : 60 : bool XmlStream::Tag::attribute( int t, bool def ) const
258 : : {
259 : 60 : return attributes.attribute( t, def );
260 : : }
261 : :
262 : : inline
263 : 234 : sal_Unicode XmlStream::Tag::attribute( int t, sal_Unicode def ) const
264 : : {
265 : 234 : return attributes.attribute( t, def );
266 : : }
267 : :
268 : : } // namespace
269 : : } // namespace
270 : :
271 : : #endif
272 : :
273 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|