programming4us
programming4us
DATABASE

SQL Server 2005 : Beyond OWC: Full-On OLAP Development (part 3) - XMLA at Your Service

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
7/30/2012 6:11:57 PM

XMLA at Your (Analysis) Service

Together, ADO MD.NET and AMO provide an almost overwhelmingly rich array of programming interfaces. Nothing is “hidden”: Anything that Management Studio and Visual Studio can do against Analysis Services databases and cubes, you can do, too, by using these two libraries. But it’s important to understand that underlying each of these libraries is nothing but XMLA.

You saw how the Analysis Services designers were, effectively, sophisticated front ends for generating XMLA scripts. You also saw how SQL Server Management Studio innately supports the generation of XMLA scripts for virtually any Analysis Services entity and sports a dedicated XMLA query window for executing those scripts.

We’d like to take a moment now to explore XMLA a bit further, by showing you how to use it from Management Studio for more than DDL scripts, how to use XMLA programmatically, and how you can expose “raw” XMLA functionality from ADO MD.NET. This will provide you with only a high-level understanding of how XMLA works, but we think it’s still extremely important. If you understand how to work with XMLA, you can potentially control Analysis Services from virtually any environment or platform that supports XML and Web services. Even if you do not plan to leave the .NET environment, understanding XMLA means understanding the native protocol of Analysis Services, and that has plenty of value in itself.

An API of Many Faces

You can understand XMLA from at least three different vantage points. First, you can see XMLA as a simple, programmable API. The core XMLA Web service provides just two methods: Discover (used to fetch metadata information from the server) and Execute (typically used to execute MDX queries and fetch the results). These methods accept and return information in the form of XML documents, which can be parsed or transformed to process or display the results.

Although XMLA can be used as a true Web service (and before the SQL Server 2005 release of Analysis Services, it had to be), its elevation to native API status changes things a bit. On the .NET platform, XMLA works over TCP/IP rather than HTTP, and a thin, managed assembly provides an API with certain enhancements over that provided by a Web reference proxy class. Specifically, if you want to use XMLA, you should set a reference to the Microsoft.AnalysisServices.Xmla library (listed on the .NET tab of the Add Reference dialog box in Visual Studio). Then you simply instantiate a Microsoft.AnalysisServices.Xmla.XmlaClient object to start writing XMLA code.

Before we look at an XMLA coding example, we will explore the second way to use XMLA: through the XMLA Query window in SQL Server Management Studio. As you will see, it is possible to create scripts that query your OLAP cubes as well as scripts that can create cubes, modify their structure, or perform an array of management tasks on them.

Finally, you can use ADO MD.NET to access the underlying XML payload returned by XMLA when MDX queries are executed. You get XML-formatted results from your MDX queries without having to submit your MDX queries in XML format or deal directly with XMLA as an API.

Using XMLA from SQL Server Management Studio

We’ll start our tour of XMLA in the XMLA Query window in Management Studio. The best way to understand XMLA is to use it in conjunction with Template Explorer because the builtin XMLA templates give you an excellent jump start on understanding the syntax and variety of possible XMLA queries.

Show the Template Explorer window if it is not visible, click the Analysis Server button (second from the left) on the window’s toolbar, and drill down on the XMLA node in the tree view. Drill down further on each of the three child nodes (Management, Schema Rowsets, and Server Status) to reveal the various XMLA templates available.

Using <Discover> for Metadata and Status Information

To see how easy it is to perform XMLA queries, drag the Sessions node (the third-to-last node under Server Status) into the XMLA Query window. Move the cursor left to deselect the text. You should see the following text in the window:

<Discover xmlns="urn:schemas-microsoft-com:xml-analysis">

  <RequestType>DISCOVER_SESSIONS</RequestType>

  <Restrictions>
    <RestrictionList>
    </RestrictionList>
  </Restrictions>

  <Properties><PropertyList></PropertyList></Properties>

</Discover>

The parent <Discover> element indicates that we will be calling the XMLA Web service’s Discover method (rather than its Execute method). You can think of the <RequestType> and <Restrictions> elements in much the same way that you think of the GetSchemaDataSet’s enumerated constant and restrictions array. The former is set to DISCOVER_SESSIONS, and the latter is empty; this will result in a complete list of all active sessions for the server.

The <Properties> child element is required for all XMLA commands. Usually this element/ parameter will contain connection and formatting information. But because we already supplied server-level connection information when the XMLA window was opened, all default settings are acceptable to us and we will leave this element empty.

