2015-07-29 14:19:43 +02:00
# include "cafPdmXmlObjectHandle.h"
# include "cafPdmObjectHandle.h"
# include "cafPdmXmlFieldHandle.h"
# include "cafPdmFieldHandle.h"
# include <QXmlStreamReader>
# include <QXmlStreamWriter>
# include <iostream>
# include <assert.h>
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmXmlObjectHandle : : PdmXmlObjectHandle ( PdmObjectHandle * owner , bool giveOwnership )
{
m_owner = owner ;
m_owner - > addCapability ( this , giveOwnership ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmXmlObjectHandle * xmlObj ( PdmObjectHandle * obj )
{
if ( ! obj ) return NULL ;
PdmXmlObjectHandle * xmlObject = obj - > capability < PdmXmlObjectHandle > ( ) ;
assert ( xmlObject ) ;
return xmlObject ;
}
//--------------------------------------------------------------------------------------------------
/// Reads all the fields into this PdmObject
/// Assumes xmlStream points to the start element token of the PdmObject for which to read fields.
/// ( and not first token of object content)
/// This makes attribute based field storage possible.
/// Leaves the xmlStream pointing to the EndElement of the PdmObject.
//--------------------------------------------------------------------------------------------------
void PdmXmlObjectHandle : : readFields ( QXmlStreamReader & xmlStream , PdmObjectFactory * objectFactory )
{
bool isObjectFinished = false ;
QXmlStreamReader : : TokenType type ;
while ( ! isObjectFinished )
{
type = xmlStream . readNext ( ) ;
switch ( type )
{
case QXmlStreamReader : : StartElement :
{
QString name = xmlStream . name ( ) . toString ( ) ;
PdmFieldHandle * fieldHandle = m_owner - > findField ( name ) ;
2015-08-05 12:34:07 +02:00
if ( fieldHandle & & fieldHandle - > xmlCapability ( ) )
2015-07-29 14:19:43 +02:00
{
2015-08-05 12:34:07 +02:00
PdmXmlFieldHandle * xmlFieldHandle = fieldHandle - > xmlCapability ( ) ;
2015-07-29 14:19:43 +02:00
if ( xmlFieldHandle - > isIOReadable ( ) )
{
// readFieldData assumes that the xmlStream points to first token of field content.
// After reading, the xmlStream is supposed to point to the first token after the field content.
// (typically an "endElement")
QXmlStreamReader : : TokenType tt ;
tt = xmlStream . readNext ( ) ;
xmlFieldHandle - > readFieldData ( xmlStream , objectFactory ) ;
}
else
{
xmlStream . skipCurrentElement ( ) ;
}
}
else
{
std : : cout < < " Line " < < xmlStream . lineNumber ( ) < < " : Warning: Could not find a field with name " < < name . toLatin1 ( ) . data ( ) < < " in the current object : " < < classKeyword ( ) . toLatin1 ( ) . data ( ) < < std : : endl ;
xmlStream . skipCurrentElement ( ) ;
}
break ;
}
break ;
case QXmlStreamReader : : EndElement :
{
// End of object.
QString name = xmlStream . name ( ) . toString ( ) ; // For debugging
isObjectFinished = true ;
}
break ;
case QXmlStreamReader : : EndDocument :
{
// End of object.
isObjectFinished = true ;
}
break ;
default :
{
// Just read on
// Todo: Error handling
}
break ;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmXmlObjectHandle : : writeFields ( QXmlStreamWriter & xmlStream )
{
std : : vector < PdmFieldHandle * > fields ;
m_owner - > fields ( fields ) ;
for ( size_t it = 0 ; it < fields . size ( ) ; + + it )
{
2015-08-05 12:34:07 +02:00
PdmXmlFieldHandle * field = fields [ it ] - > xmlCapability ( ) ;
2015-07-29 14:19:43 +02:00
if ( field & & field - > isIOWritable ( ) )
{
QString keyword = field - > fieldHandle ( ) - > keyword ( ) ;
assert ( PdmXmlObjectHandle : : isValidXmlElementName ( keyword ) ) ;
xmlStream . writeStartElement ( " " , keyword ) ;
field - > writeFieldData ( xmlStream ) ;
xmlStream . writeEndElement ( ) ;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmXmlObjectHandle : : readObjectFromXmlString ( const QString & xmlString , PdmObjectFactory * objectFactory )
{
// A valid XML is used to store field data of the object. The format of the XML is like this
/*
< classKeyword >
< fieldKeywordA > value < / fieldKeywordA >
< fieldKeywordB > value < / fieldKeywordB >
< / classKeyword >
*/
QXmlStreamReader inputStream ( xmlString ) ;
QXmlStreamReader : : TokenType tt ;
tt = inputStream . readNext ( ) ; // Start of document
tt = inputStream . readNext ( ) ;
QString classKeyword = inputStream . name ( ) . toString ( ) ;
assert ( classKeyword = = this - > classKeyword ( ) ) ;
this - > readFields ( inputStream , objectFactory ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmObjectHandle * PdmXmlObjectHandle : : readUnknownObjectFromXmlString ( const QString & xmlString , PdmObjectFactory * objectFactory )
{
QXmlStreamReader inputStream ( xmlString ) ;
QXmlStreamReader : : TokenType tt ;
tt = inputStream . readNext ( ) ; // Start of document
tt = inputStream . readNext ( ) ;
QString classKeyword = inputStream . name ( ) . toString ( ) ;
PdmObjectHandle * newObject = objectFactory - > create ( classKeyword ) ;
xmlObj ( newObject ) - > readFields ( inputStream , objectFactory ) ;
return newObject ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString PdmXmlObjectHandle : : writeObjectToXmlString ( )
{
QString xmlString ;
QXmlStreamWriter outputStream ( & xmlString ) ;
outputStream . setAutoFormatting ( true ) ;
outputStream . writeStartElement ( " " , this - > classKeyword ( ) ) ;
this - > writeFields ( outputStream ) ;
outputStream . writeEndElement ( ) ;
return xmlString ;
}
//--------------------------------------------------------------------------------------------------
/// Check if a string is a valid Xml element name
//
/// http://www.w3schools.com/xml/xml_elements.asp
///
/// XML elements must follow these naming rules:
/// Names can contain letters, numbers, and other characters
/// Names cannot start with a number or punctuation character
/// Names cannot start with the letters xml (or XML, or Xml, etc)
/// Names cannot contain spaces
//--------------------------------------------------------------------------------------------------
bool PdmXmlObjectHandle : : isValidXmlElementName ( const QString & name )
{
if ( name . isEmpty ( ) )
{
return false ;
}
if ( name . size ( ) > 0 )
{
QChar firstChar = name [ 0 ] ;
if ( firstChar . isDigit ( ) | | firstChar = = ' . ' )
{
return false ;
}
}
if ( name . size ( ) > = 3 )
{
if ( name . left ( 3 ) . compare ( " xml " , Qt : : CaseInsensitive ) = = 0 )
{
return false ;
}
}
if ( name . contains ( ' ' ) )
{
return false ;
}
return true ;
}
2015-08-20 15:22:43 +02:00
//--------------------------------------------------------------------------------------------------
/// Implementation of xmlCapability() defined in cafPdmObjectHandle.h
//--------------------------------------------------------------------------------------------------
PdmXmlObjectHandle * PdmObjectHandle : : xmlCapability ( )
{
PdmXmlObjectHandle * xmlField = capability < PdmXmlObjectHandle > ( ) ;
assert ( xmlField ) ;
return xmlField ;
}
2015-07-29 14:19:43 +02:00
} // end namespace caf