1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_xmloff.hxx" 26 27 #include "SchemaRestrictionContext.hxx" 28 #include "xformsapi.hxx" 29 30 #include <xmloff/xmltoken.hxx> 31 #include <xmloff/nmspmap.hxx> 32 #include <xmloff/xmlnmspe.hxx> 33 #include <xmloff/xmltkmap.hxx> 34 #include <xmloff/xmluconv.hxx> 35 #include <xmloff/xmlimp.hxx> 36 37 #include <com/sun/star/beans/XPropertySet.hpp> 38 #include <com/sun/star/uno/Type.hxx> 39 #include <com/sun/star/util/Date.hpp> 40 #include <com/sun/star/util/Time.hpp> 41 #include <com/sun/star/util/DateTime.hpp> 42 #include <com/sun/star/xforms/XDataTypeRepository.hpp> 43 #include <com/sun/star/xsd/DataTypeClass.hpp> 44 #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> 45 46 #include <tools/debug.hxx> 47 48 49 using rtl::OUString; 50 using com::sun::star::uno::Reference; 51 using com::sun::star::uno::Exception; 52 using com::sun::star::uno::Any; 53 using com::sun::star::uno::makeAny; 54 using com::sun::star::uno::UNO_QUERY; 55 using com::sun::star::util::Date; 56 using com::sun::star::util::DateTime; 57 using com::sun::star::xml::sax::XAttributeList; 58 using com::sun::star::beans::XPropertySet; 59 using com::sun::star::beans::XPropertySetInfo; 60 using com::sun::star::xforms::XDataTypeRepository; 61 using namespace xmloff::token; 62 63 64 65 66 static SvXMLTokenMapEntry aAttributes[] = 67 { 68 TOKEN_MAP_ENTRY( NONE, BASE ), 69 XML_TOKEN_MAP_END 70 }; 71 72 static SvXMLTokenMapEntry aChildren[] = 73 { 74 TOKEN_MAP_ENTRY( XSD, LENGTH ), 75 TOKEN_MAP_ENTRY( XSD, MINLENGTH ), 76 TOKEN_MAP_ENTRY( XSD, MAXLENGTH ), 77 TOKEN_MAP_ENTRY( XSD, MININCLUSIVE ), 78 TOKEN_MAP_ENTRY( XSD, MINEXCLUSIVE ), 79 TOKEN_MAP_ENTRY( XSD, MAXINCLUSIVE ), 80 TOKEN_MAP_ENTRY( XSD, MAXEXCLUSIVE ), 81 TOKEN_MAP_ENTRY( XSD, PATTERN ), 82 // ??? XML_ENUMERATION 83 TOKEN_MAP_ENTRY( XSD, WHITESPACE ), 84 TOKEN_MAP_ENTRY( XSD, TOTALDIGITS ), 85 TOKEN_MAP_ENTRY( XSD, FRACTIONDIGITS ), 86 XML_TOKEN_MAP_END 87 }; 88 89 90 SchemaRestrictionContext::SchemaRestrictionContext( 91 SvXMLImport& rImport, 92 sal_uInt16 nPrefix, 93 const OUString& rLocalName, 94 Reference<com::sun::star::xforms::XDataTypeRepository>& rRepository, 95 const OUString& sTypeName ) : 96 TokenContext( rImport, nPrefix, rLocalName, aAttributes, aChildren ), 97 mxRepository( rRepository ), 98 msTypeName( sTypeName ), 99 msBaseName() 100 { 101 DBG_ASSERT( mxRepository.is(), "need repository" ); 102 } 103 104 SchemaRestrictionContext::~SchemaRestrictionContext() 105 { 106 } 107 108 void SchemaRestrictionContext::CreateDataType() 109 { 110 // only do something if we don't have a data type already 111 if( mxDataType.is() ) 112 return; 113 114 DBG_ASSERT( msBaseName.getLength() > 0, "no base name?" ); 115 DBG_ASSERT( mxRepository.is(), "no repository?" ); 116 117 try 118 { 119 mxDataType = 120 Reference<XPropertySet>( 121 mxRepository->cloneDataType( 122 lcl_getBasicTypeName( mxRepository, 123 GetImport().GetNamespaceMap(), 124 msBaseName ), 125 msTypeName ), 126 UNO_QUERY ); 127 } 128 catch( const Exception& ) 129 { 130 DBG_ERROR( "exception during type creation" ); 131 } 132 DBG_ASSERT( mxDataType.is(), "can't create type" ); 133 } 134 135 void SchemaRestrictionContext::HandleAttribute( 136 sal_uInt16 nToken, 137 const OUString& rValue ) 138 { 139 if( nToken == XML_BASE ) 140 { 141 msBaseName = rValue; 142 } 143 } 144 145 typedef Any (*convert_t)( const OUString& ); 146 147 Any lcl_string( const OUString& rValue ) 148 { 149 return makeAny( rValue ); 150 } 151 152 Any lcl_int32( const OUString& rValue ) 153 { 154 sal_Int32 nValue; 155 bool bSuccess = SvXMLUnitConverter::convertNumber( nValue, rValue ); 156 return bSuccess ? makeAny( nValue ) : Any(); 157 } 158 159 Any lcl_int16( const OUString& rValue ) 160 { 161 sal_Int32 nValue; 162 bool bSuccess = SvXMLUnitConverter::convertNumber( nValue, rValue ); 163 return bSuccess ? makeAny( static_cast<sal_Int16>( nValue ) ) : Any(); 164 } 165 166 Any lcl_whitespace( const OUString& rValue ) 167 { 168 Any aValue; 169 if( IsXMLToken( rValue, XML_PRESERVE ) ) 170 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Preserve; 171 else if( IsXMLToken( rValue, XML_REPLACE ) ) 172 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Replace; 173 else if( IsXMLToken( rValue, XML_COLLAPSE ) ) 174 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Collapse; 175 return aValue; 176 } 177 178 Any lcl_double( const OUString& rValue ) 179 { 180 double fValue; 181 bool bSuccess = SvXMLUnitConverter::convertDouble( fValue, rValue ); 182 return bSuccess ? makeAny( fValue ) : Any(); 183 } 184 185 Any lcl_date( const OUString& rValue ) 186 { 187 Any aAny; 188 189 // parse ISO date 190 sal_Int32 nPos1 = rValue.indexOf( sal_Unicode('-') ); 191 sal_Int32 nPos2 = rValue.indexOf( sal_Unicode('-'), nPos1 + 1 ); 192 if( nPos1 > 0 && nPos2 > 0 ) 193 { 194 Date aDate; 195 aDate.Year = static_cast<sal_uInt16>( 196 rValue.copy( 0, nPos1 ).toInt32() ); 197 aDate.Month = static_cast<sal_uInt16>( 198 rValue.copy( nPos1 + 1, nPos2 - nPos1 - 1 ).toInt32() ); 199 aDate.Day = static_cast<sal_uInt16>( 200 rValue.copy( nPos2 + 1 ).toInt32() ); 201 aAny <<= aDate; 202 } 203 return aAny; 204 } 205 206 Any lcl_dateTime( const OUString& rValue ) 207 { 208 DateTime aDateTime; 209 bool bSuccess = SvXMLUnitConverter::convertDateTime( aDateTime, rValue ); 210 return bSuccess ? makeAny( aDateTime ) : Any(); 211 } 212 213 Any lcl_time( const OUString& rValue ) 214 { 215 Any aAny; 216 DateTime aDateTime; 217 if( SvXMLUnitConverter::convertTime( aDateTime, rValue ) ) 218 { 219 com::sun::star::util::Time aTime; 220 aTime.Hours = aDateTime.Hours; 221 aTime.Minutes = aDateTime.Minutes; 222 aTime.Seconds = aDateTime.Seconds; 223 aTime.HundredthSeconds = aDateTime.HundredthSeconds; 224 aAny <<= aTime; 225 } 226 return aAny; 227 } 228 229 230 SvXMLImportContext* SchemaRestrictionContext::HandleChild( 231 sal_uInt16 nToken, 232 sal_uInt16 nPrefix, 233 const OUString& rLocalName, 234 const Reference<XAttributeList>& xAttrList ) 235 { 236 // find value 237 OUString sValue; 238 sal_Int16 nLength = xAttrList->getLength(); 239 for( sal_Int16 n = 0; n < nLength; n++ ) 240 { 241 if( IsXMLToken( xAttrList->getNameByIndex( n ), XML_VALUE ) ) 242 sValue = xAttrList->getValueByIndex( n ); 243 } 244 245 // determine property name + suitable converter 246 OUString sPropertyName; 247 convert_t pConvert = NULL; 248 switch( nToken ) 249 { 250 case XML_LENGTH: 251 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("Length")); 252 pConvert = &lcl_int32; 253 break; 254 case XML_MINLENGTH: 255 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinLength")); 256 pConvert = &lcl_int32; 257 break; 258 case XML_MAXLENGTH: 259 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxLength")); 260 pConvert = &lcl_int32; 261 break; 262 case XML_TOTALDIGITS: 263 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("TotalDigits")); 264 pConvert = &lcl_int32; 265 break; 266 case XML_FRACTIONDIGITS: 267 sPropertyName =OUString(RTL_CONSTASCII_USTRINGPARAM("FractionDigits")); 268 pConvert = &lcl_int32; 269 break; 270 case XML_PATTERN: 271 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("Pattern")); 272 pConvert = &lcl_string; 273 break; 274 case XML_WHITESPACE: 275 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("WhiteSpace")); 276 pConvert = &lcl_whitespace; 277 break; 278 case XML_MININCLUSIVE: 279 case XML_MINEXCLUSIVE: 280 case XML_MAXINCLUSIVE: 281 case XML_MAXEXCLUSIVE: 282 { 283 // these attributes are mapped to different properties. 284 // To determine the property name, we use an attribute 285 // dependent prefix and a type dependent suffix. The 286 // converter is only type dependent. 287 288 // first, attribute-dependent prefix 289 switch( nToken ) 290 { 291 case XML_MININCLUSIVE: 292 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinInclusive")); 293 break; 294 case XML_MINEXCLUSIVE: 295 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinExclusive")); 296 break; 297 case XML_MAXINCLUSIVE: 298 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxInclusive")); 299 break; 300 case XML_MAXEXCLUSIVE: 301 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxExclusive")); 302 break; 303 } 304 305 // second, type-dependent suffix + converter 306 switch( lcl_getTypeClass( mxRepository, 307 GetImport().GetNamespaceMap(), 308 msBaseName ) ) 309 { 310 case com::sun::star::xsd::DataTypeClass::DECIMAL: 311 case com::sun::star::xsd::DataTypeClass::DOUBLE: 312 case com::sun::star::xsd::DataTypeClass::FLOAT: 313 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Double")); 314 pConvert = &lcl_double; 315 break; 316 case com::sun::star::xsd::DataTypeClass::DATETIME: 317 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("DateTime")); 318 pConvert = &lcl_dateTime; 319 break; 320 case com::sun::star::xsd::DataTypeClass::DATE: 321 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Date")); 322 pConvert = &lcl_date; 323 break; 324 case com::sun::star::xsd::DataTypeClass::TIME: 325 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Time")); 326 pConvert = &lcl_time; 327 break; 328 case com::sun::star::xsd::DataTypeClass::gYear: 329 case com::sun::star::xsd::DataTypeClass::gDay: 330 case com::sun::star::xsd::DataTypeClass::gMonth: 331 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Int")); 332 pConvert = &lcl_int16; 333 break; 334 335 case com::sun::star::xsd::DataTypeClass::STRING: 336 case com::sun::star::xsd::DataTypeClass::anyURI: 337 case com::sun::star::xsd::DataTypeClass::BOOLEAN: 338 // invalid: These shouldn't have min/max-inclusive 339 break; 340 341 /* data types not yet supported: 342 case com::sun::star::xsd::DataTypeClass::DURATION: 343 case com::sun::star::xsd::DataTypeClass::gYearMonth: 344 case com::sun::star::xsd::DataTypeClass::gMonthDay: 345 case com::sun::star::xsd::DataTypeClass::hexBinary: 346 case com::sun::star::xsd::DataTypeClass::base64Binary: 347 case com::sun::star::xsd::DataTypeClass::QName: 348 case com::sun::star::xsd::DataTypeClass::NOTATION: 349 */ 350 } 351 } 352 break; 353 354 default: 355 DBG_ERROR( "unknown facet" ); 356 } 357 358 // finally, set the property 359 CreateDataType(); 360 if( mxDataType.is() 361 && sPropertyName.getLength() > 0 362 && pConvert != NULL 363 && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) ) 364 { 365 try 366 { 367 mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) ); 368 } 369 catch( const Exception& ) 370 { 371 ; // can't set property? Then ignore. 372 } 373 } 374 375 return new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 376 } 377