SharePoint Development from a Documentation Perspective

Andrew May

Importing Content into OneNote 2003 SP1 Preview

Importing Content into OneNote 2003 SP1 Preview

  • Comments 35

The OneNote Service Pack 1 Preview is currently available for download. This Service Pack includes some cool new features that'll be of great interest to developers. We've already been seeing some questions about this new functionality in the newsgroups, so we posting a draft of the article that will appear on MSDN once SP1 is released. Keep in mind that, while we've tried to make sure the information is as accurate and complete as possible, it is a draft document, and provided as such. Void where prohibited.

 

Anyway, here's the article:

Importing Content into OneNote 2003 SP1 Preview

Applies To:

    Microsoft Office OneNote 2003 SP1

Summary:    Learn about the new extensibility features available for developers in Microsoft Office OneNote 2003 SP1. The new OneNote 1.1 Type Library includes functionality which enables you to programmatically import images, ink, and HTML into OneNote.

Introduction

For the Service Pack 1 (SP1) Preview, OneNote 2003 has added extensibility functionality that enables applications to interoperate with it in an important, fundamental way—they can add content to OneNote notebooks. You can now push content to OneNote that includes html, images, and even ink (such as from a Tablet PC). You can even create the folder, section, or page onto which you want to place your content.

Note These extensibility features are only available in the OneNote 2003 Service Pack 1 Preview. You can upgrade to the OneNote SP1 Preview here.

Using the CSimpleImporterClass

OneNote SP1 exposes the OneNote 1.1 Type Library, which consists of a single class, CSimpleImporterClass, which enables you to programmatically add content to a OneNote notebook. You can add text in html form, images, and even ink from a Tablet PC. The CSimpleImporterClass enables you to specify where in the notebook you want to place the content; you can even create new folders, sections, and pages for content, and then programmatically display the desired page. OneNote’s import functionality also lets you later delete the content you import.

The CSimpleImporterClass consists of two methods:

·         Import, which enables you to add, update, or delete images, ink, and html content to a specific page in a OneNote folder and section.

·         NavigateToPage, which enables you to display a specified page.

To use the CSimpleImportClass, you must add a reference to the OneNote 1.1 Type Library to your project. To add a reference, in Visual Studio .NET, on the Solution Explorer window, right-click References and then click Add Reference. On the COM tab, select OneNote 1.1 Type Library in the list, click Select, and then click OK.

While this article focuses on implementing OneNote’s import functionality using .NET languages, you can also use the OneNote 1.1 Type Library with unmanaged code, such as Visual Basic 6.0 or Visual C++.

The Data Import Schema

The Import method has the following signature:

Import (bstrXml as String)

The method takes an xml string describing the content object(s) you want to import, as well as the location in the notebook where you want them placed. You can also use the import command to delete objects you have previously placed in the notebook.

When called, OneNote executes the Import method with minimal intrusion on the user. OneNote does open if it is not already opened, which means the OneNote splash screen displays, but OneNote does not assume focus. Nor does it change the user’s location in the notebook if OneNote is already running. To change the focus of the OneNote application to the new content, use the NavigateToPage method, discussed later.

If the Import method fails, OneNote does not display an error to the user. However, the COM interface does return an “Unknown Error” to the application making the call.

The figure below outlines the xml schema to which the import file must adhere.

 

Figure 1. XML Schema Structure of the Import Root Element

 

 

Figure 2. Schema Structure of the PlaceObjects Element

The OneNote data import schema can be found at The OneNote 1.1 SimpleImport XML Schema.

Note The namespace for the Import method will be different in the final version of OneNote SP1 from what it is in the SP1 Preview.

The current namespace for the OneNote SP1 Preview is:

http://schemas.microsoft.com/office/onenote/01/2004/import

While the final namespace for OneNote SP1 will be:

http://schemas.microsoft.com/office/onenote/2004/import

Be advised that if you’re programming against the Preview namespace, you must update your code for the new namespace in order for it to be compatible with the final OneNote SP1.

There are two elements directly below the root <Import> element. Use the first element, <EnsurePage>, to make sure the folder, section, and page on which you want to place content exists. Use the second element, <PlaceObjects>, to actually place or delete objects from the page. The schema requires that the root element contain either at least one <EnsurePage> or <PlaceObjects> element. Any <EnsurePage> elements must appear before any <PlaceObjects> element.

Creating Folders and Pages for Content

Before you import content, the target pages for that content must exist in the OneNote notebook. Use the <EnsurePage> element to verify or create the target pages for your content. For each page you specify in an <EnsurePage> element, OneNote checks to determine if the page exists, and if not, creates it. You can even create new notebook folders and sections by specifying folders or sections that don’t exist.

