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 <xmloff/xmltoken.hxx>
25 #include <xmloff/namespacemap.hxx>
26 #include <xmloff/xmlnamespace.hxx>
27 #include <xmloff/xmltkmap.hxx>
28 #include <xmloff/xmlimp.hxx>
29 
30 #include <sax/tools/converter.hxx>
31 
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/util/Date.hpp>
34 #include <com/sun/star/util/Time.hpp>
35 #include <com/sun/star/util/DateTime.hpp>
36 #include <com/sun/star/util/Duration.hpp>
37 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
38 #include <com/sun/star/xsd/DataTypeClass.hpp>
39 #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
40 
41 #include <osl/diagnose.h>
42 #include <sal/log.hxx>
43 
44 
46 using com::sun::star::uno::Exception;
47 using com::sun::star::uno::Any;
49 using namespace com::sun::star;
50 using com::sun::star::util::Duration;
51 using com::sun::star::xml::sax::XAttributeList;
52 using com::sun::star::xforms::XDataTypeRepository;
53 using namespace xmloff::token;
54 
55 
57 {
60 };
61 
63 {
64  TOKEN_MAP_ENTRY( XSD, LENGTH ),
65  TOKEN_MAP_ENTRY( XSD, MINLENGTH ),
66  TOKEN_MAP_ENTRY( XSD, MAXLENGTH ),
67  TOKEN_MAP_ENTRY( XSD, MININCLUSIVE ),
68  TOKEN_MAP_ENTRY( XSD, MINEXCLUSIVE ),
69  TOKEN_MAP_ENTRY( XSD, MAXINCLUSIVE ),
70  TOKEN_MAP_ENTRY( XSD, MAXEXCLUSIVE ),
71  TOKEN_MAP_ENTRY( XSD, PATTERN ),
72  // ??? XML_ENUMERATION
73  TOKEN_MAP_ENTRY( XSD, WHITESPACE ),
74  TOKEN_MAP_ENTRY( XSD, TOTALDIGITS ),
75  TOKEN_MAP_ENTRY( XSD, FRACTIONDIGITS ),
77 };
78 
79 
81  SvXMLImport& rImport,
82  sal_uInt16 nPrefix,
83  const OUString& rLocalName,
85  const OUString& sTypeName ) :
86  TokenContext( rImport, nPrefix, rLocalName, aAttributes, aChildren ),
87  mxRepository( rRepository ),
88  msTypeName( sTypeName ),
89  msBaseName()
90 {
91  SAL_WARN_IF( !mxRepository.is(), "xmloff", "need repository" );
92 }
93 
95 {
96  // only do something if we don't have a data type already
97  if( mxDataType.is() )
98  return;
99 
100  SAL_WARN_IF( msBaseName.isEmpty(), "xmloff", "no base name?" );
101  SAL_WARN_IF( !mxRepository.is(), "xmloff", "no repository?" );
102 
103  try
104  {
105  mxDataType =
106  mxRepository->cloneDataType(
108  GetImport().GetNamespaceMap(),
109  msBaseName ),
110  msTypeName );
111  }
112  catch( const Exception& )
113  {
114  OSL_FAIL( "exception during type creation" );
115  }
116  SAL_WARN_IF( !mxDataType.is(), "xmloff", "can't create type" );
117 }
118 
120  sal_uInt16 nToken,
121  const OUString& rValue )
122 {
123  if( nToken == XML_BASE )
124  {
125  msBaseName = rValue;
126  }
127 }
128 
129 typedef Any (*convert_t)( const OUString& );
130 
131 static Any xforms_string( const OUString& rValue )
132 {
133  return makeAny( rValue );
134 }
135 
136 static Any xforms_int32( const OUString& rValue )
137 {
138  sal_Int32 nValue;
139  bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
140  return bSuccess ? makeAny( nValue ) : Any();
141 }
142 
143 static Any xforms_int16( const OUString& rValue )
144 {
145  sal_Int32 nValue;
146  bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
147  return bSuccess ? makeAny( static_cast<sal_Int16>( nValue ) ) : Any();
148 }
149 
150 static Any xforms_whitespace( const OUString& rValue )
151 {
152  Any aValue;
153  if( IsXMLToken( rValue, XML_PRESERVE ) )
154  aValue <<= css::xsd::WhiteSpaceTreatment::Preserve;
155  else if( IsXMLToken( rValue, XML_REPLACE ) )
156  aValue <<= css::xsd::WhiteSpaceTreatment::Replace;
157  else if( IsXMLToken( rValue, XML_COLLAPSE ) )
158  aValue <<= css::xsd::WhiteSpaceTreatment::Collapse;
159  return aValue;
160 }
161 
162 static Any xforms_double( const OUString& rValue )
163 {
164  double fValue;
165  bool bSuccess = ::sax::Converter::convertDouble( fValue, rValue );
166  return bSuccess ? makeAny( fValue ) : Any();
167 }
168 
169 static Any xforms_date( const OUString& rValue )
170 {
171  Any aAny;
172 
173  // parse ISO date
174  sal_Int32 nPos1 = rValue.indexOf( '-' );
175  sal_Int32 nPos2 = rValue.indexOf( '-', nPos1 + 1 );
176  if( nPos1 > 0 && nPos2 > 0 )
177  {
178  util::Date aDate;
179  aDate.Year = static_cast<sal_uInt16>(
180  rValue.copy( 0, nPos1 ).toInt32() );
181  aDate.Month = static_cast<sal_uInt16>(
182  rValue.copy( nPos1 + 1, nPos2 - nPos1 - 1 ).toInt32() );
183  aDate.Day = static_cast<sal_uInt16>(
184  rValue.copy( nPos2 + 1 ).toInt32() );
185  aAny <<= aDate;
186  }
187  return aAny;
188 }
189 
190 static Any xforms_dateTime( const OUString& rValue )
191 {
192  util::DateTime aDateTime;
193  bool const bSuccess = ::sax::Converter::parseDateTime(aDateTime, rValue);
194  return bSuccess ? makeAny( aDateTime ) : Any();
195 }
196 
197 static Any xforms_time( const OUString& rValue )
198 {
199  Any aAny;
200  Duration aDuration;
201  if (::sax::Converter::convertDuration( aDuration, rValue ))
202  {
203  css::util::Time aTime;
204  aTime.Hours = aDuration.Hours;
205  aTime.Minutes = aDuration.Minutes;
206  aTime.Seconds = aDuration.Seconds;
207  aTime.NanoSeconds = aDuration.NanoSeconds;
208  aAny <<= aTime;
209  }
210  return aAny;
211 }
212 
213 
215  sal_uInt16 nToken,
216  sal_uInt16 nPrefix,
217  const OUString& rLocalName,
218  const Reference<XAttributeList>& xAttrList )
219 {
220  // find value
221  OUString sValue;
222  sal_Int16 nLength = xAttrList->getLength();
223  for( sal_Int16 n = 0; n < nLength; n++ )
224  {
225  if( IsXMLToken( xAttrList->getNameByIndex( n ), XML_VALUE ) )
226  sValue = xAttrList->getValueByIndex( n );
227  }
228 
229  // determine property name + suitable converter
230  OUString sPropertyName;
231  convert_t pConvert = nullptr;
232  switch( nToken )
233  {
234  case XML_LENGTH:
235  sPropertyName = "Length";
236  pConvert = &xforms_int32;
237  break;
238  case XML_MINLENGTH:
239  sPropertyName = "MinLength";
240  pConvert = &xforms_int32;
241  break;
242  case XML_MAXLENGTH:
243  sPropertyName = "MaxLength";
244  pConvert = &xforms_int32;
245  break;
246  case XML_TOTALDIGITS:
247  sPropertyName = "TotalDigits";
248  pConvert = &xforms_int32;
249  break;
250  case XML_FRACTIONDIGITS:
251  sPropertyName = "FractionDigits";
252  pConvert = &xforms_int32;
253  break;
254  case XML_PATTERN:
255  sPropertyName = "Pattern";
256  pConvert = &xforms_string;
257  break;
258  case XML_WHITESPACE:
259  sPropertyName = "WhiteSpace";
260  pConvert = &xforms_whitespace;
261  break;
262  case XML_MININCLUSIVE:
263  case XML_MINEXCLUSIVE:
264  case XML_MAXINCLUSIVE:
265  case XML_MAXEXCLUSIVE:
266  {
267  // these attributes are mapped to different properties.
268  // To determine the property name, we use an attribute
269  // dependent prefix and a type dependent suffix. The
270  // converter is only type dependent.
271 
272  // first, attribute-dependent prefix
273  switch( nToken )
274  {
275  case XML_MININCLUSIVE:
276  sPropertyName = "MinInclusive";
277  break;
278  case XML_MINEXCLUSIVE:
279  sPropertyName = "MinExclusive";
280  break;
281  case XML_MAXINCLUSIVE:
282  sPropertyName = "MaxInclusive";
283  break;
284  case XML_MAXEXCLUSIVE:
285  sPropertyName = "MaxExclusive";
286  break;
287  }
288 
289  // second, type-dependent suffix + converter
291  GetImport().GetNamespaceMap(),
292  msBaseName ) )
293  {
294  case css::xsd::DataTypeClass::DECIMAL:
295  case css::xsd::DataTypeClass::DOUBLE:
296  case css::xsd::DataTypeClass::FLOAT:
297  sPropertyName += "Double";
298  pConvert = &xforms_double;
299  break;
300  case css::xsd::DataTypeClass::DATETIME:
301  sPropertyName += "DateTime";
302  pConvert = &xforms_dateTime;
303  break;
304  case css::xsd::DataTypeClass::DATE:
305  sPropertyName += "Date";
306  pConvert = &xforms_date;
307  break;
308  case css::xsd::DataTypeClass::TIME:
309  sPropertyName += "Time";
310  pConvert = &xforms_time;
311  break;
312  case css::xsd::DataTypeClass::gYear:
313  case css::xsd::DataTypeClass::gDay:
314  case css::xsd::DataTypeClass::gMonth:
315  sPropertyName += "Int";
316  pConvert = &xforms_int16;
317  break;
318 
319  case css::xsd::DataTypeClass::STRING:
320  case css::xsd::DataTypeClass::anyURI:
321  case css::xsd::DataTypeClass::BOOLEAN:
322  // invalid: These shouldn't have min/max-inclusive
323  break;
324 
325  /* data types not yet supported:
326  case css::xsd::DataTypeClass::DURATION:
327  case css::xsd::DataTypeClass::gYearMonth:
328  case css::xsd::DataTypeClass::gMonthDay:
329  case css::xsd::DataTypeClass::hexBinary:
330  case css::xsd::DataTypeClass::base64Binary:
331  case css::xsd::DataTypeClass::QName:
332  case css::xsd::DataTypeClass::NOTATION:
333  */
334  }
335  }
336  break;
337 
338  default:
339  OSL_FAIL( "unknown facet" );
340  }
341 
342  // finally, set the property
343  CreateDataType();
344  if( mxDataType.is()
345  && !sPropertyName.isEmpty()
346  && pConvert != nullptr
347  && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) )
348  {
349  try
350  {
351  mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) );
352  }
353  catch( const Exception& )
354  {
355  ; // can't set property? Then ignore.
356  }
357  }
358 
359  return new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
360 }
361 
362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Any(* convert_t)(const OUString &)
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3434
css::uno::Reference< css::xforms::XDataTypeRepository > mxRepository
static Any xforms_whitespace(const OUString &rValue)
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:62
sal_Int64 n
virtual void HandleAttribute(sal_uInt16 nToken, const OUString &rValue) override
will be called for each attribute
NONE
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
#define XML_TOKEN_MAP_END
Definition: xmltkmap.hxx:33
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
#define TOKEN_MAP_ENTRY(NAMESPACE, TOKEN)
static Any xforms_int16(const OUString &rValue)
static Any xforms_time(const OUString &rValue)
handle attributes through an SvXMLTokenMap
static bool parseDateTime(css::util::DateTime &rDateTime, const OUString &rString)
OUString xforms_getBasicTypeName(const Reference< XDataTypeRepository > &xRepository, const SvXMLNamespaceMap &rNamespaceMap, const OUString &rXMLName)
Definition: xformsapi.cxx:277
BASE
static Any xforms_string(const OUString &rValue)
const SvXMLTokenMapEntry aAttributes[]
static void convertDuration(OUStringBuffer &rBuffer, const double fTime)
static Any xforms_date(const OUString &rValue)
static Any xforms_dateTime(const OUString &rValue)
SvXMLImportContext(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName)
A contexts constructor does anything that is required if an element starts.
Definition: xmlictxt.cxx:29
virtual SvXMLImportContext * HandleChild(sal_uInt16 nToken, sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList) override
will be called for each child element
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:44
SchemaRestrictionContext(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName, css::uno::Reference< css::xforms::XDataTypeRepository > const &rRepository, const OUString &sTypeName)
Any makeAny(Color const &value)
#define SAL_WARN_IF(condition, area, stream)
css::uno::Reference< css::beans::XPropertySet > mxDataType
Handling of tokens in XML:
static Any xforms_int32(const OUString &rValue)
sal_Int32 nLength
Definition: xmltoken.cxx:36
const char PATTERN[]
const SvXMLTokenMapEntry aChildren[]
sal_uInt16 xforms_getTypeClass(const Reference< XDataTypeRepository > &xRepository, const SvXMLNamespaceMap &rNamespaceMap, const OUString &rXMLName)
Definition: xformsapi.cxx:192
sal_Int16 nValue
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
static Any xforms_double(const OUString &rValue)
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)