Kaydet (Commit) 7be8bac4 authored tarafından Luboš Luňák's avatar Luboš Luňák

make the linear xml processing API more generic

I'm pretty sure I'll love to use it in writerfilter instead of the normal
API whenever I get the chance.
üst 1e4fb45c
......@@ -41,15 +41,15 @@ namespace oox
namespace formulaimport
{
// used to differentiate between tags that opening or closing
const int TAG_OPENING = 1 << 29;
const int TAG_CLOSING = 1 << 30;
// used to differentiate between tags that open or close
// TODO
//inline int OPENING( int token ) { return TAG_OPENING | token; }
//inline int CLOSING( int token ) { return TAG_CLOSING | token; }
#define OPENING( token ) ( TAG_OPENING | token )
#define CLOSING( token ) ( TAG_CLOSING | token )
// you probably want to #define these to something shorter in the .cxx file,
// but they must be done as macros, otherwise they wouldn't be usable for case values,
// and macros cannot be namespaced
#define XML_STREAM_OPENING( token ) ( TAG_OPENING | token )
#define XML_STREAM_CLOSING( token ) ( TAG_CLOSING | token )
/**
Class for storing a stream of xml tokens.
......@@ -59,7 +59,55 @@ const int TAG_CLOSING = 1 << 30;
files, unlike the usual LO way of using callbacks, context handlers and similar needlesly
complicated stuff (YMMV).
@since 3.5.0
The advantages of this approach is easy to read and debug code (as it is just functions
reading tokens one by one and calling other functions, compared to having to use callbacks
and temporary storage). The disadvantage is that the XML structure needs to be handled
manually by the code.
Note that tag identifiers are simply int values and the API does not care besides matching
their values to XML stream contents and requiring that the values are not as high as TAG_OPENING.
Be prepared for the fact that some of the functions may throw exceptions if the input
stream does not match the required token (TBD).
The API tries to make the common idioms as simple as possible, see the following examples.
Parse <tagone attr="value"><tagtwo>text</tagtwo></tagone> , where tagtwo is optional:
@code
XmlStream::Tag tagoneTag = stream.ensureOpeningTag( tagone );
if( attributeTag.hasAttribute( attr ))
... = attributeTag.attribute( attr, defaultValueOfTheRightType );
if( XmlStream::Tag tagtwoTag = stream.checkOpeningTag( tagtwo ))
{
... = tagtwoTag.text;
stream.ensureClosingTag( tagtwo );
}
stream.ensureClosingTag( tagone );
@endcode
Parse an element that may contain several sub-elements of different types in random order:
@code
stream.ensureOpeningTag( element );
while( !stream.atEnd() && stream.currentToken() != CLOSING( element ))
{
switch( stream.currentToken())
{
case OPENING( subelement1 ):
handleSubElement1();
break;
case OPENING( subelement2 ):
... process subelement2;
break;
default:
stream.handleUnexpectedTag();
break;
}
stream.ensureClosingTag( element );
@endcode
If there may be just a one type of sub-element, handle it directly without the switch statement.
If there may not be a zero number of sub-elements, use a helper bool variable or use a do-while loop.
@since 3.5
*/
class OOX_DLLPUBLIC XmlStream
{
......
......@@ -41,6 +41,8 @@
#define STR( str ) OUString( RTL_CONSTASCII_USTRINGPARAM( str ))
#define CSTR( str ) ( rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr())
#define OPENING( token ) XML_STREAM_OPENING( token )
#define CLOSING( token ) XML_STREAM_CLOSING( token )
// HACK - TODO convert to the real debug stuff
#undef SAL_LOG_LEVEL
......
......@@ -44,8 +44,8 @@ The primary internal data structure for the formula is the text representation
*/
#define M_TOKEN( token ) OOX_TOKEN( officeMath, token )
#define OPENING_TAG( token ) OPENING( token )
#define CLOSING_TAG( token ) CLOSING( token )
#define OPENING( token ) XML_STREAM_OPENING( token )
#define CLOSING( token ) XML_STREAM_CLOSING( token )
// *sigh*
#define STR( str ) OUString( RTL_CONSTASCII_USTRINGPARAM( str ))
......
......@@ -2366,35 +2366,16 @@ Token_t OOXMLFastContextHandlerWrapper::getToken() const
/*
class OOXMLFastContextHandlerMath
class OOXMLFastContextHandlerLinear
*/
OOXMLFastContextHandlerMath::OOXMLFastContextHandlerMath(OOXMLFastContextHandler* pContext)
OOXMLFastContextHandlerLinear::OOXMLFastContextHandlerLinear(OOXMLFastContextHandler* pContext)
: OOXMLFastContextHandlerProperties(pContext)
, depthCount( 0 )
{
}
void OOXMLFastContextHandlerMath::process()
{
SvGlobalName name( SO3_SM_CLASSID );
comphelper::EmbeddedObjectContainer container;
rtl::OUString aName;
uno::Reference< embed::XEmbeddedObject > ref = container.CreateEmbeddedObject( name.GetByteSequence(), aName );
uno::Reference< uno::XInterface > component( ref->getComponent(), uno::UNO_QUERY );
if( oox::FormulaImportBase* import = dynamic_cast< oox::FormulaImportBase* >( component.get()))
import->readFormulaOoxml( buffer );
if (isForwardEvents())
{
OOXMLPropertySet * pProps = new OOXMLPropertySetImpl();
OOXMLValue::Pointer_t pVal( new OOXMLStarMathValue( ref ));
OOXMLProperty::Pointer_t pProp( new OOXMLPropertyImpl( NS_ooxml::LN_starmath, pVal, OOXMLPropertyImpl::ATTRIBUTE ));
pProps->add( pProp );
mpStream->props( writerfilter::Reference< Properties >::Pointer_t( pProps ));
}
}
void OOXMLFastContextHandlerMath::lcl_startFastElement(Token_t Element,
void OOXMLFastContextHandlerLinear::lcl_startFastElement(Token_t Element,
const uno::Reference< xml::sax::XFastAttributeList >& Attribs)
throw (uno::RuntimeException, xml::sax::SAXException)
{
......@@ -2402,7 +2383,7 @@ void OOXMLFastContextHandlerMath::lcl_startFastElement(Token_t Element,
++depthCount;
}
void OOXMLFastContextHandlerMath::lcl_endFastElement(Token_t Element)
void OOXMLFastContextHandlerLinear::lcl_endFastElement(Token_t Element)
throw (uno::RuntimeException, xml::sax::SAXException)
{
buffer.appendClosingTag( Element );
......@@ -2411,7 +2392,7 @@ void OOXMLFastContextHandlerMath::lcl_endFastElement(Token_t Element)
}
uno::Reference< xml::sax::XFastContextHandler >
OOXMLFastContextHandlerMath::lcl_createFastChildContext(Token_t,
OOXMLFastContextHandlerLinear::lcl_createFastChildContext(Token_t,
const uno::Reference< xml::sax::XFastAttributeList >&)
throw (uno::RuntimeException, xml::sax::SAXException)
{
......@@ -2420,12 +2401,39 @@ OOXMLFastContextHandlerMath::lcl_createFastChildContext(Token_t,
return xContextHandler;
}
void OOXMLFastContextHandlerMath::lcl_characters(const ::rtl::OUString& aChars)
void OOXMLFastContextHandlerLinear::lcl_characters(const ::rtl::OUString& aChars)
throw (uno::RuntimeException, xml::sax::SAXException)
{
buffer.appendCharacters( aChars );
}
/*
class OOXMLFastContextHandlerLinear
*/
OOXMLFastContextHandlerMath::OOXMLFastContextHandlerMath(OOXMLFastContextHandler* pContext)
: OOXMLFastContextHandlerLinear(pContext)
{
}
void OOXMLFastContextHandlerMath::process()
{
SvGlobalName name( SO3_SM_CLASSID );
comphelper::EmbeddedObjectContainer container;
rtl::OUString aName;
uno::Reference< embed::XEmbeddedObject > ref = container.CreateEmbeddedObject( name.GetByteSequence(), aName );
uno::Reference< uno::XInterface > component( ref->getComponent(), uno::UNO_QUERY );
if( oox::FormulaImportBase* import = dynamic_cast< oox::FormulaImportBase* >( component.get()))
import->readFormulaOoxml( buffer );
if (isForwardEvents())
{
OOXMLPropertySet * pProps = new OOXMLPropertySetImpl();
OOXMLValue::Pointer_t pVal( new OOXMLStarMathValue( ref ));
OOXMLProperty::Pointer_t pProp( new OOXMLPropertyImpl( NS_ooxml::LN_starmath, pVal, OOXMLPropertyImpl::ATTRIBUTE ));
pProps->add( pProp );
mpStream->props( writerfilter::Reference< Properties >::Pointer_t( pProps ));
}
}
}}
......
......@@ -641,15 +641,37 @@ private:
OOXMLFastContextHandler * getFastContextHandler() const;
};
/**
A class that converts from XFastParser/XFastContextHandler usage to a liner XML stream of data.
The purpose of this class is to convert the rather complex XFastContextHandler-based XML
processing that requires context subclasses, callbacks, etc. into a linear stream of XML tokens
that can be handled simply by reading the tokens one by one and directly processing them.
See the oox::formulaimport::XmlStream class documentation for more information.
Usage: Create a subclass of OOXMLFastContextHandlerLinear, reimplemented getType() to provide
type of the subclass and process() to actually process the XML stream. Also make sure to
add a line like the following to model.xml (for class OOXMLFastContextHandlerMath):
class OOXMLFastContextHandlerMath: public OOXMLFastContextHandlerProperties
<resource name="CT_OMath" resource="Math"/>
@since 3.5
*/
class OOXMLFastContextHandlerLinear: public OOXMLFastContextHandlerProperties
{
public:
explicit OOXMLFastContextHandlerMath(OOXMLFastContextHandler * pContext);
virtual string getType() const { return "Math"; }
explicit OOXMLFastContextHandlerLinear(OOXMLFastContextHandler * pContext);
/**
Return the type of the class, as written in model.xml .
*/
virtual string getType() const = 0;
protected:
virtual void process();
/**
Called when the tokens for the element, its content and sub-elements have been linearized
and should be processed. The data member @ref buffer contains the converted data.
*/
virtual void process() = 0;
virtual void lcl_startFastElement(Token_t Element, const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
throw (uno::RuntimeException, xml::sax::SAXException);
......@@ -662,11 +684,21 @@ protected:
virtual void lcl_characters(const ::rtl::OUString & aChars) throw (uno::RuntimeException, xml::sax::SAXException);
private:
// should be private, but not much point in making deep copies of it
oox::formulaimport::XmlStreamBuilder buffer;
private:
int depthCount;
};
class OOXMLFastContextHandlerMath: public OOXMLFastContextHandlerLinear
{
public:
explicit OOXMLFastContextHandlerMath(OOXMLFastContextHandler * pContext);
virtual string getType() const { return "Math"; }
protected:
virtual void process();
};
}}
#endif // INCLUDED_OOXML_FAST_CONTEXT_HANDLER_HXX
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment