LibreOffice Module xmloff (master) 1
SchemaRestrictionContext.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
22#include "xformsapi.hxx"
23
24#include <utility>
25#include <xmloff/xmltoken.hxx>
28#include <xmloff/xmltkmap.hxx>
29#include <xmloff/xmlimp.hxx>
30
32
33#include <com/sun/star/beans/XPropertySet.hpp>
34#include <com/sun/star/util/Date.hpp>
35#include <com/sun/star/util/Time.hpp>
36#include <com/sun/star/util/DateTime.hpp>
37#include <com/sun/star/util/Duration.hpp>
38#include <com/sun/star/xforms/XDataTypeRepository.hpp>
39#include <com/sun/star/xsd/DataTypeClass.hpp>
40#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
41
42#include <o3tl/string_view.hxx>
43#include <sal/log.hxx>
45
46
48using com::sun::star::uno::Exception;
49using com::sun::star::uno::Any;
50using namespace com::sun::star;
51using com::sun::star::util::Duration;
52using com::sun::star::xml::sax::XFastAttributeList;
53using com::sun::star::xforms::XDataTypeRepository;
54using namespace xmloff::token;
55
56
58 SvXMLImport& rImport,
60 OUString sTypeName ) :
61 TokenContext( rImport ),
62 mxRepository( rRepository ),
63 msTypeName(std::move( sTypeName ))
64{
65 SAL_WARN_IF( !mxRepository.is(), "xmloff", "need repository" );
66}
67
69{
70 // only do something if we don't have a data type already
71 if( mxDataType.is() )
72 return;
73
74 SAL_WARN_IF( msBaseName.isEmpty(), "xmloff", "no base name?" );
75 SAL_WARN_IF( !mxRepository.is(), "xmloff", "no repository?" );
76
77 try
78 {
80 mxRepository->cloneDataType(
82 GetImport().GetNamespaceMap(),
83 msBaseName ),
84 msTypeName );
85 }
86 catch( const Exception& )
87 {
88 TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation");
89 }
90 SAL_WARN_IF( !mxDataType.is(), "xmloff", "can't create type" );
91}
92
94{
95 switch (aIter.getToken() & TOKEN_MASK)
96 {
97 case XML_BASE:
98 msBaseName = aIter.toString();
99 break;
100 }
101}
102
103typedef Any (*convert_t)( const OUString& );
104
105static Any xforms_string( const OUString& rValue )
106{
107 return Any( rValue );
108}
109
110static Any xforms_int32( const OUString& rValue )
111{
112 sal_Int32 nValue;
113 bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
114 return bSuccess ? Any( nValue ) : Any();
115}
116
117static Any xforms_int16( const OUString& rValue )
118{
119 sal_Int32 nValue;
120 bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
121 return bSuccess ? Any( static_cast<sal_Int16>( nValue ) ) : Any();
122}
123
124static Any xforms_whitespace( const OUString& rValue )
125{
126 Any aValue;
127 if( IsXMLToken( rValue, XML_PRESERVE ) )
128 aValue <<= css::xsd::WhiteSpaceTreatment::Preserve;
129 else if( IsXMLToken( rValue, XML_REPLACE ) )
130 aValue <<= css::xsd::WhiteSpaceTreatment::Replace;
131 else if( IsXMLToken( rValue, XML_COLLAPSE ) )
132 aValue <<= css::xsd::WhiteSpaceTreatment::Collapse;
133 return aValue;
134}
135
136static Any xforms_double( const OUString& rValue )
137{
138 double fValue;
139 bool bSuccess = ::sax::Converter::convertDouble( fValue, rValue );
140 return bSuccess ? Any( fValue ) : Any();
141}
142
143static Any xforms_date( const OUString& rValue )
144{
145 Any aAny;
146
147 // parse ISO date
148 sal_Int32 nPos1 = rValue.indexOf( '-' );
149 sal_Int32 nPos2 = rValue.indexOf( '-', nPos1 + 1 );
150 if( nPos1 > 0 && nPos2 > 0 )
151 {
152 util::Date aDate;
153 aDate.Year = static_cast<sal_uInt16>(
154 o3tl::toInt32(rValue.subView( 0, nPos1 )) );
155 aDate.Month = static_cast<sal_uInt16>(
156 o3tl::toInt32(rValue.subView( nPos1 + 1, nPos2 - nPos1 - 1 )) );
157 aDate.Day = static_cast<sal_uInt16>(
158 o3tl::toInt32(rValue.subView( nPos2 + 1 )) );
159 aAny <<= aDate;
160 }
161 return aAny;
162}
163
164static Any xforms_dateTime( const OUString& rValue )
165{
166 util::DateTime aDateTime;
167 bool const bSuccess = ::sax::Converter::parseDateTime(aDateTime, rValue);
168 return bSuccess ? Any( aDateTime ) : Any();
169}
170
171static Any xforms_time( const OUString& rValue )
172{
173 Any aAny;
174 Duration aDuration;
175 if (::sax::Converter::convertDuration( aDuration, rValue ))
176 {
177 css::util::Time aTime;
178 aTime.Hours = aDuration.Hours;
179 aTime.Minutes = aDuration.Minutes;
180 aTime.Seconds = aDuration.Seconds;
181 aTime.NanoSeconds = aDuration.NanoSeconds;
182 aAny <<= aTime;
183 }
184 return aAny;
185}
186
187
189 sal_Int32 nElementToken,
190 const Reference<XFastAttributeList>& xAttrList )
191{
192 // find value
193 OUString sValue;
194 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
195 {
196 if( ( aIter.getToken() & TOKEN_MASK) == XML_VALUE )
197 {
198 sValue = aIter.toString();
199 break;
200 }
201 }
202
203 // determine property name + suitable converter
204 OUString sPropertyName;
205 convert_t pConvert = nullptr;
206 switch( nElementToken & TOKEN_MASK )
207 {
208 case XML_LENGTH:
209 sPropertyName = "Length";
210 pConvert = &xforms_int32;
211 break;
212 case XML_MINLENGTH:
213 sPropertyName = "MinLength";
214 pConvert = &xforms_int32;
215 break;
216 case XML_MAXLENGTH:
217 sPropertyName = "MaxLength";
218 pConvert = &xforms_int32;
219 break;
220 case XML_TOTALDIGITS:
221 sPropertyName = "TotalDigits";
222 pConvert = &xforms_int32;
223 break;
225 sPropertyName = "FractionDigits";
226 pConvert = &xforms_int32;
227 break;
228 case XML_PATTERN:
229 sPropertyName = "Pattern";
230 pConvert = &xforms_string;
231 break;
232 case XML_WHITESPACE:
233 sPropertyName = "WhiteSpace";
234 pConvert = &xforms_whitespace;
235 break;
236 case XML_MININCLUSIVE:
237 case XML_MINEXCLUSIVE:
238 case XML_MAXINCLUSIVE:
239 case XML_MAXEXCLUSIVE:
240 {
241 // these attributes are mapped to different properties.
242 // To determine the property name, we use an attribute
243 // dependent prefix and a type dependent suffix. The
244 // converter is only type dependent.
245
246 // first, attribute-dependent prefix
247 switch( nElementToken & TOKEN_MASK )
248 {
249 case XML_MININCLUSIVE:
250 sPropertyName = "MinInclusive";
251 break;
252 case XML_MINEXCLUSIVE:
253 sPropertyName = "MinExclusive";
254 break;
255 case XML_MAXINCLUSIVE:
256 sPropertyName = "MaxInclusive";
257 break;
258 case XML_MAXEXCLUSIVE:
259 sPropertyName = "MaxExclusive";
260 break;
261 }
262
263 // second, type-dependent suffix + converter
265 GetImport().GetNamespaceMap(),
266 msBaseName ) )
267 {
268 case css::xsd::DataTypeClass::DECIMAL:
269 case css::xsd::DataTypeClass::DOUBLE:
270 case css::xsd::DataTypeClass::FLOAT:
271 sPropertyName += "Double";
272 pConvert = &xforms_double;
273 break;
274 case css::xsd::DataTypeClass::DATETIME:
275 sPropertyName += "DateTime";
276 pConvert = &xforms_dateTime;
277 break;
278 case css::xsd::DataTypeClass::DATE:
279 sPropertyName += "Date";
280 pConvert = &xforms_date;
281 break;
282 case css::xsd::DataTypeClass::TIME:
283 sPropertyName += "Time";
284 pConvert = &xforms_time;
285 break;
286 case css::xsd::DataTypeClass::gYear:
287 case css::xsd::DataTypeClass::gDay:
288 case css::xsd::DataTypeClass::gMonth:
289 sPropertyName += "Int";
290 pConvert = &xforms_int16;
291 break;
292
293 case css::xsd::DataTypeClass::STRING:
294 case css::xsd::DataTypeClass::anyURI:
295 case css::xsd::DataTypeClass::BOOLEAN:
296 // invalid: These shouldn't have min/max-inclusive
297 break;
298
299 /* data types not yet supported:
300 case css::xsd::DataTypeClass::DURATION:
301 case css::xsd::DataTypeClass::gYearMonth:
302 case css::xsd::DataTypeClass::gMonthDay:
303 case css::xsd::DataTypeClass::hexBinary:
304 case css::xsd::DataTypeClass::base64Binary:
305 case css::xsd::DataTypeClass::QName:
306 case css::xsd::DataTypeClass::NOTATION:
307 */
308 }
309 }
310 break;
311
312 default:
313 OSL_FAIL( "unknown facet" );
314 }
315
316 // finally, set the property
318 if( mxDataType.is()
319 && !sPropertyName.isEmpty()
320 && pConvert != nullptr
321 && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) )
322 {
323 try
324 {
325 mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) );
326 }
327 catch( const Exception& )
328 {
329 ; // can't set property? Then ignore.
330 }
331 }
332
333 return new SvXMLImportContext( GetImport() );
334}
335
336/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static Any xforms_dateTime(const OUString &rValue)
static Any xforms_int32(const OUString &rValue)
static Any xforms_string(const OUString &rValue)
static Any xforms_int16(const OUString &rValue)
static Any xforms_date(const OUString &rValue)
static Any xforms_whitespace(const OUString &rValue)
static Any xforms_time(const OUString &rValue)
Any(* convert_t)(const OUString &)
static Any xforms_double(const OUString &rValue)
SchemaRestrictionContext(SvXMLImport &rImport, css::uno::Reference< css::xforms::XDataTypeRepository > const &rRepository, OUString sTypeName)
css::uno::Reference< css::beans::XPropertySet > mxDataType
virtual SvXMLImportContext * HandleChild(sal_Int32 nElementToken, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
will be called for each child element
css::uno::Reference< css::xforms::XDataTypeRepository > mxRepository
virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &aIter) override
will be called for each attribute
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:60
SvXMLImportContext(SvXMLImport &rImport)
A contexts constructor does anything that is required if an element starts.
Definition: xmlictxt.cxx:30
handle attributes through an SvXMLTokenMap
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
static void convertDuration(OUStringBuffer &rBuffer, const double fTime)
static bool parseDateTime(css::util::DateTime &rDateTime, std::u16string_view rString)
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
#define TOOLS_WARN_EXCEPTION(area, stream)
sal_Int16 nValue
#define SAL_WARN_IF(condition, area, stream)
@ Exception
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
Handling of tokens in XML:
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3597
sal_uInt16 xforms_getTypeClass(const Reference< XDataTypeRepository > &xRepository, const SvXMLNamespaceMap &rNamespaceMap, const OUString &rXMLName)
Definition: xformsapi.cxx:190
OUString xforms_getBasicTypeName(const Reference< XDataTypeRepository > &xRepository, const SvXMLNamespaceMap &rNamespaceMap, const OUString &rXMLName)
Definition: xformsapi.cxx:275
constexpr sal_Int32 TOKEN_MASK
Definition: xmlimp.hxx:94