11 #include "xercesc/dom/DOM.hpp"
12 #include "xercesc/framework/LocalFileFormatTarget.hpp"
13 #include "xercesc/framework/MemBufInputSource.hpp"
14 #include "xercesc/parsers/XercesDOMParser.hpp"
15 #include "xercesc/sax/EntityResolver.hpp"
16 #include "xercesc/sax/InputSource.hpp"
17 #include "xercesc/sax/SAXParseException.hpp"
18 #include "xercesc/util/PlatformUtils.hpp"
19 #include "xercesc/util/XMLString.hpp"
20 #include "xercesc/util/XMLURL.hpp"
21 #include "xercesc/util/XMLUni.hpp"
22 #include "xercesc/util/XercesDefs.hpp"
35 #include <sys/types.h>
37 using namespace xercesc;
38 using namespace Gaudi;
41 #if _XERCES_VERSION <= 30000
43 # define setIdAttribute( a, b ) setIdAttribute( a )
50 typedef const string&
CSTR;
51 inline string _toString(
const XMLCh* toTranscode ) {
52 char* buff = XMLString::transcode( toTranscode );
53 string tmp( buff == 0 ?
"" : buff );
60 XMLPlatformUtils::Initialize();
61 }
catch (
const XMLException& e ) {
62 cout <<
"Xerces-c error in initialization:" << _toString( e.getMessage() ) <<
endl;
65 ~__Init() { XMLPlatformUtils::Terminate(); }
71 XMLStr(
CSTR c ) { m_xml = XMLString::transcode(
c.c_str() ); }
75 operator const XMLCh*()
const {
return m_xml; }
77 struct XMLTag :
public XMLStr {
79 XMLTag(
CSTR s ) : XMLStr(
s ), m_str(
s ) {}
81 operator CSTR()
const {
return m_str; }
85 struct XMLCollection {
87 XMLCollection( DOMNode*
n,
bool use_children =
true ) : m_node( (DOMElement*)
n ) {
89 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
90 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++( *
this );
93 operator bool()
const {
return m_node; }
94 operator DOMNode*()
const {
return m_node; }
95 operator DOMElement*()
const {
return m_node; }
96 DOMElement* operator->()
const {
return m_node; }
97 string attr(
const XMLTag& tag )
const {
return _toString( m_node->getAttribute( tag ) ); }
98 string attr(
CSTR tag )
const {
return attr( XMLTag( tag ) ); }
99 string tag()
const {
return _toString( m_node->getTagName() ); }
102 m_node = (DOMElement*)m_node->getNextSibling();
103 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
return; }
107 struct ErrHandler :
public ErrorHandler {
113 void resetErrors()
override {}
115 void warning(
const SAXParseException& )
override {}
117 void error(
const SAXParseException& e )
override;
119 void fatalError(
const SAXParseException& e )
override;
121 struct DTDRedirect :
public EntityResolver {
122 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override {
123 static const char* dtdID =
"redirectinmem.dtd";
124 static const char* dtd =
"\
125 <!ELEMENT POOLFILECATALOG (META*,File*)>\
126 <!ELEMENT META EMPTY>\
127 <!ELEMENT File (physical,logical,metadata*)>\
128 <!ATTLIST META name CDATA #REQUIRED>\
129 <!ATTLIST META type CDATA #REQUIRED>\
130 <!ELEMENT physical (pfn)+>\
131 <!ELEMENT logical (lfn)*>\
132 <!ELEMENT metadata EMPTY>\
133 <!ELEMENT lfn EMPTY>\
134 <!ELEMENT pfn EMPTY>\
135 <!ATTLIST File ID ID #REQUIRED>\
136 <!ATTLIST pfn name ID #REQUIRED>\
137 <!ATTLIST pfn filetype CDATA #IMPLIED>\
138 <!ATTLIST pfn se CDATA #IMPLIED>\
139 <!ATTLIST lfn name ID #REQUIRED>\
140 <!ATTLIST metadata att_name CDATA #REQUIRED>\
141 <!ATTLIST metadata att_value CDATA #REQUIRED>\
143 static const size_t len =
strlen( dtd );
144 return new MemBufInputSource( (
const XMLByte*)dtd, len, dtdID,
false );
148 void ErrHandler::error(
const SAXParseException& e ) {
149 string m( _toString( e.getMessage() ) );
150 if (
m.find(
"The values for attribute 'name' must be names or name tokens" ) != string::npos ||
151 m.find(
"The values for attribute 'ID' must be names or name tokens" ) != string::npos ||
152 m.find(
"for attribute 'name' must be Name or Nmtoken" ) != string::npos ||
153 m.find(
"for attribute 'ID' must be Name or Nmtoken" ) != string::npos ||
154 m.find(
"for attribute 'name' is invalid Name or NMTOKEN value" ) != string::npos ||
155 m.find(
"for attribute 'ID' is invalid Name or NMTOKEN value" ) != string::npos )
157 string sys( _toString( e.getSystemId() ) );
159 log <<
MSG::ERROR <<
"Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column "
160 << e.getColumnNumber() <<
endmsg <<
"Message: " <<
m <<
endmsg;
162 void ErrHandler::fatalError(
const SAXParseException& e ) {
164 string m( _toString( e.getMessage() ) );
165 string sys( _toString( e.getSystemId() ) );
166 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column "
167 << e.getColumnNumber() <<
endmsg <<
"Message: " <<
m <<
endmsg;
168 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
171 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n"
172 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n"
173 "<POOLFILECATALOG>\n"
174 "</POOLFILECATALOG>\n" );
175 const XMLTag PFNCOLL(
"physical" );
176 const XMLTag LFNCOLL(
"logical" );
177 const XMLTag PFNNODE(
"pfn" );
178 const XMLTag LFNNODE(
"lfn" );
179 const XMLTag Attr_type(
"type" );
180 const XMLTag Attr_ID(
"ID" );
181 const XMLTag Attr_name(
"name" );
182 const XMLTag Attr_ftype(
"filetype" );
183 const XMLTag MetaNode(
"metadata" );
184 const XMLTag Attr_metaName(
"att_name" );
185 const XMLTag Attr_metaValue(
"att_value" );
195 if ( !
m_doc && throw_if_no_exists )
printError(
"The XML catalog was not started.",
true );
206 string xmlFile =
getfile(
false );
208 m_parser = std::make_unique<XercesDOMParser>();
209 m_parser->setValidationScheme( XercesDOMParser::Val_Auto );
211 DTDRedirect dtdinmem;
212 m_parser->setEntityResolver( &dtdinmem );
215 if ( !xmlFile.
empty() ) {
219 MemBufInputSource src( (
const XMLByte*)
s.
c_str(),
s.
length(),
"MemCatalog" );
223 }
catch (
const XMLException& e ) {
224 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
225 }
catch (
const DOMException& e ) {
226 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
227 }
catch ( ... ) {
printError(
"UNKNOWN XML parse error in file " + xmlFile ); }
232 DOMNode* e =
element( fid,
false );
233 e = e ? e->getParentNode() : 0;
234 e = e ? e->getParentNode() : 0;
236 if ( e->getAttributes() ) {
237 char* nam = XMLString::transcode( ( (DOMElement*)e )->getAttribute( Attr_ID ) );
238 if ( nam ) result = nam;
247 DOMNode* fde =
getDoc(
true )->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
248 for ( XMLCollection
c(
child( fde,
"File" ),
false );
c; ++
c ) fids.push_back(
c.attr( Attr_ID ) );
253 for ( XMLCollection
c(
child(
child(
element( fid,
false ), PFNCOLL ), PFNNODE ),
false );
c; ++
c )
254 files.emplace_back(
c.attr( Attr_name ),
c.attr( Attr_ftype ) );
259 for ( XMLCollection
c(
child(
child(
element( fid,
false ), LFNCOLL ), LFNNODE ),
false );
c; ++
c )
260 files.emplace_back(
c.attr( Attr_name ), fid );
265 for ( XMLCollection
c(
child(
element( fid ), MetaNode ),
false );
c; ++
c )
266 attr.emplace_back(
c.attr( Attr_metaName ),
c.attr( Attr_metaValue ) );
267 if ( attr.size() > 0 ) attr.emplace_back(
"guid", fid );
271 for ( XMLCollection
c(
par );
c; ++
c ) {
272 if (
c.tag() == tag ) {
273 if ( !attr.
empty() &&
c.attr( attr ) != val )
continue;
282 DOMNode* node =
element( fid );
283 DOMElement* mnod = (DOMElement*)
child( node, MetaNode, Attr_metaName, attr );
285 mnod =
getDoc(
true )->createElement( MetaNode );
286 node->appendChild( mnod );
287 mnod->setAttribute( Attr_metaName, XMLStr( attr ) );
289 mnod->setAttribute( Attr_metaValue, XMLStr( val ) );
293 printError(
"Cannot update readonly catalog!" );
297 XMLCollection
c(
child(
getDoc(
true )->getElementById( XMLStr( fid ) ), MetaNode, Attr_metaName, attr ) );
298 return c ?
c.attr( attr ) :
string(
"" );
303 DOMNode* fn =
getDoc(
true )->getElementById( XMLStr( fid ) );
304 for ( XMLCollection
c{
child( fn, MetaNode ) };
c; ++
c )
305 if ( attr[0] ==
'*' || !
c.attr( attr ).empty() ) gbc.
push_back(
c );
306 for (
const auto& i : gbc ) fn->removeChild( i );
310 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( element_name ) );
311 if ( !node && print_err )
printError(
"Cannot find element:" + element_name );
316 DOMNode *pn =
nullptr, *fn =
element( fid );
317 if ( fn ) pn = fn->getParentNode();
318 if ( pn ) pn->removeChild( fn );
322 if ( !fid.
empty() ) {
324 if ( res.first == 0 || res.second == 0 ) {
printError(
"Failed to register FID:" + fid ); }
327 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
331 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
332 if ( node && node->getNodeType() == DOMNode::ELEMENT_NODE ) {
333 ( (DOMElement*)node )->setAttribute( Attr_name, XMLStr( new_pfn ) );
339 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
341 DOMNode* pcoll_node = node->getParentNode();
342 pcoll_node->removeChild( node );
344 for ( XMLCollection pcoll( pcoll_node,
true ); pcoll; ++pcoll ) {
348 DOMNode* file_node = pcoll_node->getParentNode();
349 file_node->getParentNode()->removeChild( file_node );
355 printError(
"Cannot update readonly catalog!" );
356 return {
nullptr,
nullptr };
360 DOMElement * file = (DOMElement*)
element( fid,
false ), *phyelem = 0, *logelem = 0;
361 DOMDocument* doc =
getDoc(
true );
363 DOMNode* fde = doc->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
364 file =
m_doc->createElement( XMLStr(
"File" ) );
365 file->setAttribute( Attr_ID, XMLStr( fid ) );
366 file->setIdAttribute( Attr_ID,
true );
367 fde->appendChild( file );
370 for ( XMLCollection
c1( file );
c1; ++
c1 ) {
371 char* nam = XMLString::transcode(
c1->getNodeName() );
372 if ( nam == PFNCOLL ) phyelem =
c1;
373 if ( nam == LFNCOLL ) logelem =
c1;
377 phyelem = doc->createElement( PFNCOLL );
378 file->appendChild( phyelem );
382 logelem = doc->createElement( LFNCOLL );
383 file->appendChild( logelem );
386 return { logelem, phyelem };
390 if ( !fid.
empty() ) {
392 DOMElement * phyelem = res.second, *fnelem = 0;
393 for ( XMLCollection
c( phyelem );
c; ++
c ) {
394 char* nam = XMLString::transcode(
c->getNodeName() );
395 if ( nam == PFNNODE ) {
397 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
407 fnelem =
getDoc(
true )->createElement( PFNNODE );
408 phyelem->appendChild( fnelem );
409 fnelem->setAttribute( Attr_ftype, XMLStr( ftype ) );
410 fnelem->setAttribute( Attr_name, XMLStr( pfn ) );
411 fnelem->setIdAttribute( Attr_name,
true );
416 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:" + fid );
420 if ( !fid.
empty() ) {
422 DOMElement * logelem = res.first, *fnelem = 0;
423 for ( XMLCollection
c( logelem );
c; ++
c ) {
424 char* nam = XMLString::transcode(
c->getNodeName() );
425 if ( nam == LFNNODE ) {
427 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
436 fnelem =
getDoc(
true )->createElement( LFNNODE );
437 logelem->appendChild( fnelem );
438 fnelem->setAttribute( Attr_name, XMLStr( lfn ) );
439 fnelem->setIdAttribute( Attr_name,
true );
444 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
450 string xmlfile =
getfile(
true );
452 DOMImplementation* imp = DOMImplementationRegistry::getDOMImplementation( ii );
453 auto tar = std::make_unique<LocalFileFormatTarget>( xmlfile.
c_str() );
454 #if _XERCES_VERSION <= 30000
455 DOMWriter* wr = imp->createDOMWriter();
456 wr->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint,
true );
457 wr->writeNode( tar.get(), *
m_doc );
460 DOMLSOutput*
output = imp->createLSOutput();
461 output->setByteStream( tar.get() );
462 DOMLSSerializer* wr = imp->createLSSerializer();
463 wr->getDomConfig()->setParameter( XMLStr(
"format-pretty-print" ),
true );
475 string protocol,
path;
478 xerurl = (
const XMLCh*)XMLStr(
m_file );
479 protocol = _toString( xerurl.getProtocolName() );
480 path = _toString( xerurl.getPath() );
481 }
catch (
const XMLException& e ) {
printError( _toString( e.getMessage() ) ); }
482 if ( protocol.
empty() ) {
484 }
else if ( protocol ==
"http" || protocol ==
"ftp" ) {
486 }
else if ( protocol ==
"file" ) {
489 int exist = ::stat(
path.c_str(), &buff ) != -1;
490 if ( create && !exist ) {
500 }
else if ( exist ) {
502 }
else if ( !create ) {
506 printError( protocol +
": protocol not supported." );