Introduction

This is the documentation for the MSDN/TechNet Publishing System (MTPS) Content Service. The MTPS Content Service is an XML web service that provides access to the content stored in MTPS. This includes, for example, the content available at http://msdn2.microsoft.com/library. Using the MTPS Content Service, developers can integrate documentation, technical articles, whitepapers, images and the other content available from the MTPS system into their own applications.

The MTPS Content Service requires no registration nor authentication.

The MTPS Content Service is a read-only service; no facilities are provided for updating or amending content.

Use of the MTPS Content Services is governed by the Microsoft Terms of Use.

WSDL

The formal service description (WSDL) can be found here.

Definitions

Content Item
A unit of content from the MTPS database. It consists of one or more documents, and is uniquely identified by a content key.
Content Key
A unique identifier for a content item. It consists of a content identifier, a version, and a locale.
Content Identifier
A general term used to describe one of a content's short ID, GUID, alias, asset ID, or a content URL.
Content Short ID
A short (currently 8) sequence of alphanumeric characters that - along with a version and a locale - uniquely identifies a content item. Note that for historical reasons, a short ID is expressed in XML with the element name "contentId". Every content item has exactly one short identifier. Example: ms224917.
Content GUID
A GUID that - along with a version and a locale - uniquely identifies a content item. Every content item has exactly one GUID. GUIDs in MTPS are expressed using .NET's "D" format. Example: 10447DD7-07A1-4856-B00E-6F31465AC63F.
Content Alias
A freeform string that - along with a version and a locale - uniquely identifies a content item. Aliases serve as "friendly names" for content items. A content item may or may not have an alias. Example: System.Xml.XmlWriter.
Content URL
A URL that points to a content item. In some situations, this can be used in place of one of the other content identifiers. Note that it can contain version and locale information, which may override or be overridden by the locale and version specified elsewhere in the content key. Example: http://msdn2.microsoft.com/eak978d4(en-us,VS.80).aspx.
Version
Identifies a particular variant of a content item. For example, distinct content items describing the .NET 1.1 and .NET 2.0 flavors of the System.Xml.XmlWriter class may exist in the MTPS database. A version string identifies unambiguously which variant is desired. Versions are formatted as a dotted pair combining a product family and a product version. Version is not used to retain edit history of a content item - merely to allow documentation for different product versions to exist in the system simultaneously. Example: VS.80.
Locale
Content items can exist in the MTPS in many different languages and translations. For example, the documentation for the System.Xml.XmlWriter class is available in both English and in German. Locales are of the form defined by the System.Globalization.CultureInfo class (but case insensitive). Example: de-DE.
Document
A component of a content item. Can be in an XML or binary format. A document has a type that is either primary, common, feature, or image. A document has a format that is specific to the type. Some document types also have a name.
Primary Documents
Primary documents contain the main content of the content item. Typical formats are:
Format Description
Mtps.Xhtml XHTML-compliant, presentation-free page.
Mtps.Toc Fragment of the table-of-contents site navigation. One single fragment contains one root element and a set of children one level deep. Using a hierarchical TreeView representation for reference, there exists a fragment for each level on each branch of the TOC.
Common Documents
Common documents contain types of information that is applicable to all content within the system. Typical formats are:
Format Description
Mtps.Links Provides a mapping between source-specific ‘asset IDs’ and MTPS-specific content identifiers.
Mtps.Search Metadata tags typically used for search indexing.
Feature Documents
Feature documents may contain auxiliary information that complements a content item. Examples might include user rating information or items related to this page. Feature documents are opaque to the system. No feature document formats are defined at this time.
Image Documents
Images referenced by a primary document are stored separately within the content item. Supported image formats include gif, jpg and png.
Requested Document Descriptor
When requesting a content item from the MTPS Content Service, a client must specify which document types and formats they are requesting. Summary information will always be returned for all document types and formats, but as individual documents may be quite large, only the contents of those documents matching a requested document descriptor will be returned.

Web Service Operations

The MTPS Content Service currently supports two operations: GetContent and GetNavigationPaths.

GetContent Operation

Description

The GetContent operation allows a caller to request a particular content item from the content store, or to find a list of potential alternates if an unambiguous content key is not known.

Request

The formal definition of the request can be found in the WSDL (available here ). Here is an sample of what a request might look like:

<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>
    <getContentRequest xmlns="urn:msdn-com:public-content-syndication">
      <contentIdentifier>ms224917</contentIdentifier>
      <locale xmlns="urn:mtpg-com:mtps/2004/1/key">en-us</locale>
      <version xmlns="urn:mtpg-com:mtps/2004/1/key">VS.80</version>
      <requestedDocuments>
        <requestedDocument type="Common" selector="Mtps.Search" />
        <requestedDocument type="Primary" selector="Mtps.Xhtml" />
      </requestedDocuments>
    </getContentRequest>
  </soap:Body>