You are required to pass OneNote a string representing the path to the desired page, as well as a GUID for that page. If the path is not fully-qualified, OneNote assumes the string starts from the notebook root location for the user. Additionally, you can specify the title, date, reading direction, and page placement relative to other pages in the notebook.

By default, OneNote inserts each new page at the end of the specified section. If you specify a page GUID for the insertAfter attribute, OneNote inserts the new page as a sub-page of the page whose GUID you specified. In such cases, OneNote labels the sub-page with the title and date of the page after which it’s inserted, rather than what you specify in the title and date attributes for the sub-page. If the page you specify does not exist (for example, if it was never added, or the user deleted it), then OneNote ignores the insertAfter attribute and inserts the new page at the end of the specified section, with any specified title and date values.

Consider the following example. This <EnsurePage> element specifies a page in the OneNote section title Negotiations, in the folder Johnson Contract, in the user’s root notebook folder. The page is titled “Budget Concerns”.

      <EnsurePage path="Johnson Contract\Negotiations.one"

                  guid="{8FDD3C41-5BB5-4595-B019-7E7E9BC9D38E}"

                  title="Budget Concerns"/>

OneNote uses the optional attributes of the <EnsurePage> element if it creates the page you specify. If you specify attributes for an existing page, OneNote leaves the page unchanged. For example, if you use a GUID for an existing page, and specify a title that differs from that page’s current title, OneNote does not change the page title.

Additionally, OneNote only searches the path you specify for the desired page GUID. If the page GUID does not exist in the specified section, OneNote creates it; it does not look for the GUID in other sections of the notebook.

You can use multiple <EnsurePage> elements to create multiple pages within the OneNote notebook. You must verify or create the page before you can place content on it. You are not required to include an <EnsurePage> element for each page on which you want to place content. However, if you use the <PlaceObjects> element to try and place objects on a page that does not exist, the Import method fails. In some cases, this may be the desired outcome; for example, if you only wanted to update content on a page if the page still exists, and not add the content if the page has been deleted by the user.

Placing Content on Pages

Once you’ve ensured that the pages onto which you want to import data exist in the OneNote notebook, you can start placing objects on them using the <PlaceObjects> element. Multiple objects can be imported to multiple pages if desired. You create a <PlaceObjects> element for each page on which you want to place content. Same as the <EnsurePage> element, <PlaceObjects> has two required attributes: the path to the page, and the guid assigned to the page. You must include at least one <Object> element in each <PlaceObjects> element.

To create the xml string that describes the content you want to import into OneNote, follow these general steps:

·         If you want to make sure the page exists to place content onto, create an <EnsurePage> to verify or create the folder, section, and page as necessary.

·         Create a <PlaceObjects> element for the page to which you want to add or delete content.

·         Create an <Object> element for the first object you want to alter (add, update, or delete) on the page.

·         To delete the object, add the <Delete/> element to that object.

·         To import the object, add a <Position> element and use its x and y attributes to specify where on the page to place the object.

·         Specify the type of object you’re importing to the page by using the appropriate element, <Image>, <Ink>, or <Outline>, and setting the appropriate optional attributes, if desired.

·         If you’re importing an outline object, specify the sub-objects the outline contains in the order in which you want them to appear in the outline. You can specify any number and order of <Image>, <Ink>, and <Html> elements. However, you are required to specify at least one <Image>, <Ink>, or <Html> element for the outline.

·         Repeat this procedure for all objects you want to alter on the page. Then repeat this procedure for all pages on which you want to alter content.

Some other technical requirement to keep in mind as you create the xml string:

·         OneNote positions objects based on absolute x and y coordinates, where x and y represent measurements in points. Seventy-two points equal one inch.

·         Ink objects must be described in Ink Serialized Format (ISF) format, base-64 encoded, or specified by a path to the source file. If you specify a file path, the source file should be a plain file with the byte stream containing the ISF. If you include the ink as data in the XML, then it should be base64 encoded. For more information on programmatically capturing and manipulating ink, see this Ink Serialization Sample.

·         Image objects can be specified by a path to a source file, or base-64 encoded.

·         Text must be described in html, within a CDATA block, or specified by a path to a source file. In a CDATA block, all characters are treated as a literal part of the element’s character data, rather than as XML markup. XML and HTML use some of the same characters to designate special processing instructions. Using the CDATA block prevents OneNote from misinterpreting HTML content as XML instructions.

·         Although the schema does not currently support importing audio or video files, you can include links to these files within the HTML content you import.

Updating Content

To update objects that are already in a notebook, simply re-import the objects to the same page, using the same GUIDs. Be aware, however, that re-importing an object overwrites that object without notifying the user. Any changes made to the content since it was last imported are lost.

Deleting Content

