Adventure in SPWonderland

Take apart and put back together

NAVIGATION - SEARCH

Fix: Getting the Silverlight Blueprints for SharePoint to work

I'm doing a presentation tonight for SUGUK on Silverlight in sharePoint and wanted to demo some of the Silverlight Blueprints for SharePoint.

Naturally I hit a few issues along the way so I thought I'd pass a few tips on.

A major requirement is to have .Net 3.5 and AJAX running on your SharePoint site. If you configure AJAX by hand as I did check this MSDN article for configuring AJAX but use 3.5.0.0 as the version number.

I configured AJAX by hand but there is also a CodePlex feature that can install AJAX on all your WFE.

It will also help to have Visual Studio 2008 and the Silverlight SDk installed on your dev box.

The first issue is that none of the XAP's as shipped will work on my machine. You'll get an error like this

 

 

checking the XAP files shows the shipped one has this as the first line of the manifest.

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="SL.XAML.Navigation" EntryPointType="SL.XAML.Navigation.App">

but if I recompile the source I get

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="SL.XAML.Navigation" EntryPointType="SL.XAML.Navigation.App" RuntimeVersion="2.0.30226.2">

The missing RuntimeVersion seems the key here, looks like the U2U folks were running a slightly different build of chiron the XAP compiler and certainly the Silverlight 2 runtime on my machine wont run a XAP without it.

So the fix is to recompile the Silverlight Applications and redeploy the XAP to the ClientBin directory in your IIS website directory.

Second and more bizarre is the Navigation Sample. If you try to run it you get an error about being unable to load the Assembly.

The problem here is that the PublicKey for the SL.Controls.Navigation.Dll is wrong in the MasterPage.

 

 

The MasterPage has 4aec304184eb9a69 when the DLL has bb99f30c0098259c.

The Fix is to change the MasterPage Register TagPrefix line to bb99f30c0098259c. You can use SharePoint Designer or uninstall the feature change it and then reinstall, reactivate.

This will happen when you dev with an internal snk file which has your company private keys in it and then decide you've got to change it before you ship. I've done exactly the same thing myself, it really helps to test it on a single machine outside your company first.

And IT LIVES

 

Client Side: Who am I?

Sometimes when working in client-side javascript you'd like to know your Windows username for instance to add to the root Outlook Web Access URL for say a contacts search i.e. http://flexnetowa/exchange/colinb/contacts/?cmd=search 

Now the stock answer whenever this comes up in the SharePoint newsgroups is: it can't be done, use server side code to render it out.

Thats fair enough and easy to do, I've created a WebPart that stores a users details as a JavaScript object so it can be referenced in code. But what if I don't want to install yet another server-side Web Part.

In the interests of providing code you won't get anywhere else here's the tip.