To see the XML-formatted results of this command, press F5, Ctrl+E (or use the various Execute toolbar or menu commands). The results might look bewildering at first, but the XML results are easier to interpret if you scroll past the <xsd:schema> element to the first <row> element. That element’s content format should look similar to the following:

<row>
  <SESSION_ID>12394A18-5CB8-4AD1-AEB1-88E151C0030B</SESSION_ID>
  <SESSION_SPID>2356</SESSION_SPID>
  <SESSION_CONNECTION_ID>27</SESSION_CONNECTION_ID>
  <SESSION_USER_NAME>MYMACHINE\UserName</SESSION_USER_NAME>
  <SESSION_CURRENT_DATABASE>Chapter18</SESSION_CURRENT_DATABASE>
  <SESSION_START_TIME>2005-12-25T20:52:56</SESSION_START_TIME>
  <SESSION_ELAPSED_TIME_MS>841</SESSION_ELAPSED_TIME_MS>
  <SESSION_LAST_COMMAND_START_TIME>2005-12-25T20:52:57</SESSION_LAST_COMMAND_START_TIME>
  <SESSION_LAST_COMMAND_END_TIME>2005-12-25T20:52:56</SESSION_LAST_COMMAND_END_TIME>
  <SESSION_LAST_COMMAND_ELAPSED_TIME_MS>0</SESSION_LAST_COMMAND_ELAPSED_TIME_MS>
  <SESSION_IDLE_TIME_MS>0</SESSION_IDLE_TIME_MS>
  <SESSION_CPU_TIME_MS>80</SESSION_CPU_TIME_MS>
  <SESSION_LAST_COMMAND>DISCOVER_SESSIONS</SESSION_LAST_COMMAND>
  <SESSION_LAST_COMMAND_CPU_TIME_MS>0</SESSION_LAST_COMMAND_CPU_TIME_MS>
 </row>

					  

XMLA supports two response formats, tabular and multidimensional. Typically, as in this case, the Discover method returns tabular-formatted results, with each row contained in a separate <row> element, and each column contained in its own named child element. The Execute method, which we will examine shortly, typically uses the multidimensional format for its response content.

More Info

The tabular XMLA response format is nearly identical to the XML format used by the ADO.NET DataTable object, which is used, in turn, by the DataSet object’s ReadXml and WriteXml methods. Therefore, when you use XMLA programmatically, you can tweak tabular response content slightly and convert it to an ADO.NET DataTable, which is suitable for binding to Windows Forms or ASP.NET controls.


Note

The content of the <SESSION_USER_NAME> element in the XML snippet just shown has been obfuscated to MYMACHINE\UserName; actual results would present the real domain name and user name of the user logged into the session.


Using <Execute> for DDL Tasks

Let’s try another query. This time, we’ll use XMLA to perform an administrative task—processing the Adventure Works cube in our Adventure Works DW database:

<Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
<Command>
      <Process xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">
             <Type>ProcessFull</Type>
             <Object>
               <DatabaseID>Adventure Works DW</DatabaseID>
               <CubeID>Adventure Works DW</CubeID>
             </Object>
           </Process>
</Command>
<Properties />
</Execute>

					  

Notice that this command is contained in an <Execute> element instead of the <Discover> element used in our last query. That’s because this query performs an action. The <Execute> element contains a child <Command> element and an empty <Properties> child element, as with the last query. Within the <Command> element, the <Process> child element (and its child <Type> and <Object> elements) tells Analysis Services to run a full process against the Adventure Works cube in the Adventure Works DW database.

Important

The cube ID supplied is “Adventure Works DW,” even though the cube itself is named “Adventure Works.” XMLA, as it turns out, works with IDs rather than names. In the case of the Adventure Works cube, the ID and name do not match. To determine the ID of a cube, right-click on it in the Object Explorer window in Management Studio and choose Properties from the shortcut menu. The cube’s ID will appear in the second row of the General page in the Cube Properties dialog box, as shown in Figure 9.


Figure 9. The Cube Properties dialog box in SQL Server Management Studio, with the General page and ID property selected

Press F5 to run the process task. During processing, you will see the “Executing query...” message and animated icon appear in the XMLA Query window’s status bar and various status information on the Messages tab of the Results pane. When the processing is done, the Results tab will appear, displaying a standard “empty” XMLA message indicating that the process terminated successfully:

<return xmlns="urn:schemas-microsoft-com:xml-analysis">
  <root xmlns="urn:schemas-microsoft-com:xml-analysis:empty" />
</return>