To delete an object, place the <Delete/> element within the object element. To delete an object, you must be able to identify it by its GUID and path. In practical terms, this generally means an application can only delete objects it places in OneNote to begin with. However, if the application stores the GUID across sessions, it can delete objects it imported into OneNote in previous sessions. You cannot delete folders, sections, or pages, even those you created.

Sample XML String

Below is an example of what a typical xml string for the Import method might resemble. This xml file describes the placement of three new objects onto an existing page, and the deletion of an object already contained on that page.

<?xml version="1.0"?>

<Import xmlns="http://schemas.microsoft.com/office/onenote/01/2004/import">

 

      <EnsurePage path="MSN Instant Messenger\Conversations.one"

                  guid="{8FDD3C41-5BB5-4595-B019-7E7E9BC9D38E}"

                  title="Personal"

                  date="2003-10-16T17:30:00-08:00"

                  insertAfter="{05239BEA-894E-406d-80AD-8678D1BC1EDD}"/>

 

      <PlaceObjects pagePath="MSN Instant Messenger\Conversations.one"

                    pageGuid="{8FDD3C41-5BB5-4595-B019-7E7E9BC9D38E}">

 

            <Object guid="{5FCFD7F9-02C2-42fc-B6AF-7A8450D43C2D}">

                  <Position x="72" y="72"/>

                  <Image backgroundImage="true">

                        <File path="c:\image.png"/>

                  </Image>

            </Object>

 

            <Object guid="{F6FC4149-1092-48ea-806D-0067C8661A18}">

                  <Position x="72" y="72"/>

                  <Ink>

                        <File path="c:\ink.isf"/>

                  </Ink>

            </Object>

 

            <Object guid="{7EA551C4-F778-40ce-9181-21A3DB6D33CA}">

                  <Position x="72" y="432"/>

                  <Outline width="360">

                        <Html>

                              <Data>

                                    <![CDATA[

                                          <html><body><p>Sample text here.</p></body></html>

                                          ]]>

                              </Data>

                        </Html>

                  </Outline>

            </Object>

 

            <Object guid="{1A6648BA-D792-48f1-AC6A-43DF6E258851}">

                  <Delete/>

            </Object>

 

      </PlaceObjects>

 

</Import>

The following example demonstrates a basic implementation of the OneNote import functionality. The code displays a dialog that enables the user to select an xml file, and then passes the contents of that xml file as an argument for the Import method. This example assumes the xml file conforms to the OneNote data import schema. This example also assumes the project contains a reference to the OneNote 1.0 Type Library.

  Dim strFileName As String

  Dim XmlFileStream As StreamReader

  Dim strImportXml As String

  Dim objOneNote As OneNote.CSimpleImporterClass

 

  OpenFileDialog1.Filter = "XML files (*.XML)|*.XML|Text files (*.TXT)|*.TXT"

  OpenFileDialog1.ShowDialog()

  strFileName = OpenFileDialog1.FileName()

 

  objOneNote = New OneNote.CSimpleImporterClass

  XmlFileStream = New StreamReader(strFileName)

  strImportXml = XmlFileStream.ReadToEnd

  objOneNote.Import(strImportXml)

 

  XmlFileStream.Close()

For the sake of simplicity, so as to highlight how the Import method is implemented, this example assumes that an XML file has already been created to use as the string for the Import method. In most cases, however, the application that calls the Import method will first create the XML string itself. For more information on creating XML using the .NET framework, see Well-Formed XML Creation with the XMLTextWriter.

In addition, most applications will need to create and assign GUIDs to the pages and objects they create. Use the NewGuid method to create a new GUID, and the ToString method to get the string representation of the value of GUID, which the XML string requires. For more information, see GUID Structure in the .NET Framework Class Library.

Displaying a Specified Page

By design, the Import method executes with minimal focus, so that when you import data, the user is not distracted by OneNote displaying data they might not want to see, or worse, navigate away from a OneNote page the user is currently using. Also, in the cases where you import multiple objects to multiple pages, OneNote does not have to make assumptions about which page the user wants to see, if any.

To display a specific page, use the NavigateToPage method. If OneNote is not open, this method opens OneNote to the specified page. If OneNote is already open, the method navigates to the specified page in the current instance of OneNote.

To select the page to display, you must specify the path to the page, as well as the GUID for that page. If you specify a page that does not exist, OneNote returns an error.

The NavigateToPage method has the following signature:

NavigateToPage(bstrPath as String, bstrGuid as string)

Conclusion