</soap:Envelope>
    

Here, a SOAP 1.1 request is shown, but a SOAP 1.2 binding is also supported.

The request consists of a three-part content key - a content identifier (which can be either a content short ID, a content GUID, a content alias, or a content URL, or an asset ID) , a locale, and a version - and zero or more requested document descriptors .

Version is optional. If version is not specified, the latest version is assumed. Locale, however, is required. Failure to specify locale will result in a partial match.

Note that if the request contains a content URL and the URL contains version and/or locale information, and the request also contains version and/or locale information, then the version/locale in the request itself override the version/locale in the URL.

Response

Several response scenarios are possible:

  1. Exact match. The specified content key uniquely identifies a content item.
  2. Partial match. The specified content key ambiguously identifies a content item.
  3. No match. The specified content key does not identify any content items.
  4. Other fault. For example, a malformed request or an internal database error.

Exact Match

When the provided content identifier - short ID, GUID, or alias - is found in the database, and when a content item exactly matching the requested version and locale exists, an exact match has occurred. In this case, several things are returned with the response:

  1. Key information. This includes the locale, version , short ID, GUID, and alias (if one exists) of the matched content item.
  2. Available version and locale information. If other versions and locales exist that have the same content key as the requested item, a list of these available versions and locales are returned.
  3. Documents. Summary information for all available documents is always returned. Additionally, if any documents match the requested document descriptors in the request, their full contents are also returned.

Given the sample request shown above, a response for an exact match might look as follows:

<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>
    <getContentResponse
        xmlns="urn:msdn-com:public-content-syndication"
        xmlns:k="urn:mtpg-com:mtps/2004/1/key">
      <k:contentId>ms224917</k:contentId>
      <k:contentGuid>10447dd7-07a1-4856-b00e-6f31465ac63f</k:contentGuid>
      <k:contentAlias />
      <k:locale>en-us</k:locale>
      <k:version>VS.80</k:version>
      <availableVersionsAndLocales>
        <availableVersionAndLocale>
          <k:locale>en-us</k:locale>
          <k:version>VS.80</k:version>
        </availableVersionAndLocale>
        <availableVersionAndLocale>
          <k:locale>en-us</k:locale>
          <k:version>VS.90</k:version>
        </availableVersionAndLocale>
      </availableVersionsAndLocales>
      <primaryDocuments>
        <p:primary primaryCat:primaryFormat="Mtps.Xhtml"
            xmlns:primaryCat="urn:mtpg-com:mtps/2004/1/primary/category"
            xmlns:p="urn:mtpg-com:mtps/2004/1/primary">
          <xhtml:xhtml>
            <!-- Content omitted for clarity -->
          </xhtml:xhtml>
        </p:primary>
      </primaryDocuments>
      <imageDocuments />
      <commonDocuments>
        <c:common commonCat:commonFormat="MTPS.Links"
            xmlns:commonCat="urn:mtpg-com:mtps/2004/1/common/category"
            xmlns:c="urn:mtpg-com:mtps/2004/1/common" />
        <c:common commonCat:commonFormat="MTPS.Search"
            xmlns:commonCat="urn:mtpg-com:mtps/2004/1/common/category"
            xmlns:c="urn:mtpg-com:mtps/2004/1/common">
          <search>
            <!-- Content omitted for clarity -->
          </search>
        </c:common>
      </commonDocuments>
      <featureDocuments />
    </getContentResponse>
  </soap:Body>
</soap:Envelope>
    

Again, this sample shows the SOAP 1.1 version, but SOAP 1.2 responses would be generated in response to a SOAP 1.2 request.

There are several things to note about this response:

Partial Match

If the content key provided in the request identifies an existing content item, but the specified version and locale are not present (or version is not specified and the specified locale is not present), there is a partial match. In this case, only two things are returned:

  1. Identity information. This includes the short ID, GUID, and alias (if one exists) of the matched content item.
  2. Available version and locale information. A list of any other versions and locales that exist that have the same content key as the requested item is returned.

If the sample request above were only a partial match, the response might look as follows:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getContentResponse xmlns="urn:msdn-com:public-content-syndication"
        xmlns:k="urn:mtpg-com:mtps/2004/1/key">
      <k:contentId>ms224917</k:contentId>
      <k:contentGuid>10447dd7-07a1-4856-b00e-6f31465ac63f</k:contentGuid>
      <k:contentAlias />
      <k:locale />
      <k:version />
      <availableVersionsAndLocales>
        <availableVersionAndLocale>
          <k:locale>en-us</k:locale>
          <k:version>VS.90</k:version>
        </availableVersionAndLocale>
        <availableVersionAndLocale>
          <k:locale>de-de</k:locale>
          <k:version>test.20</k:version>
        </availableVersionAndLocale>
      </availableVersionsAndLocales>
      <primaryDocuments />
      <imageDocuments />
      <commonDocuments />
      <featureDocuments />
    </getContentResponse>
  </soap:Body>
</soap:Envelope>
    

Note that no documents are returned - basically just the various content identifiers and the available versions and locales. Generally the correct action in response to a partial match will be to select one of the available versions and locales, and then to retry the request. That should result in an exact match.

No Match

If the content key in the request does not match any content item in the database, a fault is returned.

Faults

When a problem occurs, a SOAP fault of the appropriate version (1.1 or 1.2) is returned. The faultstring (SOAP 1.1) or Reason/Text (SOAP 1.2) element of the fault will contain a human-readable, English message describing the error which has occurred. The detail element of the fault will contain MTPS-specific information about the error, in the form of a mtps:mtpsFaultDetail element. The formal schema for that element can be found in the WSDL document. Here is a brief description of each of the elements:

Element Description
eventId A code describing the error. See table below.
source The source of the error. Always "GetContent".
helpLink The URL of a webpage containing helpful information about the error and how to resolve it.

The error codes in the eventId element will be one of the following:

Code Description
mtpsContentIdentifierNotFound The specified content identifier did not correspond to any content items in MTPS.
mtpsContentIdentifierAbsent There was no content identifier in the request.
mtpsContentIdentifierInvalidFormat The content identifier in the request was in an incorrect format.
mtpsRequestAbsent The soap:Body element did not contain a request of the appropriate type.
mtpsVersionInvalidFormat The version in the request was in an incorrect format.
mtpsLocaleNull The locale was not specified in the request.
mtpsLocaleInvalidFormat The locale in the request was in an incorrect format.
mtpsGeneralServerError Some other error occurred.

Sample C# Client Code

The below samples demonstrate the use of the MTPS Content Service. They assume that a proxy has been generated via "Add Web Reference" in Visual Studio 2005, and that using statements have brought in the namespaces System, System.Web.Services.Protocols, System.Xml, System.Xml.Serialization, and whatever namespace you assigned to your proxy when running "Add Web Reference".

Scenario 1 - Retrieve summary information for a content item by short ID using SOAP 1.1, exact match

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the short ID, version, and locale
      request.contentIdentifier = "abhtw0f1"; // System.Xml.XmlReader.Read
      request.locale = "en-us";
      request.version = "VS.80";

      // Create the proxy and set the SOAP version
      ContentService proxy = new ContentService();
      proxy.SoapVersion = SoapProtocolVersion.Soap11;

      // Call the web service
      getContentResponse response = proxy.GetContent(request);

      Console.WriteLine(response.contentId);              // abhtw0f1
      Console.WriteLine(response.locale);                 // en-us
      Console.WriteLine(response.version);                // VS.80

      // Two common documents are returned
      Console.WriteLine(response.commonDocuments.Length); // 2

      // The first common document contains search info
      Console.WriteLine(response.commonDocuments[0].commonFormat); // MTPS.Search

      // No contents were requested, so we only get summary info like format
      Console.WriteLine(response.commonDocuments[0].Any.Length); // 0

      // One other version/locale is available (German)
      // The first version/locale is the one we passed in
      Console.WriteLine(response.availableVersionsAndLocales.Length); // 2
      Console.WriteLine(response.availableVersionsAndLocales[0].locale); // en-us
      Console.WriteLine(response.availableVersionsAndLocales[0].version); // VS.80
      Console.WriteLine(response.availableVersionsAndLocales[1].locale); // de-de
      Console.WriteLine(response.availableVersionsAndLocales[1].version); // VS.80
    

Scenario 2 - Retrieve the XHTML for an item by GUID, SOAP 1.2, exact match

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the GUID, version, and locale
      request.contentIdentifier = "4de07e43-5601-446e-9105-1144a5fdb08d";
      request.locale = "en-us";
      request.version = "VS.80";

      // Specify that we want the XHTML primary document contents to come back
      requestedDocument[] documents = new requestedDocument[1];
      documents[0] = new requestedDocument();
      documents[0].type = documentTypes.primary;
      documents[0].selector = "Mtps.Xhtml";
      request.requestedDocuments = documents;

      // Create the proxy. No need to set version since SOAP 1.2 is the default
      ContentService proxy = new ContentService();

      // Call the web service
      getContentResponse response = proxy.GetContent(request);

      Console.WriteLine(response.contentId);              // abhtw0f1
      Console.WriteLine(response.contentGuid);            // 4de07e43-5601-446e-9105-1144a5fdb08d
      Console.WriteLine(response.locale);                 // en-us
      Console.WriteLine(response.version);                // VS.80

      // Two primary documents are returned
      Console.WriteLine(response.primaryDocuments.Length); // 2

      // The first primary document contains the XHTML
      Console.WriteLine(response.primaryDocuments[0].primaryFormat); // Mtps.Xhtml

      // Contents were requested, so we get the Xhtml
      Console.WriteLine(response.primaryDocuments[0].Any.Name); // div

Scenario 3 - Retrieve the Mtps.Toc and Mtps.Xhtml documents for an item by Short ID, SOAP 1.2, exact match

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the GUID, version, and locale
      request.contentIdentifier = "ms288592";
      request.locale = "en-us";
      request.version = "VS.80";

      // Specify that we want the Mtps.Toc and Mtps.Xhtml primary document contents to come back
      requestedDocument[] documents = new requestedDocument[2];
      documents[0] = new requestedDocument();
      documents[0].type = documentTypes.primary;
      documents[0].selector = "Mtps.Xhtml";
      documents[1] = new requestedDocument();
      documents[1].type = documentTypes.primary;
      documents[1].selector = "Mtps.Toc";
      request.requestedDocuments = documents;

      // Create the proxy. No need to set version since SOAP 1.2 is the default
      ContentService proxy = new ContentService();

      // Call the web service
      getContentResponse response = proxy.GetContent(request);

      Console.WriteLine(response.contentId);              // abhtw0f1
      Console.WriteLine(response.contentGuid);            // 4de07e43-5601-446e-9105-1144a5fdb08d
      Console.WriteLine(response.locale);                 // en-us
      Console.WriteLine(response.version);                // VS.80

      // Two primary documents are returned
      Console.WriteLine(response.primaryDocuments.Length); // 2

      // Order is not guaranteed, so the first document might be either
      // the Mtps.Toc or the Mtps.Xhtml document. Loop until we find the 
      // one we want
      foreach (primary primaryDoc in response.primaryDocuments)
      {
         Console.WriteLine(primaryDoc.primaryFormat); // Mtps.Xhtml or Mtps.Toc
         Console.WriteLine(response.primaryDocuments[0].Any.Name); // <div> or <toc>
      }

Scenario 4 - Partial match by GUID

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the GUID, version, and locale
      request.contentIdentifier = "4de07e43-5601-446e-9105-1144a5fdb08d";
      request.locale = "en-us";
      request.version = "VS.80";

      // Create the proxy. No need to set version since SOAP 1.2 is the default
      ContentService proxy = new ContentService();

      // Call the web service
      getContentResponse response = proxy.GetContent(request);

      Console.WriteLine(response.contentId);              // abhtw0f1
      Console.WriteLine(response.contentGuid);            // 4de07e43-5601-446e-9105-1144a5fdb08d

      // Console.WriteLine(response.locale);                 // null when no exact match
      // Console.WriteLine(response.version);                // null when no exact match

      // Nine other versions/locales available
      Console.WriteLine(response.availableVersionsAndLocales.Length); // 9
      Console.WriteLine(response.availableVersionsAndLocales[0].locale); // de-de - German
      Console.WriteLine(response.availableVersionsAndLocales[0].version); // VS.80
    

Scenario 5 - Fault - no match

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the alias, version, and locale
      request.contentIdentifier = "System.Xml.XmlWroter"; // misspelling
      request.locale = "en-us";
      request.version = "VS.80";

      // Create the proxy. No need to set version since SOAP 1.2 is the default
      ContentService proxy = new ContentService();

      // Call the web service
      try
      {
        getContentResponse response = proxy.GetContent(request);
      }
      catch (SoapException e)
      {
        XmlNode detail = e.Detail; 
        XmlNamespaceManager nsmgr = 
          new XmlNamespaceManager(detail.OwnerDocument.NameTable);
        nsmgr.AddNamespace("mtps", "urn:msdn-com:public-content-syndication");
        
        // Print the eventID, helpLink, and source
        Console.WriteLine(detail.SelectSingleNode("mtps:mtpsFaultDetail/mtps:eventId/text()").Value);
        Console.WriteLine(detail.SelectSingleNode("mtps:mtpsFaultDetail/mtps:helpLink/text()").Value);
        Console.WriteLine(detail.SelectSingleNode("mtps:mtpsFaultDetail/mtps:source/text()").Value);
      }
    