It might seem counterintuitive for an empty response to indicate success, but consider that a failed process will always return an error message on the Messages tab. For example, if you were to intentionally change the <CubeID> element’s contents from Adventure Works DW to Adventure Works (which is a valid cube name but an invalid cube ID) and re-execute the query, you would see the following text on the Messages tab:

Executing the query ...
Errors in the metadata manager. Either the cube with the ID of 'Adventure Works' does
 not exist in the database with the ID of 'Adventure Works DW', or the user does not
have permissions to access the object.
Execution complete

					  

Using <Execute> to Run MDX Queries

To round out your understanding of XMLA you must understand that XMLA can also be used to execute MDX queries. It is a bit ironic that we are pointing this out after discussing XMLA’s DDL scripting capabilities because XMLA was originally designed primarily for MDX query execution (and metadata discovery). As such, XMLA easily accommodates the notion of cell sets containing axes, positions, and a collection of cells. Each of these entities is neatly packaged in the multidimensional-formatted XML response payload.

Under most circumstances, you would let ADO MD.NET process this XML document and populate a CellSet (or DataSet, DataTable, or DataReader) object with its contents, but you can use the Management Studio XMLA window to examine the XML content directly. This is relatively easy to do because the XML content, though somewhat complex, is quite readable if you have an understanding of OLAP, MDX, and cell sets.

<Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
  <Command>
    <Statement>
      SELECT Shippers.[Shipper Name].MEMBERS ON COLUMNS,
            Time.Year.MEMBERS ON ROWS
      FROM Sales
      WHERE Measures.[Total Sales]
    </Statement>
  </Command>
  <Properties>
    <PropertyList>
      <Catalog>Chapter18</Catalog>
    </PropertyList>
  </Properties>
</Execute>

Note that we once again use <Execute> as our parent tag, indicating that we are calling XMLA’s Execute method. The <Execute> element, as before, contains <Command> and <Properties> subelements. This time the <Command> element consists merely of a <Statement> element whose value is the MDX command we want to execute.

The <Properties> element, rather than being left empty as in our previous examples, consists of a <PropertyList> child element, which can in turn contain several child elements containing simple values. In the case of our query, we are only specifying the database name (in the <Catalog> element). For all other properties, we are using default values. Without a <Catalog> value, the query would run against the default database.

Note

It might seem odd that we must specify a database name, since the connection information we supplied to the XMLA window already indicates the database we want to use, but XMLA connections effectively accommodate only server information. The fact that the XMLA Query window uses the standard Connection To Analysis Services dialog box (on whose Connection Properties tab you can specify a database after clicking the Options button) is an anomaly. The database selection made in the Connection To Analysis Services dialog box is ignored; therefore, when you create an XMLA query, you must explicitly specify your database within the XMLA query itself.


Execute the query now to fetch the multidimensional response. You will see that a large XML response is returned. To make this XML easier to read, copy and paste it into a new XMLA Query window. This will allow you to expand and contract elements within the XML using the outline nodes in the left margin of the XMLA editor.

Now contract the xs:schema node in the return/root element (it begins on the third line of the document), and then contract the OlapInfo/CubeInfo element two lines below it. Go down one line more and examine the AxesInfo element. Notice that each axis, as well as the “Slicer” axis (which represents the MDX command’s WHERE clause), is described. Now contract the OlapInfo node (on line 4 of the document) and examine the Axes node immediately below it, looking at each <Axis> node within it. Notice that each tuple and member is enumerated, complete with Caption, UniqueName (<UName> element), and other property values.

For example, the entire COLUMNS axis (axis 0) is described in the XML response payload as follows, with one tuple per shipper (and one each for the All and Unknown members):