OneNote’s new import functionality opens up exciting possibilities for interacting with other applications. Any application that can save data (either its own or another application’s) as html text, images, or ISF can now push that content into OneNote and place it wherever is desired. And as long as the application retains the GUIDs used, it can update or delete the content it pushed whenever necessary.

  • Excellent! I've been interested in this since I got the preview. Now I can finally play with it.
  • So... there is no way to know the GUIDs for existing pages? I have been messing with the API a little and I can create new .one files and import data in that way. Are there plans to add a way to look though the existing files and GUIDs for them? Am I missing something? Is this coming and just not implemented yet?
  • BTW, very cool that you guys recognized the need to add some extensibility to OneNote. I think its a great program and use it all day every day.
  • Great question. No, we did not provide functionality for you to enumerate through the existing page GUIDs. This is actually by design. The basic idea here is that if an application created the page, then it should be able to add, update and delete objects on that page. We didn't want to give the application blanket access to everything the user might have in their notebook. As for notebook sections, of course, you can use WinAPI calls to find out what sections (.one files) are in a user's notebook directory.
  • I dont want to add that overhead to my project, and try to store the GUIDs for each page in onenote and replicate it in my logic. esp, if i am going to have more than one person using it. Then I will have to create a database to pass the guids each person creates to the other people. Also if I have to keep track of the GUID then, I wont want them to create anything in onenote, and will need to force them all through my UI, and will have to redo a whole interface.

    it would be a lot easier, and allow the end user a lot more flexibility if i could query the guids programatically.
  • Could you explain the scenario that you're envisioning? What's your program do, and how do you see OneNote fitting into that? There may be a more creative solution here for your scenario -- although I won't make any promises. At the very least, I can try to keep your scenario in mind as we work on future versions of OneNote.

    <a href="http://blogs.msdn.com/Chris_Pratley/">Chris Pratley</a> has written frequently that designing software is all about trade-offs, and our SP1 release was no different, particularly with its short release cycle.

    One of our largest concerns was that in this first implementation, it was appropriate for applications to be able to modify and delete content they had created (although as you point out, that may require a bit of bookkeeping), but users might feel uncomfortable if a misbehaving/buggy application could accidentally delete or overwrite a bunch of their content that had nothing to do with the purpose of that app.

    Bear in mind that in this version we have _no_ support for exporting data. That means even if you had the GUID you couldn’t check the content on the page, confirm if it made sense to delete or update, etc. You'd have the GUID -- but nothing else. Creating a facility for deleting or updating a page a user or other application created that has content your application can’t even read seemed not in the best interests of users.

    In general, you'll probably get the impression that our new APIs are pretty minimalistic -- and they are. After all, the class is called C/Simple/Importer. :) Nonetheless, we think that the Import APIs are still pretty useful, and hope that you agree.
  • Insert at the Current Location (wherever OneNote's cursor is currently positioned) would have been very helpful.

    For example, I want to create an import for SVG files from Grafigo (or anything else) as either Ink or an Image (support for both).

    With this API, I will have to create a scratch page just to get the graphic into OneNote, but then I am not sure if I'll be able to move it around to the section where I need it.

    I don't need programmatic control of deletions, the user can do that themself in OneNote, what I need is some way to get things into OneNote that it doesn't natively support and allow the user to cut/paste/drag/drop it whever they need it in any notebook/section.

    Thanks for the preliminary API, I look forward to the next version. Perhaps allowing InsertObject (in addition to just image) would be helpful, then an SVG Importer would be moot.
  • How does the Outline object handle nesting? In your example it just shows HTML being inserted; should I nest the <p> tags, or nest the <outline> tags, or what?
  • Agreed: Insert at the Current Location would be great to have, and hopefully something we'll be able offer in a future version.

    InsertObject is a bit tricky because it makes life much simpler to keep the content that's on the page to be the same OneNote content that is generally supported through regular user interactions. At some point, we may just add a real "Insert Object" menu item to OneNote with OLE embedding. Or, we may add support for SVG images directly to the image loader, at which point everything is fine.

    However, there will always be more complicated scenarios. One of the ways that I could imagine us supporting richer data types is via generic metadata that could be associated with objects in OneNote. In that manner, you could have the ink/image representation object on the page, yet keep the SVG representation as metadata that could be accessed via whatever mechanism we have for extensible exporting of content.

    What do you think? If we were to do something like this in the future, would this help? (Mind you, this is just random brainstorming -- please don't mistake this for anything other than the musings of just one guy. :)
  • With regards to nesting, you can in fact nest multiple bits of HTML, Image and Ink content elements within an Outline; they're all added directly to the Outline.

    You can specify nested outline elements within your html. By default, each <p> tag corresponds to a top level outline element, <p style="text-indent: 0.5in"> will indent the paragraph by one level per 0.5 inches of indentation. Additionally, <ul> & <ol> (bulleted/numbered lists) will automatically indent <li> paragraphs.

    Hope this helps!
Page 1 of 3 (35 items) 123