Scenario 6 - Retrieve summary information for a content item by URL using SOAP 1.1, exact match

      // Create the request object
      getContentRequest request = new getContentRequest();
      // Assign the URL, version, and locale
      // Note that the URL specifies a version and a locale
      request.contentIdentifier = "http://msdn2.microsoft.com/eak978d4(de-de,VS.70).aspx";
      request.locale = null;
      request.version = "VS.80";

      // Create the proxy and set the SOAP version
      ContentService proxy = new ContentService();
      proxy.SoapVersion = SoapProtocolVersion.Soap11;

      // Call the web service
      getContentResponse response = proxy.GetContent(request);

      Console.WriteLine(response.contentId);              // eak978d4
      // Note that the request.version overrides the version embedded in the URL
      Console.WriteLine(response.version);                // VS.80
      // But because request.locale was null, the locale from the URL is used
      Console.WriteLine(response.locale);                 // de-de

      // Two common documents are returned
      Console.WriteLine(response.commonDocuments.Length); // 2

      // The first common document contains search info
      Console.WriteLine(response.commonDocuments[0].commonFormat); // MTPS.Search

      // No contents were requested, so we only get summary info like format
      Console.WriteLine(response.commonDocuments[0].Any.Length); // 0

      // One other version/locale is available (German)
      // The first version/locale is the one we passed in
      Console.WriteLine(response.availableVersionsAndLocales.Length); // 2
      Console.WriteLine(response.availableVersionsAndLocales[0].locale); // en-us
      Console.WriteLine(response.availableVersionsAndLocales[0].version); // VS.80
      Console.WriteLine(response.availableVersionsAndLocales[1].locale); // de-de
      Console.WriteLine(response.availableVersionsAndLocales[1].version); // VS.80
    

GetNavigationPaths Operation

Description

Navigation path data - sometimes referred to as Table of Contents (TOC) information despite the fact that it is more broadly useful than simply providing a TOC - is somewhat non-intuitive in structure. Navigation path data for a content item is not stored within the content item itself. Rather, there is an entirely separate hierarchy of content items that describe the navigational struture. These content items are easily distinguished by the presence of an Mtps.Toc document. Mtps.Toc documents contain a description of a content item and its immediate children, as well as content keys for the Mtps.Toc documents of those children. Using this information, it is possible to traverse the entire navigation structure, but it would be highly inefficient.

The GetNavigationPaths operation allows a client to request all the possible navigational routes between two topics in a single round trip. Note that more than one route may exist between two topics, as the TOC may list the same topic in multiple places.

Request

The formal definition of the request can be found in the WSDL (available here). Here is an sample of what a request might look like:

<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>
        <getNavigationPathsRequest xmlns="urn:msdn-com:public-content-syndication">
            <root xmlns:k="urn:mtpg-com:mtps/2004/1/key">
                <k:contentId>ms224917</k:contentId>
                <k:locale>en-us</k:locale>
                <k:version>SQL.90</k:version>
            </root>
            <target xmlns:k="urn:mtpg-com:mtps/2004/1/key">
                <k:contentId>ms259124</k:contentId>
                <k:locale>en-us</k:locale>
                <k:version>SQL.90</k:version>
            </target>
        </getNavigationPathsRequest>
    </soap:Body>
</soap:Envelope>
    

Here, a SOAP 1.1 request is shown, but a SOAP 1.2 binding is also supported.

The request consists of two parts: a root and a target. Each of these consists of a content short identifier, a locale, and a version - collectively a navigation key. All three parts are required, and content identifiers other than a short identifier (e.g. a content GUID or content alias) are not currently supported.

The root identifies the content item that is the start of the requested navigation paths. The target identifies the content item that is the endpoint of the requested navigation paths. Root should be a navigational-type item. Target should be a content-type item, not a navigational-type item. That is, root should refer to an item that has a document of type Mtps.Toc, while target should refer to an item that has a document of type Mtps.Xhtml.

The most commonly used root will be the topmost node in the TOC tree. This node has a short ID of ms310241 and a version of MSDN.10.

Response