Now its true the SharePoint Web Services provide no method to tell you who you are (side-note: I suspect you may be able to do this by creating a CAML query against the userinfo table but I've not managed to get that working) but you can get your username by using the FrontPage RPC and calling author.dll, this is how Word displays who you are on its TaskPane when you open a Word document in a document library.

When you call the author.dll ISAPI DLL with the 'open service' method name it returns a host of information about the server and the services it provides.

I'm using the XmlHttpRequest object again which despite the name can also be used to retrieve a text document not just an XML one.

heres the returned information

<html><head><title>vermeer RPC packet</title></head>
<body>
<p>method=open service:6.0.2.6356
<p>service=
<ul>
<li>service_name=
<li>meta_info=
<ul>
<li>vti_defaultlanguage
<li>SW|en-us
<li>vti_usernames
<li>VR|
<li>vti_servercharsets
<li>VX|windows-1257 big5 windows-1252 windows-874 utf-8 windows-1251 windows-1256 euc-kr gb2312 windows-1253 windows-1258 koi8-r iso-8859-1 gb18030 iso-2022-jp ks_c_5601-1987 windows-1250 windows-1255 us-ascii euc-jp unicode unicodeFFFE windows-1254 iso-8859-2 iso-8859-15 shift_jis
<li>vti_scnoprompt
<li>IX|1
<li>vti_toolpaneurl
<li>SX|http://sharepoint.flexnet.ds/_layouts/1033/toolpane.aspx
<li>vti_assemblyversion
<li>SX|Microsoft.SharePoint, Version&#61;11.0.0.0, Culture&#61;neutral, PublicKeyToken&#61;71e9bce111e9429c
<li>vti_webtemplate
<li>IR|1
<li>vti_hasonetlayoutfiles
<li>BR|true
<li>vti_navbuttonnextlabel
<li>SR|Next
<li>vti_casesensitiveurls
<li>IX|0
<li>vti_htmlextensions
<li>SX|.html.htm.shtml.shtm.stm.htt.htx.asp.aspx.alx.asa.hta.htc.jsp.cfm.odc.dwt.php.phtml.php2.php3.php4.
<li>vti_approvallevels
<li>VR|Approved Denied Pending&#92; Review
<li>vti_themedefault
<li>SR|none
<li>vti_welcomenames
<li>VX|default.htm default.aspx
<li>vti_servertz
<li>SX|+0100
<li>vti_adminurl
<li>SX|http://sharepoint.flexnet.ds/_layouts/1033/settings.aspx
<li>vti_showhiddenpages
<li>IW|1
<li>vti_categories
<li>VR|Business Competition Expense&#92; Report Goals/Objectives Ideas In&#92; Process Miscellaneous Planning Schedule Travel VIP Waiting
<li>vti_featurelist
<li>VX|vti_RulesScript vti_ServerIndexServer vti_TimedDocEvents vti_ServiceMarkUrlDirExec vti_DocSaveToDB vti_ServiceMarkUrlDirBrowse vti_ACAll vti_ServerODBC vti_ServerASP vti_ServiceMarkUrlDirScript
<li>vti_hasfulltextsearch
<li>IX|1
<li>vti_defaultcharset
<li>SR|windows-1252
<li>vti_navbuttonuplabel
<li>SR|Up
<li>vti_httpdversion
<li>SX|Microsoft-IIS/6.0
<li>vti_serverlanguages
<li>VX|en-us
<li>vti_sourcecontrolproject
<li>SX|&#60;STS-based Locking&#62;
<li>vti_doclibwebviewenabled
<li>IX|1
<li>vti_extenderversion
<li>SR|6.0.2.6361
<li>vti_ignorekeyboard
<li>IR|0
<li>vti_navbuttonprevlabel
<li>SR|Back
<li>vti_longfilenames
<li>IX|1
<li>vti_sourcecontrolsystem
<li>SX|lw
<li>vti_username
<li>SX|FLEXNET&#92;colinb
<li>vti_navbuttonhomelabel
<li>SR|Home
<li>vti_sourcecontrolcookie
<li>SX|fp_internal
<li>vti_sitecollectionurl
<li>SX|/
<li>vti_language
<li>IR|1033
</ul>
</ul>
</body>
</html>

 

Notice my windows username is listed against the vti_username item.

Using the XmlHttpRequest object to call author.dll synchronously (we're going to wait for the call to return)

xmlrequest = "method=open service:6.0.2.6356&service_name=";

if (!xmlhttp) xmlhttp=GetHTTPObject();

xmlhttp.open("POST", "/_vti_bin/_vti_aut/author.dll ",false);
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlhttp.setRequestHeader("X-Vermeer-Content-Type","application/x-www-form-urlencoded");

xmlhttp.send(xmlrequest);

The responseText property on xmlhttp contains the returned document.

The hardest bit is parsing the result to extract the username.

Once that is done I show the username in a DIV element.

So the next time someone asks this question we'll be able to give them some options.

ClientSideUsername.dwp (2.92 KB)

Cross-Browser AJAX for SharePoint Lists Part 2

In part 1 we have got to the point where we have called the SharePoint lists.asmx Web Service and retrieved the list of all Lists on our SharePoint site.
We now need to filter down to only those lists that are based on the links list template, this is template type 103, we can use an Xpath expression to filter the items.

// Filter for the Links lists items
links_lists=ajaxsp_GetSoapResponseItems(xmlhttpLists.responseXML, "//sp:List[@ServerTemplate='" + ListTemplate + "']", moz_NSResolver1 );

We loop through the list items and use the getAttribute of the XML Dom node to retrieve the fields we are interested in and concatenate a string of <LI> items which we then set to the innerHTML property of a DIV element.

Each list item on the left is a hyperlink that calls the javascript function GetLinkItems when clicked.
This function is passed three parameters - the list Guid, list Title and the Default View URL which normally is the full list of links.

function GetLinkItems(ListGuid, ListName, ListDefaultView)


To get the list items we need to call the GetListItems method and pass it the listName parameter.

// Create SOAP Request
xmlrequest = SoapPrefix + '<GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">'
xmlrequest = xmlrequest + '<listName>' + ListGuid + '</listName></GetListItems>' + SoapPostfix;

To send the SOAP request we do the same as before only this time we set the GetListItems SOAP method

xmlhttpItems.open("POST", "_vti_bin/Lists.asmx?op=GetListItems ",true); xmlhttpItems.setRequestHeader("Content-Type","text/xml; charset=utf-8"); xmlhttpItems.setRequestHeader("SOAPAction","http://schemas.microsoft.com/sharepoint/soap/GetListItems ");
// Set event handler
xmlhttpItems.onreadystatechange=ajaxsp_GetLinkItemsEvent;
// Post request
xmlhttpItems.send(xmlrequest);

Our GetLinkItemsEvent parses the XML and formats the data into a TABLE element with the ms-summarycustombody style to match the theme of the SharePoint site.
Each hyperlink has the target=”_blank” attribute which causes the links to open in a new window, my preferred method of opening links. This can easily be changed.


Creating a new Item Form

Now we have displayed our list of links we need to look at adding a new item.
In the Web Part after the script blocks I have some HTML that contains a DIV element. The DIV element has a style that sets its position to be absolute and hidden.
Inside the DIV I’ve create a HTML table that sets the layout of the AddNew form.
To render the URL editing and Notes fields I use the built-in functions provided in the SharePoint javascript file ows.js to handle input fields on SharePoint forms.
The complete list of fields type that can be used are:

DateField
URLField
NumberField
BooleanField
NoteField
RichTextField
TextField
FileNameField
GridChoiceField
ChoiceField

I only need to use the URLField and NoteField type.


These functions are called in javascript like this
var fld = new URLField(frm,"URL","URL", "","");
fld.fRequired = true;
fld.IMEMode="";fld.BuildUI();

The URLField function takes parameters of a OWSForm, Internal Field Name, Display Name, Default URL Value , Default Description.
BuildUI takes care of creating the input HTML which is great as it automatically creates two input fields, one for the URL and one for the description.

I create a NoteField object like this.

fld = new NoteField(frm,"Comments","Notes","");
fld.stNumLines = "6";
fld.IMEMode="";
fld.BuildUI();

The NoteField functions parameters are a OWSForm, Internal Field Name, Display Name, Default Note Field Value


Heres the function prototype for creating a OWSForm object:

function OWSForm(stName, fUseDHTMLOverride, stPagePath)

Creating the OWSForm is tricky in that it’s easy to create the OWSForm object in itself but it expects the name of the onpage form used in the WebPart page postbacks, that’s fine but it overwrites the onsubmit function which causes problems for any other component like the Web Part settings toolbar that need to post to the server. The way around this is to pass it a dummy name and then after the call set the Form name to the genuine article.
The second parameter is fUseDHTMLOverride which is used to force the use of DHTML when rendering the controls.
stPagePath is used to locate any extra files needed such as the datepicker’s template htm page.

Heres how its called in code

// Pass a dummy form name so it does not overwrite the Submit event
var _WPQ_frm= new OWSForm("DummyName" , true, "_layouts/");
// Now assign the proper form name it as it’s needed for the fields to locate their values
_WPQ_frm.stName=MSOWebPartPageFormName;

We use the global variable MSOWebPartPageFormName here which is defined in ows.js and available on all WebPartPages and gives the name of the FORM element used for postback. Note we don’t postback ourselves but the OWS Field elements think that they might.

I’ve laid out the new item form with the Javascript to create the edit fields embedded in a HTML table. This table is wrapped in a DIV which is initially hidden. The code to show and center the DIV element is Javascript 101 so I won’t go into details but check the function ajaxsp_DisplayNewForm if you’re interested.

I want to set focus to the Http edit field so we need to a reference to the Edit fields.
We can use getElementById for this but we need to know the name of the field on the form.
The key to this is to understand how the OWS form elements name themselves.

Fields are named by the internal function FrmStFieldNameFactory which does this:
return "OWS:" + name + ":" + stPart;
This concatenates OWS with the name of the field and the subfield name.

The URL field type is composed of two sub fields named URL and Desc. In this case we’re referencing the URL field and the URL subpart of that field.

So to reference the URL sub part of the URL field we can use this code.

var fldURL=document.getElementById("OWS:URL:URL");
if (fldURL) fldURL.focus();

 

Adding a new record via SOAP services

Now that we can get the URL, Description and Notes field values we use the UpdateListItems method of the Lists.asmx web service to add the new record.
This method takes a CAML string to do adds, updates and deletes.
This is an example CAML batch string we send:

<Batch>
<Method ID='1' Cmd='New'>
<Field Name='URL'>http/www.google.com, Description here - note comma and space</Field>
<Field Name='Comments'>My Comment String</Field>
<Method>
</Batch>

The ajaxsp_AddListItem routine assembles this string, places it inside the UpdateListItems SOAP string and sends it to the web service. 
The ajaxsp_AddListItemEvent handles the returned SOAP string which may include a faultstring node if the SOAP call fails or an ErrorText node if the new record fails to add in SharePoint. Once the insert succeeds we hide the new item form and refresh the list.

Thats almost it, there is some extra code where I store the last displayed list in a cookie so if the page refreshes I can display the list items again. This cookie is designed to only last for the browser session.


 

Summary

This has been a deep dive into calling the SharePoint Web Services from client side javascript but the actual methods involved are pretty basic and simple to use, most of the complications and extra code come from handling non IE browsers.

Some of the other ways that Web Services could be used include adding field by field server-side validation, filling comboboxes from SQL Server tables, getting unread email counts information from Exchange via WebDav.

Feel free to download the DWP file and browse the code for yourselves.

LinksLists.dwp (16.2 KB)

Cross-Browser AJAX for SharePoint Lists Part 1

On my personal SharePoint site I use the SharePoint Links type lists a huge amount, I have at least 20 of these and I like to flick between them a lot, having the links to hand is a great productivity booster.
I find the standard navigation just too slow and although the double-click minimize/restore Web Part helps what I really wanted was a windows application usability for these lists.


This is a perfect job for client-side JavaScript making SOAP calls to the SharePoint WebServices using DHTML to display the items. This kind of code now has the nifty name of AJAX although this is really AJAX-lite as the size of our framework is tiny and doesn’t need to handle complex object serialization/deserialization or data binding.

The goal is to have a WebPart that lists the Links based lists (must be an easier way to say that) and with a click display the items on the list, I also wanted to have an easy way to add items into the list. All code would be client-side javascript and also needed to work in Mozilla based browsers such as FireFox as I also use that a lot. Once the initial page has been rendered as normal by SharePoint there are no other postbacks or page refreshes needed so response times are very fast.


The Javascript will be initially be hosted in a Content Editor Web Part but I plan to create a server side WebPart also. Here’s a screen shot.

List of Lists

 

Add a new Item


 
SharePoint already does some AJAX already, albeit in a limited fashion, to handle getting and setting Web Part properties while editing the Properties of Web Parts. It posts to the WebPartPages.asmx SOAP service using the SaveWebPart and GetWebPart SOAP methods. Note the built-in SharePoint SOAP calls are only made if the browser is IE 5 and up. This and the fact that the library calls are hard-coded to use the WebPartPages web service only meant I had to create my own routines.

Soap requests by hand

Ok down to the nitty-gritty.
I’m going to assume you already have some understanding of what SOAP is but basically it is the method of sending an XML formatted request to a URL via HTTP and getting back a XML formatted response.
The first thing our Web Part needs is the list of Links type lists on the SharePoint site we are on.
To do this we will call the GetListCollection method of the Lists.ASMX web Service.
If you add /_vti_bin/lists.asmx page to your site URL you will see the methods this service exposes. Click the GetListCollection method to see the format of the SOAP request it expects.

The function GetLinksList populates the list of links and is the entry point into our code. We hook into the windows load event like this:

if (window.addEventListener)
window.addEventListener('load', _WPQ_AjaxObject.GetLinksList, false);
else
window.attachEvent("onload",_WPQ_AjaxObject.GetLinksList);

Note the use of the _WPQ_ token, this is replaced by our Web Part ID by the CEWP at runtime so avoiding duplicate global variables when there are two instances of the same Web Part on a page.

So we send a POST request to the URL /_vti_bin/Lists.asmx?op=GetListCollection and make sure we have a SOAPAction header set to the correct operation which is http://schemas.microsoft.com/sharepoint/soap/GetListCollection.
This will give use a list of all lists which we can filter for the Links’s type.

The body of the request will look like this:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
</soap:Body>
</soap:Envelope>

This is a very simple request string and notice the majority of the text is the boilerplate SOAP XML envelope that will never change, so in the code I’ve created vars that contain this text called SoapPrefix and SoapPostFix

To submit the request we create a XMLHttpRequest object and use its send method asynchronously, the function that calls the List Web Service looks like this

function ajaxsp_GetLinksList()
{
var xmlrequest;

xmlrequest = aSoapPrefix+ '<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>'
xmlrequest += SoapPostfix;

if (!xmlhttpLists) xmlhttpLists= GetHTTPObject();

xmlhttpLists.open("POST, "_vti_bin/Lists.asmx?op=GetListCollection",true);
xmlhttpLists.setRequestHeader("
Content-Type","text/xml; charset=utf-8");
xmlhttpLists.setRequestHeader("
SOAPAction","http://schemas.microsoft.com/sharepoint/soap/GetListCollection");
xmlhttpLists.setRequestHeader("Content-Length", xmlrequest.length);


// set the callback event
xmlhttpLists.onreadystatechange=ajaxsp_GetLinksListEvent;
// Send the request
xmlhttpLists.send(xmlrequest);

return true;

}

Two important functions are GetHTTPObject which returns the HttpRequest object for both IE and Mozilla based browsers and the ajaxsp_GetLinksListEvent which does the heavy lifting of processing the returned XML

GetHTTPObject needs to create different objects for IE and Mozilla because Mozilla has a built-in native Javascript object called XMLHttpRequest whereas IE uses the ActiveX XMLHTTP  object contained in MSXML libraries, there a quite a few versions of this library and the ProgID changes with each one but I just use either Msxml2.XMLHTTP  of Microsoft.XMLHTTP which should cover most modern machines with IE5.0 and up, interestingly IE 7 has now gained the native XMLHttpRequest object.


Heres a snippet of the returned XML.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><GetListCollectionResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<GetListCollectionResult>
<Lists>
<List DocTemplateUrl="" DefaultViewUrl="/Lists/Company Links/AllItems.aspx" ID="{60E01147-6A7A-47F0-8CA1-4D88426280DE}" Title="1 Company Links" Description="" ImageUrl="/_layouts/images/itlink.gif" Name="{60E01147-6A7A-47F0-8CA1-4D88426280DE}" BaseType="0" ServerTemplate="103" Created="20050225 11:43:06" Modified="20060222 09:58:24" LastDeleted="20060220 17:42:54" Version="1" Direction="none" ThumbnailSize="" WebImageWidth="" WebImageHeight="" Flags="4105" ItemCount="16" AnonymousPermMask="" RootFolder="" ReadSecurity="1" WriteSecurity="1" Author="3" EventSinkAssembly="" EventSinkClass="" EventSinkData="" EmailInsertsFolder="" AllowDeletion="True" AllowMultiResponses="False" EnableAttachments="False" EnableModeration="False" EnableVersioning="False" Hidden="False" MultipleDataList="False" Ordered="True" ShowUser="True" />
<List DocTemplateUrl="" DefaultViewUrl="/Lists/Links/AllItems.aspx" ID="{233585BA-5972-40BB-85C8-67F793F22F67}" Title="2 Links" Description="Use the Links list for links to Web pages that your team members will find interesting or useful." ImageUrl="/_layouts/images/itlink.gif" Name="{233585BA-5972-40BB-85C8-67F793F22F67}" BaseType="0" ServerTemplate="103" Created="20041008 14:10:07" Modified="20060224 10:43:07" LastDeleted="20050302 08:40:12" Version="1" Direction="none" ThumbnailSize="" WebImageWidth="" WebImageHeight="" Flags="4105" ItemCount="26" AnonymousPermMask="" RootFolder="" ReadSecurity="1" WriteSecurity="1" Author="3" EventSinkAssembly="" EventSinkClass="" EventSinkData="" EmailInsertsFolder="" AllowDeletion="True" AllowMultiResponses="False" EnableAttachments="False" EnableModeration="False" EnableVersioning="False" Hidden="False" MultipleDataList="False" Ordered="True" ShowUser="True" />


As you can see a large amount of information is returned for each list but I’m most interested in four attributes of each list:

Name –List Name for display
ServerTemplate – for filtering
DefaultViewURL – to allow jumping to the standard SharePoint links page
Hidden - for hiding hidden lists.

The ServerTemplate is used to filter out only those lists that are Links based list which have a list template of 103. I use the constant LISTTEMPLATE_LINKS which is defined in ows.js.

The routines for parsing this XML into DOM nodes brings out the second major difference between IE and Mozilla : IE uses the MSXML ActiveX objects whereas Mozilla has the XML parsing javascript objects built-in.
I’ve encapsulated the conversion of the response XML into a set of DOM nodes into the GetSoapResponseItems routine

// Cross Browser helper to filter the XML results
// Returns array of Node objects
function ajaxsp_GetSoapResponseItems(SoapResponseXML, XPathFilter, NSResolver)
{
var m_Items=[];

// Mozilla
if (window.addEventListener)
{
    var aItems = xmlhttpLists.responseXML.evaluate(XPathFilter, SoapResponseXML, NSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
    for( var i = 0; i < aItems.snapshotLength; i++){m_Items[i] = aItems.snapshotItem(i);}
}
else
{ // IE
    var xmlDom=new ActiveXObject("MSXML2.DOMDocument.3.0");
    xmlDom.async=false;
    xmlDom.loadXML(SoapResponseXML.xml);
    m_Items=xmlDom.selectNodes(XPathFilter.replace("sp:",""));
}

return m_Items;

}

In IE you create a MSXML.DomDocument ActiveX object and use its LoadXML method to load the XML and use selectNodes with an XPath expression to get back the list of items
Mozilla has support for a lot of the DOM Level 3 XPath  (http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html)  which allows XPath expression to be run against the XML data. The responseXML property is actually an object that has parsed the XML but unfortunately it doesn’t have support for selectNodes so you have to use the evaluate function to get a XpathResult and with that you can add the individual Dom nodes to an array.
One wrinkle with Mozilla is that’s its very picky about NameSpaces so you must specifiy a prefix in your XPath filter for default namespaces and also you need a routine that converts the prefix to the full Namespace, there are a couple of ways of doing this but a simple function returning a string is the easiest.

function moz_NSResolver1(NSPrefix)
{
switch(NSPrefix)
{
case "soap" : return "http://schemas.xmlsoap.org/soap/envelope/"; break;
default : return "http://schemas.microsoft.com/sharepoint/soap/";
}
}

As this function needs to vary depending on the XML I pass this in as function pointer in parameter NSResolver.
IE does some guessing for you so we can strip the prefix from the XPath filter.

Now once we have the Links Lists I create a set of ListItems (LI) in an Unordered List (UL) and display them by setting the innerHTML of a DIV element.

Whew, thats enough for one entry, In part 2 I’ll delve into displaying the actual links and creating a form for adding a new item using the client-side OWS Field objects and post the DWP file that contains all the code and which can be imported into your Web Part page.