<Axis name="Axis0">
  <Tuples>
    <Tuple>
      <Member Hierarchy="[Shippers].[Shipper Name]">
        <UName>[Shippers].[Shipper Name].[All Shippers]</UName>
        <Caption>All Shippers</Caption>
        <LName>[Shippers].[Shipper Name].[(All)]</LName>
        <LNum>0</LNum>
        <DisplayInfo>66536</DisplayInfo>
      </Member>
    </Tuple>
    <Tuple>
      <Member Hierarchy="[Shippers].[Shipper Name]">
        <UName>[Shippers].[Shipper Name].&[1]</UName>
        <Caption>Speedy Express</Caption>
        <LName>[Shippers].[Shipper Name].[Shipper Name]</LName>
        <LNum>1</LNum>
        <DisplayInfo>0</DisplayInfo>
      </Member>
    </Tuple>
    <Tuple>
      <Member Hierarchy="[Shippers].[Shipper Name]">
        <UName>[Shippers].[Shipper Name].&[2]</UName>
        <Caption>United Package</Caption>
        <LName>[Shippers].[Shipper Name].[Shipper Name]</LName>
        <LNum>1</LNum>
        <DisplayInfo>131072</DisplayInfo>
      </Member>
    </Tuple>
    <Tuple>
      <Member Hierarchy="[Shippers].[Shipper Name]">
        <UName>[Shippers].[Shipper Name].&[3]</UName>
        <Caption>Federal Shipping</Caption>
        <LName>[Shippers].[Shipper Name].[Shipper Name]</LName>
        <LNum>1</LNum>
        <DisplayInfo>131072</DisplayInfo>
      </Member>
    </Tuple>
    <Tuple>
      <Member Hierarchy="[Shippers].[Shipper Name]">
         <UName>[Shippers].[Shipper Name].[All Shippers].UNKNOWNMEMBER</UName>
         <Caption>Unknown</Caption>
         <LName>[Shippers].[Shipper Name].[Shipper Name]</LName>
         <LNum>1</LNum>
         <DisplayInfo>131072</DisplayInfo>
       </Member>
     </Tuple>
   </Tuples>
 </Axis>

					  

For the Slicer axis, notice that the Measures tuple/member has a UniqueName of [Measures].[Total Sales], which squares with the WHERE clause in our MDX query:

<Axis name="SlicerAxis">
  <Tuples>
<Tuple>
  <Member Hierarchy="[Measures]">
    <UName>[Measures].[Total Sales]</UName>
    <Caption>Total Sales</Caption>
    <LName>[Measures].[MeasuresLevel]</LName>
    <LNum>0</LNum>
    <DisplayInfo>0</DisplayInfo>
  </Member>
 ...

Now contract the Axes node and examine the CellData node immediately following it. Notice that each cell’s Value and FormattedValue (<FmtValue> element) is provided, and that the cells are identified by the ordinal address we discussed earlier:

<CellData>
<Cell CellOrdinal="0">
   <Value xsi:type="xsd:double">1.35445859E6</Value>
   <FmtValue>$1,354,458.59</FmtValue>
</Cell>
<Cell CellOrdinal="1">
   <Value xsi:type="xsd:double">3.7398319E5</Value>
   <FmtValue>$373,983.19</FmtValue>
</Cell>
...

Calling Execute Programmatically from .NET

With this understanding of XMLA’s encoding of CellSet objects, you can imagine how it would be possible to create an XSL stylesheet that transforms the data into a human-readable HTML page. In fact, Microsoft has created just such a stylesheet. It is called Xamd.xsl, and it is distributed as part of a sample application in the XMLA SDK 1.1 (which you can download for free from http://msdn.microsoft.com, and which is actually designed for SQL Server 2000). You can use the stylesheet to transform any two-axis XML cell set into well-formed HTML, with the results displayed in a table.

You can thus execute MDX queries via XMLA directly from .NET (using Microsoft.AnalysisServices.Xmla, as discussed earlier). You can then use the stylesheet, some System.Xml code, and a WebBrowser control to display the results. To do so, you’ll first need to make sure you include the following namespaces in your code:

using System.Xml;
using System.Xml.Xsl;
using System.IO;

Once the namespaces are properly imported, you can use the code in Listing 2, which performs the XSL transformation for the MDX query we just discussed.

Listing 2. Executing MDX Queries with XMLA
// XMLA:
Microsoft.AnalysisServices.Xmla.XmlaClient xmlac = new
 Microsoft.AnalysisServices.Xmla.XmlaClient();

// System.Xml:
XslCompiledTransform xslCellSetTable = new XslCompiledTransform();
XmlTextWriter xtwCellSetTable = new XmlTextWriter(Path.GetFullPath(".") +
 "\\Execute.htm", null);
XmlDocument xdcResults = new XmlDocument();

string command = "<Statement>" + txtMDX.Text + "</Statement>";
string properties = "<PropertyList>" +
                    "   <Catalog>Chapter18</Catalog>" +
                    "</PropertyList>";
string results;

try
{
   // Load the stylesheet:
   xslCellSetTable.Load(Path.GetFullPath(".") + "\\xamd.xsl");

   // Fetch the XML into a string:
   xmlac.Connect(ConnectionString);
   xmlac.Execute(command, properties, out results, false, true);

   // Load the XML text into an XmlDocument
   xdcResults.LoadXml(results);

   // Strip off the outer <return> tag (which the stylesheet is not expecting):
   xdcResults.LoadXml(xdcResults.FirstChild.InnerXml);

   // Transform the XML to an HTML file:
   xslCellSetTable.Transform(xdcResults, xtwCellSetTable);

   // Close XmlTextWriter:
   xtwCellSetTable.Close();

   // Display generated HTML file in the WebBrowser control:
   wbrMain.Navigate(Path.GetFullPath(".") + "\\Execute.htm");
}

catch (Exception ex)
{
   MessageBox.Show(ex.Message);
}

finally
{
   // Close the connection:
   xmlac.Disconnect();
}

					  

Notice that the XmlaClient object has an Execute method that accepts XML strings identical to the contents of the <Command> and <Properties> child elements of the <Execute> element supplied in Management Studio’s XMLA Query window. The results are assigned to a third string argument. The last two arguments are Booleans of relatively little importance in this case.

Once the Execute method call is complete and the XML result string has been assigned to the string variable results, the code simply loads it into an XmlDocument object, applies the stylesheet transformation, and dumps the resultant HTML to a file called Execute.htm. The code then displays the file’s contents in a WebBrowser control. Your results should look similar to those depicted in Figure 10.

Figure 10. HTML-transformed results of an MDX query run via the XMLA Execute command

Manipulating XMLA Response Content from ADO MD.NET

In addition to using the stylesheet in conjunction with low-level XMLA coding, you can also use it with ADO MD.NET. That is because the AdomdCommand object has an ExecuteXmlReader method that directly returns the XMLA response payload generated when an AdomdCommand objects MDX query is executed. So by combining the ExecuteXmlReader method and code similar to that in Listing 2, the results can once again be displayed as HTML in a WebBrowser control.

Sample code for this technique is provided in Listing 3 (taken from the AdomdCommand .ExecuteXmlReader source code region in the form frmAPIs in the sample code’s Chapter19 Windows Forms application). This code makes the same assumptions as Listing 2.

Listing 3. Using ExecuteXmlReader
// ADO MD.NET:
AdomdConnection conXML = new AdomdConnection(ConnectionString);
AdomdCommand comXML = new AdomdCommand(txtMDX.Text, conXML);

// System.Xml:
XslCompiledTransform xslCellSetTable = new XslCompiledTransform();
XmlTextWriter xtwCellSetTable = new XmlTextWriter(Path.GetFullPath(".") +
 "\\Execute.htm", null);

try
{
   // Open the connection:
   conXML.Open();

   // Load the stylesheet:
   xslCellSetTable.Load(Path.GetFullPath(".") + "\\xamd.xsl");

   // Fetch and transform the XML to an HTML file:
   xslCellSetTable.Transform(comXML.ExecuteXmlReader(), xtwCellSetTable);

   // Close the XmlTextWriter:
   xtwCellSetTable.Close();

   // Display generated HTML file in the WebBrowser control:
   wbrMain.Navigate(Path.GetFullPath(".") + "\\Execute.htm");
}

catch (Exception ex)
{
   MessageBox.Show(ex.Message);
}

finally
{
   // Close the connection:
   conXML.Close();
}

					  

For the code in Listing 3 to compile properly, the following namespace inclusions must be properly inserted at the top of your source code file:

using Microsoft.AnalysisServices.AdomdClient;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
Other  
  •  Microsoft SQL Server 2008 R2 : Using FILESTREAM Storage (part 2) - Using FILESTREAM Storage for Data Columns
  •  Microsoft SQL Server 2008 R2 : Using FILESTREAM Storage (part 1) - Enabling FILESTREAM Storage
  •  SQL Server 2005 : Using Excel (part 2) - Using PivotTables and Charts in Applications and Web Pages
  •  SQL Server 2005 : Using Excel (part 1) - Working Within Excel
  •  Microsoft SQL Server 2008 R2 : Hierarchyid Data Type (part 2) - Modifying the Hierarchy
  •  Microsoft SQL Server 2008 R2 : Hierarchyid Data Type (part 1) - Creating a Hierarchy, Populating the Hierarchy, Querying the Hierarchy
  •  Using SQL Server 2005 Integration Services : Extensibility (part 4) - Custom Connection Managers
  •  Using SQL Server 2005 Integration Services : Extensibility (part 3) - Script Components
  •  Using SQL Server 2005 Integration Services : Extensibility (part 2) - Custom Components
  •  Using SQL Server 2005 Integration Services : Extensibility (part 1) - Script Tasks
  •  
    Top 10
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
    - Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
    - Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    programming4us programming4us
    programming4us
     
     
    programming4us