Here is a sample of what a response might look like:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <getNavigationPathsResponse
        xmlns="urn:msdn-com:public-content-syndication"
        xmlns:k="urn:mtpg-com:mtps/2004/1/key">
            <navigationPaths>
                <navigationPath>
                    <navigationPathNodes>
                        <navigationPathNode>
                            <navigationNodeKey>
                                <k:contentId>ms224917</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>SQL.90</k:version>
                            </navigationNodeKey>
                            <isPhantom>false</isPhantom>
                            <contentNodeKey>
                                <k:contentId>ms224928</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.10</k:version>
                            </contentNodeKey>
                            <title>LVL1_WDRT001_TOPIC01</title>
                        </navigationPathNode>
                        <navigationPathNode>
                                <navigationNodeKey>
                                    <k:contentId>ms224923</k:contentId>
                                    <k:locale>en-us</k:locale>
                                    <k:version>test.20</k:version>
                                </navigationNodeKey>
                                <isPhantom>false</isPhantom>
                                <contentNodeKey>
                                    <k:contentId>ms224923</k:contentId>
                                    <k:locale>en-us</k:locale>
                                    <k:version>test.20</k:version>
                                </contentNodeKey>
                            <title>LVL1_WDRT001_TOPIC02</title>
                        </navigationPathNode>
                    </navigationPathNodes>
                </navigationPath>
                <navigationPath>
                    <navigationPathNodes>
                        <navigationPathNode>
                            <navigationNodeKey>
                                <k:contentId>ms224923</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.10</k:version>
                            </navigationNodeKey>
                            <isPhantom>false</isPhantom>
                            <contentNodeKey>
                                <k:contentId>ms224928</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.10</k:version>
                            </contentNodeKey>
                            <title>LVL1_WDRT001_TOPIC01</title>
                        </navigationPathNode>
                        <navigationPathNode>
                            <navigationNodeKey>
                                <k:contentId>ms224923</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.10</k:version>
                            </navigationNodeKey>
                            <isPhantom>true</isPhantom>
                            <contentNodeKey>
                                <k:contentId>ms224939</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.10</k:version>
                            </contentNodeKey>
                            <title>LVL1_WDRT001_SUBTREE_REFERENCE</title>
                        </navigationPathNode>
                        <navigationPathNode>
                            <navigationNodeKey>
                                <k:contentId>ms224923</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.20</k:version>
                            </navigationNodeKey>
                            <isPhantom>false</isPhantom>
                            <contentNodeKey>
                                <k:contentId>ms224923</k:contentId>
                                <k:locale>en-us</k:locale>
                                <k:version>test.20</k:version>
                            </contentNodeKey>
                            <title>LVL2_WDRT001_TOPIC02</title>
                        </navigationPathNode>
                    </navigationPathNodes>
                </navigationPath>
            </navigationPaths>
        </getNavigationPathsResponse>
    </soap:Body>
</soap:Envelope>
    

The reponse is structured as follows:

The distinction between navigationNodeKey and contentNodeKey requires some explanation of the way navigation data is structured in the MTPS system. For each node in the table of contents (TOC), there are actually two content items: one for the TOC node itself, and one for the corresponding content. On the MSDN website, these correspond to the currently selected node in the left-hand navigation tree, and the content that appears in the main area of the window. This degree of separation is necessary because a particular content item could actually appear in two locations in the TOC.

To reflect this structure, two content keys are returned for each navigationPathNode. The navigationNodeKey identifies the TOC item itself. One could, for example, use this key with the GetContent operation to retrieve the Mtps.Toc document that lists all the children of this TOC node. The contentNodeKey, on the other hand, identifies the content item to which this TOC node operates. For example, if the current node is the TOC entry for a class, the contentNodeKey might identify the content item containing the Mtps.Xhtml document with overview information for the class.

Phantoms

Phantom nodes are a byproduct of the way navigational data is structured within MTPS. Essentially, they are "placeholder" navigational nodes that the system must interject. A node is a phantom node if the the <isPhantom> element in a <navigationPathNode> has a value of "true". In almost all cases, the correct way to handle phantoms is to skip them - to process as if the phantom node were not returned at all.

The sample code below demonstrates the correct handling of phantom nodes.

Faults

Faults are returned in the same manner as identified for GetContent faults. This table describes possible fault conditions and fault codes for GetNavigationPaths:

Code Description
mtpsContentIdentifierNotFound The specified content identifier did not correspond to any content items in MTPS.
mtpsRootAbsent The root element was missing from the request.
mtpsTargetAbsent The target element was missing from the request.
mtpsRequestAbsent The soap:Body element did not contain a request of the appropriate type.
mtpsContentIdNull The contentId element was missing or empty in either the root or the target..
mtpsContentIdInvalidFormat The contentId element was in an invalid format in either the root or the target.
mtpsVersionNull The version was not specified in either the root or the target..
mtpsVersionInvalidFormat The version in the request was in an incorrect format.
mtpsLocaleNull The locale was not specified in either the root or the target..
mtpsLocaleInvalidFormat The locale in the request was in an incorrect format in either the root or the target.
mtpsGeneralServerError Some other error occurred.

Sample C# Client Code

The below samples demonstrate the use of the MTPS Content Service. They assume that a proxy has been generated via "Add Web Reference" in Visual Studio 2005.

