1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // This file contains the implementation of the XsdHandler class.
27 
28 #include "kml/xsd/xsd_handler.h"
29 #include <cstring>  // strcmp
30 #include "boost/scoped_ptr.hpp"
31 #include "kml/base/attributes.h"
32 #include "kml/xsd/xsd_element.h"
33 #include "kml/xsd/xsd_file.h"
34 #include "kml/xsd/xsd_schema.h"
35 #include "kml/xsd/xsd_util.h"
36 
37 using kmlbase::Attributes;
38 
39 namespace kmlxsd {
40 
41 // <xs:complexType name="..." abstract="...">
StartComplexType(const Attributes & attributes)42 void XsdHandler::StartComplexType(const Attributes& attributes) {
43   if (!current_type_) {  // <xs:complexType> and/or <xs:simpleType>
44     current_type_ = XsdComplexType::Create(attributes);
45   }
46 }
47 
48 // </xs:complexType">
49 // </xs:simpleType">
EndType()50 void XsdHandler::EndType() {
51   xsd_file_->add_type(current_type_);
52   current_type_ = NULL;
53 }
54 
55 // <xs:extension base="...">
StartExtension(const Attributes & attributes)56 void XsdHandler::StartExtension(const Attributes& attributes) {
57   if (XsdComplexTypePtr complex_type =
58           XsdComplexType::AsComplexType(current_type_)) {
59     string base;
60     if (attributes.GetString(kBase, &base)) {
61       complex_type->set_extension_base(base);
62     }
63   }
64 }
65 
66 // <xs:simpleType name="..."/>
StartSimpleType(const Attributes & attributes)67 void XsdHandler::StartSimpleType(const Attributes& attributes) {
68   if (!current_type_) {  // <xs:simpleType is never nested...
69     current_type_ = XsdSimpleType::Create(attributes);
70   }
71 }
72 
73 // <xs:restriction base="...">
StartRestriction(const Attributes & attributes)74 void XsdHandler::StartRestriction(const Attributes& attributes) {
75   if (XsdSimpleTypePtr simple_type =
76           XsdSimpleType::AsSimpleType(current_type_)) {
77     string base;
78     if (attributes.GetString(kBase, &base)) {
79       simple_type->set_restriction_base(base);
80     }
81   }
82 }
83 
84 // <xs:enumeration value="...">
StartEnumeration(const Attributes & attributes)85 void XsdHandler::StartEnumeration(const Attributes& attributes) {
86   if (XsdSimpleTypePtr simple_type =
87           XsdSimpleType::AsSimpleType(current_type_)) {
88     string value;
89     if (attributes.GetString(kValue, &value)) {
90       simple_type->add_enumeration(value);
91     }
92   }
93 }
94 
95 // <xs:element name="..." type="..." default=".."/>
96 // <xs:element ref="..." minOccurs="..." maxOccurs="..."/>
StartXsElement(const Attributes & attributes)97 void XsdHandler::StartXsElement(const Attributes& attributes) {
98   XsdElement* element = XsdElement::Create(attributes);
99   if (!element) {
100     return;
101   }
102 
103   // Is this a global element?
104   if (parse_.top() == kSchema) {
105     xsd_file_->add_element(element);
106   } else if (XsdComplexTypePtr complex_type =
107                  XsdComplexType::AsComplexType(current_type_)) {
108      // Is it a child of <xs:complexType>?
109     complex_type->add_element(element);
110   }
111 }
112 
113 // ExpatHandler::StartElement
StartElement(const string & xs_element_name,const kmlbase::StringVector & atts)114 void XsdHandler::StartElement(const string& xs_element_name,
115                               const kmlbase::StringVector& atts) {
116   boost::scoped_ptr<Attributes> attributes(Attributes::Create(atts));
117 
118   if (xs_element_name.compare(kSchema) == 0) {
119     xsd_file_->set_schema(XsdSchema::Create(*attributes));
120   } else if (xs_element_name.compare(kElement) == 0) {
121     StartXsElement(*attributes);
122   } else if (xs_element_name.compare(kComplexType) == 0) {
123     StartComplexType(*attributes);
124   } else if (xs_element_name.compare(kExtension) == 0) {
125     StartExtension(*attributes);
126   } else if (xs_element_name.compare(kSimpleType) == 0) {
127     StartSimpleType(*attributes);
128   } else if (xs_element_name.compare(kRestriction) == 0) {
129     StartRestriction(*attributes);
130   } else if (xs_element_name.compare(kEnumeration) == 0) {
131     StartEnumeration(*attributes);
132   }
133 
134   // Always push, and we always pop in EndElement().
135   parse_.push(xs_element_name);
136 }
137 
138 // ExpatHandler::EndElement
EndElement(const string & xs_element_name)139 void XsdHandler::EndElement(const string& xs_element_name) {
140   // Always pop, because we always push in StartElement().
141   parse_.pop();
142   if (xs_element_name.compare(kComplexType) == 0) {
143     EndType();
144   } else if (xs_element_name.compare(kSimpleType) == 0) {
145     EndType();
146   }
147 }
148 
149 }  // end namespace kmlxsd
150