Not sure if this is needed, but there
are more that one sharepoint sites
hosted at "website.com" (The one I'm
trying to access is
"website.com/sites/mysite" ) Does that
change things?
Absolutely it does! The web service URLs you have discovered are actually virtual, meaning that the URL pattern _vti_bin/Lists.asmx
is available under EVERY SharePoint site. Whatever site your list lives in must be the starting point for your web service URL.
Thus, try: http://website.com/sites/mysite/_vti_bin/Lists.asmx
You might find MSDN's SharePoint Web Service Guidelines article helpful, too.
UPDATE #1:
CAML won't help you "break apart" your results. It's strictly a query/filter technology, and it looks like you're using it appropriately. It's up to you to tell us whether or not the result set you're getting back is what you expect. If you need help constructing more complicated CAML queries, I suggest downloading a copy of U2U's CAML Query Builder (but that's another topic).
So, on to the results. It's a little confusing to look at it, but there is some method to the madness. The columns you've set up on your list are all here (provided you're not constraining them in the CAML query, which is possible). You'll notice they use SharePoint's internal name for the column, prefixed with ows_
. So, if you know the internal names, you can construct the XML attribute names and use XML classes, LINQ, or XSLT to dive into the results and get what you need. See my answer to another SO question for tips on divining SP's internal column names.
If it helps to know what I do in this situation, I simply build a POCO model class to represent one of my list items, and write a parser method to take SharePoint's XML results and return a collection of the model objects. I'm fond of LINQ to XML for this task.
Were you using SharePoint 2010, you could use the new Client Object Model classes and get better managed wrappers around working with SharePoint Sites, Lists, ListItems and such.
UPDATE #2:
Just for some color, I'm posting a sample of the code I use to parse SharePoint XML. Registrant
in this example is a POCO model class I wrote to represent a SharePoint list item for a custom list. It's trivial and I won't bother posting it.
/// <summary>
/// Parses registrant XML returned from SharePoint's Lists web service into a collection
/// of <see cref="Registrant"/> objects (root element = "listitems").
/// </summary>
/// <param name="xml">SharePoint XML</param>
/// <returns>Collection of Registrant objects, or null if no registrant data could be parsed.</returns>
public static List<Registrant> ParseSharePointXmlCollection( XElement xml ) {
// Test: Not expected XML element or has no child elements
if ( !xml.Name.LocalName.Equals( "listitems" ) || !xml.HasElements ) {
return null;
}
List<Registrant> regList = null;
XElement data = xml.Element( XName.Get( "data", "urn:schemas-microsoft-com:rowset" ) );
if ( (data != null) && (data.HasElements) ) {
regList = new List<Registrant>();
IEnumerable<XElement> regXmlNodes = data.Elements( XName.Get( "row", "#RowsetSchema" ) );
foreach (XElement regXml in regXmlNodes) {
Registrant reg = ParseSharePointXml( regXml );
if ( reg != null ) {
regList.Add( reg );
}
}
}
return regList;
}
/// <summary>
/// Parses registrant XML returned from SharePoint's Lists web service into a single
/// <see cref="Registrant"/> object (root element = "row").
/// </summary>
/// <param name="xml">SharePoint XML</param>
/// <returns>A Registrant object, or null if no registrant data could be parsed.</returns>
public static Registrant ParseSharePointXml( XElement xml ) {
// Test: Not expected XML element or has no attributes
if ( !xml.Name.LocalName.Equals( "row" ) || !xml.HasAttributes ) {
return null;
}
Registrant reg = null;
// Parse ID (if this fails, fail the whole operation)
if ( xml.Attribute( "ows_ID" ) != null ) {
reg = new Registrant();
reg.ID = xml.Attribute( "ows_ID" ).Value;
}
else {
return null;
}
// Parse First Name
if ( xml.Attribute( "ows_Q_Registrant_x0020_First_x0020_N" ) != null ) {
reg.FirstName = xml.Attribute( "ows_Q_Registrant_x0020_First_x0020_N" ).Value;
}
// Parse Last Name
if ( xml.Attribute( "ows_Q_Registrant_x0020_Last_x0020_Na" ) != null ) {
reg.LastName = xml.Attribute( "ows_Q_Registrant_x0020_Last_x0020_Na" ).Value;
}
// Parse Email
if ( xml.Attribute( "ows_Q_Registrant_x0020_Email" ) != null ) {
reg.Email = xml.Attribute( "ows_Q_Registrant_x0020_Email" ).Value;
}
// Parse Assistant Name
if ( xml.Attribute( "ows_Q_Asst_x0020_First_x0020_Name" ) != null ) {
reg.AssistantFirstName = xml.Attribute( "ows_Q_Asst_x0020_First_x0020_Name" ).Value;
}
if ( xml.Attribute( "ows_Q_Asst_x0020_Name" ) != null ) {
reg.AssistantLastName = xml.Attribute( "ows_Q_Asst_x0020_Name" ).Value;
}
// Parse Assistant Email
if ( xml.Attribute( "ows_Q_Asst_x0020_Email" ) != null ) {
reg.AssistantEmail = xml.Attribute( "ows_Q_Asst_x0020_Email" ).Value;
}
return reg;
}
UPDATE #3:
Sample code to convert an XmlNode
object to an XElement
:
public static XElement GetXElement( this XmlNode node ) {
XDocument xdoc = new XDocument();
using ( XmlWriter xmlWriter = xdoc.CreateWriter() ) {
node.WriteTo( xmlWriter );
}
return xdoc.Root;
}
Best Answer
Use a custom xml sitemap provider. Both applications can be configured to access the shared xml datasource and a timer job or similar can be coded to update the xml as required.
MSDN Customizing Navigation Controls and Providers
Code project SharePoint Custom Site Navigation