1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18
19 #include "itkDOMNodeXMLReader.h"
20 #include "expat.h"
21
22 #include <fstream>
23
24 namespace itk
25 {
26
27 /**
28 * The following three functions are called by the expat XML parser during the parsing process,
29 * and the calls are forwarded to the callback functions of DOMNodeXMLReader.
30 */
31
itkXMLParserStartElement(void * parser,const char * name,const char ** atts)32 static void itkXMLParserStartElement( void* parser, const char* name, const char** atts )
33 {
34 // Begin element handler that is registered with the XML_Parser.
35 // This just casts the user data to a itkXMLParser and calls
36 // StartElement.
37 static_cast<DOMNodeXMLReader*>(parser)->StartElement( name, atts );
38 }
39
itkXMLParserEndElement(void * parser,const char * name)40 static void itkXMLParserEndElement( void* parser, const char* name )
41 {
42 // End element handler that is registered with the XML_Parser. This
43 // just casts the user data to a itkXMLParser and calls EndElement.
44 static_cast<DOMNodeXMLReader*>(parser)->EndElement( name );
45 }
46
itkXMLParserCharacterDataHandler(void * parser,const char * data,int length)47 static void itkXMLParserCharacterDataHandler( void* parser, const char* data, int length )
48 {
49 // Character data handler that is registered with the XML_Parser.
50 // This just casts the user data to a itkXMLParser and calls
51 // CharacterDataHandler.
52 static_cast<DOMNodeXMLReader*>(parser)->CharacterDataHandler( data, length );
53 }
54
DOMNodeXMLReader()55 DOMNodeXMLReader::DOMNodeXMLReader()
56 {
57 }
58
59 /**
60 * Function called by Update() or end-users to generate the output DOM object
61 * from an input stream such as file, string, etc.
62 */
63 void
Update(std::istream & is)64 DOMNodeXMLReader::Update( std::istream& is )
65 {
66 if ( m_DOMNodeXML.IsNull() )
67 {
68 OutputType::Pointer temp = OutputType::New();
69 this->SetDOMNodeXML( temp );
70 }
71 m_DOMNodeXML->RemoveAllAttributesAndChildren();
72 this->m_Context = nullptr;
73
74 is >> std::noskipws;
75 std::string s;
76 while ( true )
77 {
78 char c = 0;
79 is >> c;
80 if ( !is.good() )
81 {
82 break;
83 }
84 s.append( 1, c );
85 }
86
87 XML_Parser parser = XML_ParserCreate( nullptr );
88 XML_SetElementHandler( parser, &itkXMLParserStartElement, &itkXMLParserEndElement );
89 XML_SetCharacterDataHandler( parser, &itkXMLParserCharacterDataHandler );
90 XML_SetUserData( parser, this );
91
92 bool ok = XML_Parse( parser, s.data(), static_cast<int>( s.size() ), false );
93 if ( !ok )
94 {
95 ExceptionObject e( __FILE__, __LINE__ );
96 std::string message( XML_ErrorString(XML_GetErrorCode(parser)) );
97 e.SetDescription( message.c_str() );
98 throw e;
99 }
100
101 XML_ParserFree( parser );
102 }
103
104 /**
105 * Function called by end-users to generate the output DOM object from the input XML file.
106 */
107 void
Update()108 DOMNodeXMLReader::Update()
109 {
110 std::ifstream is( this->m_FileName.c_str() );
111 if ( !is.is_open() )
112 {
113 itkExceptionMacro( "failed openning the input XML file" );
114 }
115
116 this->Update( is );
117
118 is.close();
119 }
120
121 /** Callback function -- called from XML parser with start-of-element
122 * information.
123 */
124 void
StartElement(const char * name,const char ** atts)125 DOMNodeXMLReader::StartElement( const char* name, const char** atts )
126 {
127 OutputType* node = nullptr;
128 if ( this->m_Context )
129 {
130 OutputPointer node1 = OutputType::New();
131 node = (OutputType*)node1;
132 this->m_Context->AddChildAtEnd( node );
133 }
134 else
135 {
136 node = this->m_DOMNodeXML;
137 }
138
139 node->SetName( name );
140
141 size_t i = 0;
142 while ( atts[i] )
143 {
144 std::string key( atts[i++] );
145 std::string value( atts[i++] );
146 if ( StringTools::MatchWith(key,"id") )
147 {
148 node->SetID( value );
149 }
150 else
151 {
152 node->SetAttribute( key, value );
153 }
154 }
155
156 this->m_Context = node;
157 }
158
159 /** Callback function -- called from XML parser when ending tag
160 * encountered.
161 */
162 void
EndElement(const char * name)163 DOMNodeXMLReader::EndElement( const char* name )
164 {
165 if ( this->m_Context->GetName() != name )
166 {
167 itkExceptionMacro( "start/end tag names mismatch" );
168 }
169
170 this->m_Context = this->m_Context->GetParent();
171 }
172
173 /** Callback function -- called from XML parser with the character data
174 * for an XML element.
175 */
176 void
CharacterDataHandler(const char * text,int len)177 DOMNodeXMLReader::CharacterDataHandler( const char* text, int len )
178 {
179 std::string s( text, len );
180
181 StringTools::Trim( s );
182 if ( s.empty() )
183 {
184 return;
185 }
186
187 this->m_Context->AddTextChildAtEnd( s );
188 }
189
190 } // namespace itk
191