Difference between revisions of "XML and Filter"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (The main Program)
(4 intermediate revisions by one other user not shown)
Line 147: Line 147:
 
</source>
 
</source>
  
This code installs an eventListener with a  com.sun.star.xml.sax.XDocumentHandler interface.The corresponding IDL documentation of this interface is :
+
This code installs an eventListener with a  <idl>com.sun.star.xml.sax.XDocumentHandler</idl> interface.The corresponding IDL documentation of this interface is :
  
 
<source lang="idl">
 
<source lang="idl">
Line 389: Line 389:
 
</office:document>
 
</office:document>
 
</source>
 
</source>
Please note that, at the moment it's the only XML program I can send to Openoffice and every others don't work.
+
{{Warn|Please note that, at the moment it's the only XML program I can send to Openoffice and every others don't work.}}
 
Have a look [[FastParser#Implementing_an_xml_format_import_filter_with_the_fast_sax_api|here]] for SAX implementation documentation
 
Have a look [[FastParser#Implementing_an_xml_format_import_filter_with_the_fast_sax_api|here]] for SAX implementation documentation
  
Line 477: Line 477:
 
// close document
 
// close document
 
xHandler->endDocument();
 
xHandler->endDocument();
</code>
+
</source>
  
 
The first difficulty is with the instruction :
 
The first difficulty is with the instruction :
<code>[cpp]
+
<source lang="cpp">
 
// C++
 
// C++
 
SvXMLAttributeList aAttrList;
 
SvXMLAttributeList aAttrList;
Line 789: Line 789:
  
 
[[Category:Filter]]
 
[[Category:Filter]]
 +
[[Category:Cpp]]
 
[[Category:Office Open XML]]
 
[[Category:Office Open XML]]

Revision as of 10:13, 11 July 2018

We want in this chapter examine how XML and filters work.

Parsing a XML File with SAX

To start, have a look at :

Using UNO's Xml sax parser via the API

It's a Danny Brewer's OooBasic program which use SAX. To avoid searching I begin to give the code here.

Sax and OooBasic (Danny Brewer)

This example demonstrates several things.

  • Using the UCB's SimpleFileAccess to read from a file. (UCB = Universal Content Broker)
  • Using OOo's XML sax parser.
  • Creating a listener with Basic's CreateUnoListener() function.

If you have never used a Sax Xml parser before, then this example may not be for you.

OOo has a Sax Xml parser available via. the Uno api. The following program, in Basic, shows how to use it to parse an Xml document. As the document is parsed, events are fired which print little annoying dialog boxes on the screen. (Be sure to parse a VERY SMALL xml document so that you only have to click OK about a dozen or so times!)

REM Listing 1 Using SAX with OooBasic
REM  *****  BASIC  *****
REM  **** Danny Brewer (Mon Jan 12, 2004) ****
Sub Main 
  cXmlFile = "C:\TestData.xml"  
  cXmlUrl = ConvertToURL( cXmlFile ) 
  ReadXmlFromUrl( cXmlUrl ) 
End Sub 
 
' This routine demonstrates how to use the Universal Content Broker's 
' SimpleFileAccess to read from a local file. 
Sub ReadXmlFromUrl( cUrl ) 
' The SimpleFileAccess service provides mechanisms to open, read, write files, 
' as well as scan the directories of folders to see what they contain. 
' The advantage of this over Basic's ugly file manipulation is that this 
' technique works the same way in any programming language. 
' Furthermore, the program could be running on one machine, while the SimpleFileAccess 
' accesses files from the point of view of the machine running OOo, not the machine 
' where, say a remote Java or Python program is running. 
  oSimpleFileAccess = createUnoService( "com.sun.star.ucb.SimpleFileAccess" )  
' Open input file. 
  oInputStream = oSimpleFileAccess.openFileRead( cUrl ) 
 
ReadXmlFromInputStream( oInputStream ) 
  oInputStream.closeInput() 
End Sub 
 
Sub ReadXmlFromInputStream( oInputStream ) 
' Create a Sax Xml parser. 
  oSaxParser = createUnoService( "com.sun.star.xml.sax.Parser" ) 
' Create a document event handler object. 
' As methods of this object are called, Basic arranges 
' for global routines (see below) to be called. 
  oDocEventsHandler = CreateDocumentHandler() 
' Plug our event handler into the parser. 
' As the parser reads an Xml document, it calls methods 
' of the object, and hence global subroutines below 
' to notify them of what it is seeing within the Xml document. 
  oSaxParser.setDocumentHandler( oDocEventsHandler ) 
' Create an InputSource structure. 
  oInputSource = createUnoStruct( "com.sun.star.xml.sax.InputSource" ) 
  With oInputSource 
    .aInputStream = oInputStream ' plug in the input stream 
  End With 
' Now parse the document. 
' This reads in the entire document. 
' Methods of the oDocEventsHandler object are called as 
' the document is scanned. 
  oSaxParser.parseStream( oInputSource ) 
End Sub 
 
'================================================== 
'  Xml Sax document handler. 
'================================================== 
' Global variables used by our document handler. 
' 
' Once the Sax parser has given us a document locator, 
' the glLocatorSet variable is set to True, 
' and the goLocator contains the locator object. 
' 
' The methods of the locator object has cool methods 
' which can tell you where within the current Xml document 
' being parsed that the current Sax event occured. 
' The locator object implements com.sun.star.xml.sax.XLocator. 
' 
Private goLocator As Object 
Private glLocatorSet As Boolean 
 
' This creates an object which implements the interface 
' com.sun.star.xml.sax.XDocumentHandler. 
' The doucment handler is returned as the function result. 
Function CreateDocumentHandler() 
' Use the CreateUnoListener function of Basic. 
' Basic creates and returns an object that implements a particular interface. 
' When methods of that object are called, 
' Basic will call global Basic functions whose names are the same 
' as the methods, but prefixed with a certian prefix. 
  oDocHandler = CreateUnoListener( "DocHandler_", "com.sun.star.xml.sax.XDocumentHandler" ) 
  glLocatorSet = False 
  CreateDocumentHandler() = oDocHandler 
End Function 
 
'================================================== 
'  Methods of our document handler call these 
'  global functions. 
'  These methods look strangely similar to 
'  a SAX event handler. ;-) 
'  These global routines are called by the Sax parser 
'  as it reads in an XML document. 
'  These subroutines must be named with a prefix that is 
'  followed by the event name of the com.sun.star.xml.sax.XDocumentHandler interface. 
'================================================== 
Sub DocHandler_startDocument() 
  Print "Start document" 
End Sub 
 
Sub DocHandler_endDocument() 
' Print "End document" 
End Sub 
 
Sub DocHandler_startElement( cName As String, oAttributes As com.sun.star.xml.sax.XAttributeList ) 
  Print "Start element", cName 
End Sub 
 
Sub DocHandler_endElement( cName As String ) 
'  Print "End element", cName 
End Sub 
 
Sub DocHandler_characters( cChars As String ) 
End Sub 
 
Sub DocHandler_ignorableWhitespace( cWhitespace As String ) 
End Sub 
 
Sub DocHandler_processingInstruction( cTarget As String, cData As String ) 
End Sub 
 
Sub DocHandler_setDocumentLocator( oLocator As com.sun.star.xml.sax.XLocator ) 
' Save the locator object in a global variable. 
' The locator object has valuable methods that we can 
' call to determine 
  goLocator = oLocator 
  glLocatorSet = True 
End Sub

This code installs an eventListener with a com.sun.star.xml.sax.XDocumentHandler interface.The corresponding IDL documentation of this interface is :

//Listing 2 IDL XdocumentHandler Interface
// IDL
module com {  module sun {  module star {  module xml {  module sax {  
interface XDocumentHandler: com::sun::star::uno::XInterface
{ 
	void startDocument() 
			raises( com::sun::star::xml::sax::SAXException ); 
	void endDocument() 
			raises( com::sun::star::xml::sax::SAXException ); 
	void startElement( [in] string aName, 
			 [in] com::sun::star::xml::sax::XAttributeList xAttribs ) 
			raises( com::sun::star::xml::sax::SAXException ); 
	void endElement( [in] string aName ) 
			raises( com::sun::star::xml::sax::SAXException ); 
	void characters( [in] string aChars ) 
			raises( com::sun::star::xml::sax::SAXException ); 
	void ignorableWhitespace( [in] string aWhitespaces ) 
			raises( com::sun::star::xml::sax::SAXException ); 
	void processingInstruction( [in] string aTarget, 
			 [in] string aData ) 
			raises( com::sun::star::xml::sax::SAXException ); 
	void setDocumentLocator( [in] com::sun::star::xml::sax::XLocator xLocator ) 
			raises( com::sun::star::xml::sax::SAXException );  
}; 
}; }; }; }; };

You can find the complete implementation of this interface in the OooBasic code of Listing 1. We have then to write an Event Listener in C++. If you want to remember how Event Listener works in C++ have a look here.

The C++ Event Listener

We have first to create a C++ class :

//Listing 3 Class Definition (could be in hxx file)
// C++
class XFlatXml : public ::cppu::WeakImplHelper1< ::com::sun::star::xml::sax::XDocumentHandler> 
{ 
private: 
 Reference< XMultiServiceFactory > xMSF; 
public: 
 
 XFlatXml( const Reference< XMultiServiceFactory > &r ) : xMSF( r ) 
 {} 
 
// Reference < com::sun::star::io::XOutputStream > xOutputStream; 
  virtual void SAL_CALL startDocument() throw (SAXException,RuntimeException) ; 
  virtual void SAL_CALL endDocument() throw (SAXException,RuntimeException); 
  virtual void SAL_CALL startElement(const OUString& str, const Reference<XAttributeList>& attriblist) throw (SAXException,RuntimeException); 
  virtual void SAL_CALL endElement(const OUString& str) throw (SAXException,RuntimeException); 
  virtual void SAL_CALL characters(const OUString& str) throw (SAXException,RuntimeException); 
  virtual void SAL_CALL ignorableWhitespace(const OUString& str) throw (SAXException,RuntimeException); 
  virtual void SAL_CALL processingInstruction(const OUString& str, const OUString& str2) throw (SAXException,RuntimeException) ; 
  virtual void SAL_CALL setDocumentLocator(const Reference<XLocator>& doclocator) throw (SAXException,RuntimeException) ; 
};

A C++ correponding implementation code could be

//Listing 4 The Event Listener Class Implementation
// C++
void XFlatXml::startDocument() throw (SAXException,RuntimeException){ 
  printf("StartDocument\n"); 
} 
 
void XFlatXml::endDocument() throw (SAXException,RuntimeException){ 
  printf("EndDocument\n"); 
} 
 
void XFlatXml::startElement(const OUString& str, const Reference<XAttributeList>& attriblist) throw (SAXException,RuntimeException){ 
  Ostring OStr = OUStringToOString ( str,RTL_TEXTENCODING_UTF8); 
  cout<< "StartElement : <" << OStr << " "; 
  for (short i=0;i<attriblist->getLength();i++){ 
    OStr = OUStringToOString ( attriblist->getNameByIndex(i),RTL_TEXTENCODING_UTF8); 
    cout << OStr <<"="; 
    OStr = OUStringToOString ( attriblist->getValueByIndex(i),RTL_TEXTENCODING_UTF8); 
    cout << OStr; 
  } 
  cout << ">" << endl; 
} 
 
void XFlatXml::endElement(const OUString& str) throw (SAXException,RuntimeException) { 
  Ostring OStr = OUStringToOString ( str,RTL_TEXTENCODING_UTF8); 
  cout<< "EndElement : </" << OStr << ">" << endl;  
} 
 
void XFlatXml::characters(const OUString& str) throw (SAXException,RuntimeException) { 
  OString OStr = OUStringToOString ( str,RTL_TEXTENCODING_UTF8); 
  cout<< "Characers : " << OStr << endl; 
} 
 
void XFlatXml::ignorableWhitespace(const OUString& str) throw (SAXException,RuntimeException){ 
  printf("ignorableWhitespace\n"); 
} 
 
void XFlatXml::processingInstruction(const OUString& str, const OUString& str2) throw (SAXException,RuntimeException) { 
  printf("processingInstruction\n"); 
 
} 
 
void XFlatXml::setDocumentLocator(const Reference<XLocator>& doclocator) throw (SAXException,RuntimeException) { 
  printf("setDocumentLocator\n"); 
}

Now it's time to make this event listener working.

Main Program

//Listing 5  The Main Program
// C++ 
int main( ) 
{ 
//retrieve an instance of the remote service manager 
  Reference< XMultiServiceFactory > rOfficeServiceManager; 
  rOfficeServiceManager = ooConnect(); 
  OSL_ENSURE(rOfficeServiceManager.is(), "Unable to connected to the office\n"); 
 
// Installing our new XDocumentHandler 
  XFlatXml *xListener = new XFlatXml(rOfficeServiceManager); 
  Reference< XDocumentHandler > xHandler = static_cast< XDocumentHandler* > ( xListener ); 
// getting oSimpleFileAcess 
  // com.sun.star.ucb.XSimpleFileAccess \ added in makefile 
  // #include <com/sun/star/ucb/XSimpleFileAccess.hpp> added in this file 
  // using namespace com::sun::star::ucb; added in this file 
  Reference< XSimpleFileAccess > xSFI( rOfficeServiceManager->createInstance 
       (OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess")),UNO_QUERY); 
  OSL_ENSURE(xSFI.is(), "Unable to get SimpleFileAcessService\n"); 
 
  // Don't forget #include <osl/file.hxx>
  OUStr sUrl;
  osl::FileBase::getFileURLFromSystemPath(
                 OUString::createFromAscii("/home/smoutou/TestData.xml"),sUrl);
 
// getting oInputStream 
  // using namespace com::sun::star::io; added in this file 
  Reference <XInputStream > oInputStream=xSFI->openFileRead(sUrl); 
 
// oSaxParser = createUnoService( "com.sun.star.xml.sax.Parser" ) 
  // com.sun.star.xml.sax.XParser \ added in Makefile 
  //#include <com/sun/star/xml/sax/XParser.hpp> added in this file 
  Reference < XParser > oSaxParser( rOfficeServiceManager->createInstance 
         ( OUString::createFromAscii( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY ); 
  OSL_ENSURE(oSaxParser.is(), "Unable to get Sax Parser\n"); 
  oSaxParser->setDocumentHandler( xHandler ); 
 
 // com.sun.star.xml.sax.InputSource \ added in Makefile 
 // #include <com/sun/star/xml/sax/InputSource.hpp> added in this file 
  struct InputSource oInputSource; 
  oInputSource.aInputStream = oInputStream; 
 
  oSaxParser->parseStream(oInputSource); 
  oInputStream->closeInput(); 
  return 0; 
}

To test how the program works we have to provide a XML file. We can take Danny's example :

Listing 6 XML file for test

<Employees> 
  <Employee id="101"> 
    <Name> 
      <First>John</First> 
      <Last>Smith</Last> 
    </Name> 
    <Address> 
      <Street>123 Main</Street> 
      <City>Lawrence</City> 
      <State>KS</State> 
      <Zip>66049</Zip> 
    </Address> 
    <Phone type="Home">785-555-1234</Phone> 
  </Employee> 
<Employee id="102"> 
  <Name> 
    <First>Bob</First> 
    <Last>Jones</Last> 
  </Name> 
  <Address> 
    <Street>456 Puke Drive</Street> 
    <City>Lawrence</City> 
    <State>KS</State> 
    <Zip>66049</Zip> 
  </Address> 
  <Phone type="Home">785-555-1235</Phone> 
  </Employee> 
</Employees>

This file prints out in a shell :

Listing 7 Result

setDocumentLocator 
StartDocument 
StartElement : <Employees > 
Characers : 
 
Characers : 
StartElement : <Employee id=101> 
Characers : 

Characers : 
StartElement : <Name > 
Characers : 
 
Characers : 
StartElement : <First > 
Characers : John 
EndElement : </First> 
Characers : 
 
Characers : 
StartElement : <Last > 
Characers : Smith 
EndElement : </Last> 
Characers : 
 
Characers : 
..... 

Writing directly XML Instructions in a Document

Since I read OpenOffice filters using the XML based file format I wanted to understand exactly the concepts and make some working code. It was for me a very hard task : I have to read extensively OOo source code because the example code given in the article cannot work without little corrections. I finally found the clues in :

  • <OOB680_m5>/filter/source/xsltdialog (attributelist.hxx and the corresponding attributelist.cxx)
  • <OOB680_m5>/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx

Our Goal and the corresponding Code

Our goal is very well described in the comments of the Listing 9 below (given again in Listing 8): send the XML text in a document which gives the famous « Hello World! » into a writer document. The difficulty is, we don't want to see all the Listing 8 in our writer document but only the text « Hello World! » as a paragraph : this is the meaning of the corresponding XML text.

Listing 8 What we would want to send in a Writer Document for interpretation

<office:document 
      office:class="text" 
      xmlns:office="http://openoffice.org/2000/office" 
      xmlns:text="http://openoffice.org/2000/text" >
   <office:body>
     <text:p>Hello World!</text:p>
   </office:body>
</office:document>
Documentation caution.png Please note that, at the moment it's the only XML program I can send to Openoffice and every others don't work.

Have a look here for SAX implementation documentation

I provide now the code from the XML article where I have added comments which show the little errors in the code.

//Listing 9 http://xml.openoffice.org/filter/Code
// C++
using namespace ::com::sun::star;
 
// instantiate the XML import component !!!! fell a ';' !!!!
::rtl::OUString sService =
    ::rtl::OUString::createFromAscii("com.sun.star.comp.Writer.XMLImporter")
// !!!!!!!!! xHandler instead of xImport because xHandler is used below
uno::Reference<xml::sax::XDocumentHandler> xImport(
    xServiceFactory->createInstance(sService), uno::UNO_QUERY );
ASSERT( xImport.is(), "can't instantiate XML import" );
 
// OK. Now we have the import. Let's make a real simple document.
 
// a few comments:
// 1. We will use string constants from xmloff/xmlkywd.hxx
// 2. For convenience, we'll use a globally shared attribute list from the 
//    xmloff project (xmloff/attrlist.hxx)
// 3. In a real project, we would pre-construct our OUString, rather than use
//    the slow createFromAscii(…) method every time.
 
// We will write the following document: (the unavoidable 'Hello World!')
// <office:document 
//      office:class="text" 
//      xmlns:office="http://openoffice.org/2000/office" 
//      xmlns:text="http://openoffice.org/2000/text" >
//   <office:body>
//     <text:p>Hello World!</text:p>
//   </office:body>
// </office:document>
 
SvXMLAttributeList aAttrList;
 
xHandler->startDocument();
 
// our first element: first build up the attribute list, then start the element
// DON'T FORGET TO ADD THE NAMESPACES!
aAttrList.AddAttribute(
    ::rtl::OUString::createFromAscii("xmlns:office"), 
    ::rtl::OUString::createFromAscii("CDATA"), 
    ::rtl::OUString::createFromAscii("http://openoffice.org/2000/office") );
aAttrList.AddAttribute(
    ::rtl::OUString::createFromAscii("xmlns:text"), 
    ::rtl::OUString::createFromAscii("CDATA"), 
    ::rtl::OUString::createFromAscii("http://openoffice.org/2000/text") );
aAttrList.AddAttribute(
    ::rtl::OUString::createFromAscii("office:class"), 
    ::rtl::OUString::createFromAscii("CDATA"), 
        ::rtl::OUString::createFromAscii("text") );
xHandler->startElement(
    ::rtl::OUString::createFromAscii("office:document"),
    aAttrList );
 
// body element (no attributes)
aAttrList.clear();
xHandler->startElement(
    ::rtl::OUString::createFromAscii("office:body"),
    aAtrList );
 
// paragraph element (no attributes)
aAttrList.clear();
xHandler->startElement(
    ::rtl::OUString::createFromAscii("text:p"),
    aAtrList );
 
// write text
xHandler->characters(
    ::rtl::OUString::createFromAscii("Hello World!") );
 
// close paragraph !!!!!!! Error here ',' instead of ';' !!!!!
xHandler->startElement(
    ::rtl::OUString::createFromAscii("text:p"),
 
// close body
xHandler->endElement(
    ::rtl::OUString::createFromAscii("office:body") );
 
// close document element
xHandler->endElement(
    ::rtl::OUString::createFromAscii("office:document") );
 
// close document
xHandler->endDocument();

The first difficulty is with the instruction :

// C++
SvXMLAttributeList aAttrList;

Why ? Because when writing a C++ automation program we haven't the SvXMLAttributeList type defined. Then we have to write it. I have take the corresponding code from OOo source code : <OOB680_m5>/filter/source/xsltdialog (attributelist.hxx and the corresponding attributelist.cxx) but because the reader could not have downloaded the corresponding code, I provide it completely here.

The AttributeList Class

First we provide the corresponding class :

//Listing 10 AttributList class
// C++
struct AttributeList_Impl
{
	AttributeList_Impl()
	{
		// performance improvement during adding
		vecAttribute.reserve(20);
	}
	vector<struct TagAttribute_Impl> vecAttribute;
};
 
//  From  <OOB680_m5>/filter/source/xsltdialog/attributelist.hxx 
class AttributeList : public WeakImplHelper1 < XAttributeList >
{
	AttributeList_Impl *m_pImpl;
public:
	AttributeList();
	virtual ~AttributeList();
 
	// methods that are not contained in any interface
	void AddAttribute( const OUString &sName , const OUString &sType , const OUString &sValue );
	void Clear();
	void RemoveAttribute( const OUString sName );
	void SetAttributeList( const Reference< XAttributeList > & );
	void AppendAttributeList( const Reference< XAttributeList > & );
 
	// ::com::sun::star::xml::sax::XAttributeList
	virtual sal_Int16 SAL_CALL getLength(void) 
		throw( RuntimeException );
	virtual OUString SAL_CALL getNameByIndex(sal_Int16 i) 
		throw( RuntimeException );
	virtual OUString SAL_CALL getTypeByIndex(sal_Int16 i) 
		throw( RuntimeException );
	virtual OUString SAL_CALL getTypeByName(const OUString& aName) 
		throw( RuntimeException );
	virtual OUString SAL_CALL getValueByIndex(sal_Int16 i) 
		throw( RuntimeException );
	virtual OUString SAL_CALL getValueByName(const OUString& aName) 
		throw( RuntimeException );
 
};

The complete implementation is :

//Listing 11 AttributList class Implementation
// C++
//*************** AttributeList impementation
// from    <OOB680_m5>/filter/source/xsltdialog/attributelist.hxx 
sal_Int16 SAL_CALL AttributeList::getLength(void) throw( RuntimeException ){
	return m_pImpl->vecAttribute.size();
}
 
OUString SAL_CALL AttributeList::getNameByIndex(sal_Int16 i) throw( RuntimeException ){
	if( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size()) ) {
		return m_pImpl->vecAttribute[i].sName;
	}
	return OUString();
}
 
OUString SAL_CALL AttributeList::getTypeByIndex(sal_Int16 i) throw( RuntimeException ){
	if( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size() ) ) {
		return m_pImpl->vecAttribute[i].sType;
	}
	return OUString();
}
 
OUString SAL_CALL  AttributeList::getValueByIndex(sal_Int16 i) throw( RuntimeException ){
	if( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size() ) ) {
		return m_pImpl->vecAttribute[i].sValue;
	}
	return OUString();
}
 
OUString SAL_CALL AttributeList::getTypeByName( const OUString& sName ) throw( RuntimeException ){
	vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin();
 
	for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
		if( (*ii).sName == sName ) {
			return (*ii).sType;
		}
	}
	return OUString();
}
 
OUString SAL_CALL AttributeList::getValueByName(const OUString& sName) throw( RuntimeException ){
	vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin();
 
	for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
		if( (*ii).sName == sName ) {
			return (*ii).sValue;
		}
	}
	return OUString();
}
 
AttributeList::AttributeList(){
	m_pImpl = new AttributeList_Impl;
}
 
AttributeList::~AttributeList(){
	delete m_pImpl;
}
 
void AttributeList::AddAttribute(const OUString &sName ,
                                 const OUString &sType ,
                                 const OUString &sValue ){
	m_pImpl->vecAttribute.push_back( TagAttribute_Impl( sName , sType , sValue ) );
}
 
void AttributeList::Clear(){
	m_pImpl->vecAttribute.clear();
 
	OSL_ENSURE( ! getLength(), "Length > 0 after AttributeList::Clear!");
}
 
void AttributeList::RemoveAttribute( const OUString sName ){
	vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin();
 
	for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
		if( (*ii).sName == sName ) {
			m_pImpl->vecAttribute.erase( ii );
			break;
		}
	}
}
 
void AttributeList::SetAttributeList( const Reference< XAttributeList >  &r ){
	Clear();
	AppendAttributeList( r );
}
 
void AttributeList::AppendAttributeList( const Reference< XAttributeList >  &r ){
	OSL_ENSURE( r.is(), "r isn't!" );
 
	sal_Int32 nMax = r->getLength();
	sal_Int32 nTotalSize = m_pImpl->vecAttribute.size() + nMax;
	m_pImpl->vecAttribute.reserve( nTotalSize );
 
	for( sal_Int16 i = 0 ; i < nMax ; i ++ ) {
		m_pImpl->vecAttribute.push_back( TagAttribute_Impl(
			r->getNameByIndex( i ) ,
			r->getTypeByIndex( i ) ,
			r->getValueByIndex( i )));
	}
	OSL_ENSURE( nTotalSize == getLength(), "nTotalSize != getLength()");
}

The main Program

To make a complete automation program, we have to provide a main program.

//Listing 12  The corrected Listing 9 program for automation.
// C++
int main( )
{
//retrieve an instance of the remote service manager
    Reference< XMultiServiceFactory > rOfficeServiceManager;
    rOfficeServiceManager = ooConnect();
    OSL_ENSURE(rOfficeServiceManager.is(), "Unable to connected to the office\n");
//get the desktop service using createInstance returns an XInterface type
    Reference< XInterface  > Desktop = rOfficeServiceManager->createInstance(
    OUString::createFromAscii( "com.sun.star.frame.Desktop" ));
 
//query for the XComponentLoader interface
    Reference< XComponentLoader > rComponentLoader (Desktop, UNO_QUERY);
    OSL_ENSURE(rComponentLoader.is() , "Unable to get XComponentloader service\n");
 
   Reference< XDesktop > rDesktop(Desktop,UNO_QUERY);
   OSL_ENSURE(rDesktop.is() , "Unable to get XDesktop service\n");
 
//get an instance of the OOowriter document
    Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
	OUString::createFromAscii("private:factory/swriter"),
        OUString::createFromAscii("_blank"),
        0,
        Sequence < ::com::sun::star::beans::PropertyValue >());
 
// instantiate the XML import component 
    OUString sService = OUString::createFromAscii("com.sun.star.comp.Writer.XMLImporter");
    Reference<XDocumentHandler> xImport(
			rOfficeServiceManager->createInstance(sService), UNO_QUERY );
    OSL_ENSURE( xImport.is(), "can't instantiate XML import" );
 
// ******** These important lines where not in the original listing
// I find the clue in <OOB680_m5>/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx
// #include <com/sun/star/document/XImporter.hpp> added in this file
// using namespace com::sun::star::document; added in this file
// com.sun.star.document.XImporter \ added in the MakeFile
    Reference < XImporter > xImporter( xImport, UNO_QUERY );
    xImporter->setTargetDocument ( xWriterComponent );
 
// OK. Now we have the import. Let's make a real simple document.
 
// a few comments:
// 1. We will use string constants from xmloff/xmlkywd.hxx
// 2. For convenience, we'll use a globally shared attribute list from the 
//    xmloff project (xmloff/attrlist.hxx)
// 3. In a real project, we would pre-construct our OUString, rather than use
//    the slow createFromAscii(\x{2026}) method every time.
 
// We will write the following document: (the unavoidable 'Hello World!')
// <office:document 
//      office:class="text" 
//      xmlns:office="http://openoffice.org/2000/office" 
//      xmlns:text="http://openoffice.org/2000/text" >
//   <office:body>
//     <text:p>Hello World!</text:p>
//   </office:body>
// </office:document>
 
 
    xImport->startDocument();
 
//  SvXMLAttributeList aAttrList; in http://xml.openoffice.org/filter/
// It is possible to find the corresponding code in source :
//    <OOB680_m5>/filter/source/xsltdialog/attributelist.hxx and
//    <OOB680_m5>/filter/source/xsltdialog/attributelist.cxx
    AttributeList *xAttrList = new AttributeList();
    Reference< XAttributeList > aAttrList = static_cast< XAttributeList* > ( xAttrList );
 
// our first element: first build up the attribute list, then start the element
// DON'T FORGET TO ADD THE NAMESPACES!
 
xAttrList->AddAttribute(
    OUString::createFromAscii("xmlns:office"), 
    OUString::createFromAscii("CDATA"), 
    OUString::createFromAscii("http://openoffice.org/2000/office") );
 
xAttrList->AddAttribute(
    OUString::createFromAscii("xmlns:text"), 
    OUString::createFromAscii("CDATA"), 
    OUString::createFromAscii("http://openoffice.org/2000/text") );
xAttrList->AddAttribute(
    OUString::createFromAscii("office:class"), 
    OUString::createFromAscii("CDATA"), 
    OUString::createFromAscii("text") );
 
xImport->startElement(
    OUString::createFromAscii("office:document"),
    aAttrList );
 
// body element (no attributes)
aAttrList.clear();
xImport->startElement(
    OUString::createFromAscii("office:body"),
    aAttrList );
 
// paragraph element (no attributes)
aAttrList.clear();
xImport->startElement(
    OUString::createFromAscii("text:p"),
    aAttrList );
 
// write text
xImport->characters(
    OUString::createFromAscii("Hello World!") );
 
// close paragraph
xImport->endElement(
    OUString::createFromAscii("text:p") );
 
// close body
xImport->endElement(
    OUString::createFromAscii("office:body") );
 
// close document element
xImport->endElement(
    OUString::createFromAscii("office:document") );
 
// close document
xImport->endDocument();
 
  return 0;
}

It's easy to find the program ooConnect() in this document.

TODO: There's more to come here ...

See also

Personal tools