Sample 1 - Retrieving all paths between two content items

      ContentService proxy = new ContentService();

      navigationKey root = new navigationKey();
      // This is the root of the MSDN English TOC tree - you'll
      // probably specify this as your root most often.
      root.contentId = "ms123401";
      root.locale = "en-us";
      root.version = "MSDN01.10";

      navigationKey target = new navigationKey();
      target.contentId = "abhtw0f1";
      target.locale = "en-us";
      target.version = "VS.80";

      getNavigationPathsRequest request = new getNavigationPathsRequest();
      request.root = root;
      request.target = target;

      getNavigationPathsResponse response = proxy.GetNavigationPaths(request);

      Console.WriteLine("There were {0} paths between the root and the target.",
        response.navigationPaths.Length);
      int pathNumber = 1;

      // Loop through all the resultant navigation paths
      foreach (navigationPath path in response.navigationPaths)
      {
        Console.WriteLine("Path number {0}", pathNumber++);

        int nodeNumber = 1;
        int phantoms = 0; 

        // For each path, loop over all the navigationPathNodes. Skip any 
        // phantom nodes. 
        foreach (navigationPathNode node in path.navigationPathNodes)
        {
            if (node.isPhantom)
            {
               ++phantoms; 
            }
            else
            {
              // For each node, print out the relevant information
              Console.WriteLine("Node number {0}: ", nodeNumber++);
              Console.WriteLine("Title: {0}", node.title);
              Console.WriteLine("Navigation node: {0}, {1}, {2}",
                  node.navigationNodeKey.contentId,
                  node.navigationNodeKey.locale,
                  node.navigationNodeKey.version);
              Console.WriteLine("Content node: {0}, {1}, {2}",
                  node.contentNodeKey.contentId,
                  node.contentNodeKey.locale,
                  node.contentNodeKey.version);
            }
        }
        Console.WriteLine("Skipped {0} phantom nodes.", phantoms); 
      }
    

Notes on Selected Document Formats

Mtps.Xhtml

The Mtps.Xhtml primary document is the main document type in MTPS. It holds the XHTML content of a content item. This XHTML is generally compliant with the W3C’s Modular XHTML 1.1 standard. Because of the large amount of legacy content in the system, there are instances where complete compliance was not possible, but content is always well-formed XML. In most cases it is also standards-compliant.

It is important to note that the XHTML MTPS manages is “presentation-free”. That is, the XHTML contains no script, styles, or other artifacts that would control the look and feel of the rendered content. This allows the XHTML to be used in many different contexts by having styling applied at runtime, after the document is retrieved. The Mtps.Xhtml document does, however, contain some extension elements (easily detectible by the fact that they are not in the XHTML namespace) to enable certain behaviors on the MSDN2 website. If processing these extra elements would cause problems for your application, you can always use the Mtps.Failsafe primary document instead. When available, it is an equivalent to the Mtps.Xhtml document that contains only XHTML elements.

Some of the common extension elements used in Mtps.Xhtml documents are listed in the following table. The "mtps" prefix indicates a namespace URI of http://msdn2.microsoft.com/mtps.

Element Description
mtps:CodeSnippet Contains a chunk of code. This element may have a Language attribute indicating the language in which the code is written. Language might also have a value of "None" indicating that it is in no particular programming language. For instance, an XML sample common to all code snippets in a document may have a Language of "None".
mtps:CollapsibleArea As the name implies, indicates a region of the document intended to be collapsible. May have a Title attribute containing the title of the region.
mtps:InstrumentedLink Represents a hyperlink. The NavigateUrl attribute will contain a URL (usually an asset ID) that is the target of the link.
mtps:KTableControl TODO: I don't think I really understand what this thing is supposed to do.
mtps:MemberLink TODO: I'm not really sure what this is for.

Mtps.Failsafe

The Mtps.Failsafe primary document format is meant to serve as an alternative to the richer Mtps.Xhtml. Mtps.Failsafe contains an XHTML document that contains none of the MTPS extensions present in the Mtps.Xhtml format, and as such may be easier for some consumers to work with.

This XHTML is generally compliant with the W3C’s Modular XHTML 1.1 standard. Because of the large amount of legacy content in the system, there are instances where complete compliance was not possible, but content is always well-formed XML. In most cases it is also standards-compliant.

Mtpc.Toc

As described above in the documentation for GetNavigationPaths, the Mtps.Toc primary document format is used to express the navigational structure of content items in MTPS. This is an example of an Mtps.Toc document:

<toc:Node toc:Title="XmlReader Class" 
    toc:SubTree="AssetId:VS%7ccpref19%7c%24%5ccpref.hxt%400%2c0%2c47" 
    toc:SubTreeVersion="VS.80" 
    toc:SubTreeLocale="en-US" 
    toc:Description="" 
    toc:Target="AssetId:T%3aSystem.Xml.XmlReader" 
    toc:TargetLocale="en-US" 
    toc:TargetVersion="VS.80" 
    toc:IsPhantom="false" 
    xmlns:toc="urn:mtpg-com:mtps/2004/1/toc">
    <toc:Node toc:Title="XmlReader Members" 
        toc:Target="AssetId:AllMembers.T%3aSystem.Xml.XmlReader" 
        toc:TargetLocale="en-US" 
        toc:TargetVersion="VS.80" 
        toc:IsPhantom="false" />
    <toc:Node toc:Title="XmlReader Constructor" 
        toc:Target="AssetId:M%3aSystem.Xml.XmlReader.%23ctor" 
        toc:TargetLocale="en-US" 
        toc:TargetVersion="VS.80" 
        toc:IsPhantom="false" />
    <toc:Node toc:Title="XmlReader Methods" 
        toc:SubTree="AssetId:VS%7ccpref19%7c%24%5ccpref.hxt%400%2c0%2c47%2c2" 
        toc:SubTreeVersion="VS.80" 
        toc:SubTreeLocale="en-US" 
        toc:Target="AssetId:Methods.T%3aSystem.Xml.XmlReader" 
        toc:TargetLocale="en-US" 
        toc:TargetVersion="VS.80" 
        toc:IsPhantom="false" />
    <toc:Node toc:Title="XmlReader Properties" 
        toc:SubTree="AssetId:VS%7ccpref19%7c%24%5ccpref.hxt%400%2c0%2c47%2c3" 
        toc:SubTreeVersion="VS.80" 
        toc:SubTreeLocale="en-US" 
        toc:Target="AssetId:Properties.T%3aSystem.Xml.XmlReader" 
        toc:TargetLocale="en-US" 
        toc:TargetVersion="VS.80" 
        toc:IsPhantom="false" />
</toc:Node>
    

The topmost Node element represents the content item of interest. SubTree, SubTreeVersion, and SubTreeLocale combine to form a contentKey for the content item containing this Mtps.Toc document, and as such are usually not very interesting. Target, TargetLocale, and TargetVersion, however combine to form a content key for the content item containing the Mtps.Xhtml document associated with this navigation node.

Each of the subordinate Node elements represents a navigational child of the topmost element. Each of them has Target, TargetLocale, and TargetVersion attributes with the same semantics - they identify the associated content item. SubTree, SubTreeVersion, and SubTreeLocale may or may not be present, depending on whether that node itself has child nodes. If so, these attributes combine to identify a content item with an Mtps.Toc document one level farther "down" the tree.

The semantics of Title are fairly obvious.

The Description attribute is not used and will always be empty.

The IsPhantom attribute indicates whether this node is a navigational phantom. Phantoms are documented above.

Mtps.Links

The Mtps.Links document is a convenience addition to any content item whose primary document contains links by asset ID. It is a straightforward XML format mapping asset IDs to short IDs, content GUIDs, and content aliases (if extant). This information is useful to applications wishing to normalize to on identifier form, or for applications wishing to translate from asset IDs to short IDs for use in calls to GetNavigationPaths.

Here is an example of an Mtps.Links document:

<mtps:links xmlns:mtps="urn:msdn-com:public-content-syndication">
    <mtps:link>
        <mtps:assetid>assetid:t%3asystem.xml.xmlurlresolver</mtps:assetid>
        <?xml namespace="" prefix="k" ?>
        <k:contentid xmlns:k="urn:mtpg-com:mtps/2004/1/key">008et5fc</k:contentid>
        <k:contentguid xmlns:k="urn:mtpg-com:mtps/2004/1/key">725ceabb-b81d-4b7e-8e5c-4b3179bdae5d</k:contentguid>
        <k:contentalias xmlns:k="urn:mtpg-com:mtps/2004/1/key">system.xml.xmlurlresolver</k:contentalias>
    </mtps:link>
    <mtps:link>
        <mtps:assetid>assetid:e695047f-3c0f-4045-8708-5baea91cc380</mtps:assetid>
        <k:contentid xmlns:k="urn:mtpg-com:mtps/2004/1/key">2bcctyt8</k:contentid>
        <k:contentguid xmlns:k="urn:mtpg-com:mtps/2004/1/key">e695047f-3c0f-4045-8708-5baea91cc380</k:contentguid>
        <k:contentalias xmlns:k="urn:mtpg-com:mtps/2004/1/key">
        </k:contentalias>
    </mtps:link>
</mtps:links>

Mtps.Search

TODO

Mtps.Klinks

TODO