Showing posts with label Transform. Show all posts
Showing posts with label Transform. Show all posts

Sunday, April 28, 2013

mdq.XmlTransform -- Part 2: Creating an MS Word Doc


Intro

mdq.xmlTransform can do amazing things. Today I will show you how to write a T-SQL query that returns a Microsoft Office Word document viewable in Word 2003 and later (and most programs that open .doc or .docx files). With mdq.xmlTransform it's very easy. If you don't yet have it, see Setting up mdq.XmlTransform for DDL and setup instructions; it takes less than a minute to setup.


Let's get right to it

Some may be intimidated at the idea of writing a query that returns an MS Word document. Don't be, it's simple. That's why I'll keep this real short and just show you.


(1) A Quick WordProcessingML (WordML) tutorial

1. Open notepad (Start > Run > notepad.exe)
2. Copy/paste the code below into your blank notepad file:

<?xml version="1.0" encoding="utf-8"?>
   
<?mso-application progid="Word.Document"?>
   
       
<w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">
           
<w:body>
                               
           
<w:p>
               
<w:r>
                   
<w:t>Hello Word!!!</w:t>
               
</w:r>
           
</w:p>
   
            
</w:body>
       
</w:wordDocument>

3. Go to file > save as and for "Save as Type" select All Files
4. For the file name type helloWord.xml
5. Click Save then close the file.

Now open the file with Microsoft Word version 2003 or later and you should see this:

Congrats! You just created your first word document using WordML.


(2) Using mdq.xmlTransform to produce a Word document

SQL Server supports the XML Data Type. WordML is XML. mdq.xmlTransform transforms XML. Now that you have seen how WordML works lets write a SQL query that returns a Word Document.

Using a database with mdq.xmlTranform, copy/paste and execute this code into SSMS:

DECLARE @xslt xml='

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">

    <xsl:output method="xml"  xml:space="default" />

 

    <!--  This template does all the work -->

    <xsl:template match="/" xml:space="default">

        <xsl:processing-instruction name="mso-application" xml:space="default">

            <xsl:text>progid="Word.Document"</xsl:text>

        </xsl:processing-instruction>

  

        <w:wordDocument><!-- This creates the word doc -->

            <w:body>

            <w:p>

                <w:r>

                    <w:t>Created with mdq.xmlTransform (no loops)</w:t>

                </w:r>

            </w:p>

            </w:body>

        </w:wordDocument>

    </xsl:template>  

    <xsl:template match="DataSourceID"/>

</xsl:stylesheet>';

 

SELECT REPLACE(mdq.xmlTransform('',@xslt),

                      '<?mso-application progid="Word.Document"?>',

                      '<?xml version="1.0" encoding="ISO-8859-1"?>

                       <?mso-application progid="Word.Document"?>') AS xml_output;

 

You should already know what will happen if you: copy/paste the result set into a new notepad file, save it like we did earlier, and then open it with Word (but feel free to do it again if you thought it was cool).


...and now for something a little more impressive...

Hopefully some developers, DBAs and BI people see the potential here. Think of how many SQL objects that are (or can be) stored in XML format. Query plans, traces, SSRS reports (RDL) and SSIS packages (DTSX packages) to name a few. Word and Excel files, your whatever.config files, a multitude of SharePoint objects, RSS feeds, web service data, Extended Events, etc, etc... All XML. Thanks to the XML data type and mdq.xmlTransform, information from all these things can be stored, measured, analyzed and, as I will show you in a moment, stuffed into XML files or fragments.

(3) Create a Word doc with SSRS Report (RDL) data

The code below contains two XML documents. For the first (1) I grabbed an some data from an SSRS RDL file (just part of it to keep things simple). Using T-SQL REPLACE I removed the rd: namespace references. The second (2) is an XML transform that will extract the Data Provider and Connection String from an SSRS report and use it to create a Word Doc.

<!--  (1) Grab an RDL XML FRAGMENT from an SSRS report -->
<!--  (using T-SQL REPLACE to remove the rd: namespace references) -->

<DataSource Name="ReportingDemo">
   
<DataSourceID>f34d206b-ca72-4ca6-9d5c-4151cd7eaxxx</DataSourceID>
   
<ConnectionProperties>
       
<DataProvider>SQL</DataProvider>
       
<ConnectString>
            Data Source=ABC;EFG Catalog=XYZ
       
</ConnectString>
   
</ConnectionProperties>
</DataSource>

<!—(2) Create an XSLT function that puts this data into a MS Word Doc -->

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">
   
<xsl:output method="xml"  xml:space="default" omit-xml-declaration="no" />


    <!--  This template does all the work -->
    <xsl:template match="/DataSource/ConnectionProperties" xml:space="preserve">
        <xsl:processing-instruction name="mso-application" xml:space="default">
            <xsl:text>progid="Word.Document"</xsl:text>
        </xsl:processing-instruction>
   
        <w:wordDocument><!-- This creates the word doc -->
            <w:body>

                <!-- These two templates collect the data -->
                <xsl:apply-templates select="DataProvider"/>
                <xsl:apply-templates select="ConnectString"/>
            </w:body>
        </w:wordDocument>
    </xsl:template>
   
    <xsl:template match="DataProvider" xml:space="preserve">
            <w:p>
                <w:r>
                    <w:t><xsl:apply-templates /></w:t>
                </w:r>
            </w:p>
    </xsl:template>

    <xsl:template match="ConnectString" xml:space="preserve">
            <w:p>
                <w:r>
                    <w:t><xsl:apply-templates /></w:t>
                </w:r>
            </w:p>
    </xsl:template>


    <!-- This disposes of DataSourceID-->
    <xsl:template match="DataSourceID"/>

</xsl:stylesheet>

If we feed that RDL data and transform to mdq.xmlTransform like this:

DECLARE @xml xml='

<DataSource Name="ReportingDemo">

    <DataSourceID>f34d206b-ca72-4ca6-9d5c-4151cd7eaxxx</DataSourceID>

    <ConnectionProperties>

        <DataProvider>SQL</DataProvider>

        <ConnectString>

            Data Source=ABC;EFG Catalog=XYZ

        </ConnectString>

    </ConnectionProperties>

</DataSource>',

 

@xslt xml='

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">

    <xsl:output method="xml"  xml:space="default" />

 

    <!--  This template does all the work -->

    <xsl:template match="/DataSource/ConnectionProperties" xml:space="default">

        <xsl:processing-instruction name="mso-application" xml:space="default">

            <xsl:text>progid="Word.Document"</xsl:text>

        </xsl:processing-instruction>

  

        <w:wordDocument><!-- This creates the word doc -->

            <w:body>

                <!-- These two templates collect the data -->

                <xsl:apply-templates select="DataProvider"/>

                <xsl:apply-templates select="ConnectString"/>

            </w:body>

        </w:wordDocument>

    </xsl:template>

  

    <xsl:template match="DataProvider" xml:space="preserve">

            <w:p>

                <w:r>

                    <w:t><xsl:apply-templates /></w:t>

                </w:r>

            </w:p>

    </xsl:template>

 

    <xsl:template match="ConnectString" xml:space="preserve">

            <w:p>

                <w:r>

                    <w:t><xsl:apply-templates /></w:t>

                </w:r>

            </w:p>

    </xsl:template>

 

    <!-- This disposes of DataSourceID-->

    <xsl:template match="DataSourceID"/>

</xsl:stylesheet>';

 

SELECT REPLACE(mdq.xmlTransform(@xml,@xslt),

                      '<?mso-application progid="Word.Document"?>',

                      '<?xml version="1.0" encoding="ISO-8859-1"?>

                       <?mso-application progid="Word.Document"?>') AS xml_output;

 

We get this:

<?xml version="1.0" encoding="utf-8"?>
   
<?mso-application progid="Word.Document"?>
   
       
<w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">
           
<w:body>
               
           
<w:p>
               
<w:r>
                   
<w:t>SQL</w:t>
               
</w:r>
           
</w:p>
               
           
<w:p>
               
<w:r>
                   
<w:t>Data Source=ABC;EFG Catalog=XYZ</w:t>
               
</w:r>
           
</w:p>
   
            
</w:body>
       
</w:wordDocument>

...which, if we copy/paste into notepad and save as wow.xml, then open with Microsoft Office Word, we get:

Conclusion

mdq.xmlTransform is a powerful tool. Period. Today I showed you how to create a basic Word document using just T-SQL and mdq.xmlTransform. Thanks for reading!


--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')

Last Updated: 4/29/2013 11:35am (Posted, fixed code issues)

Saturday, April 27, 2013

XSLT 2.0 in SQL Server?


...not if you are relying on .NET or MSXML to process your XSLT 2.0 (or 3.0) transforms.

Many XSLT enthusiasts have been waiting years to show people what you can do in Microsoft Land (.NET, SQL Server, etc) with XSLT 2.0. MSXML still only supports XSLT 1.0. I went to MSDN's Frequently Asked Questions about XSLT page today for an update...

The end.


--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')

Last Updated: 4/27/2013 (Posted)

Sunday, April 21, 2013

Setting up mdq.XmlTransform


Intro

Last week I published an article about the mdq.XmlTransform Scalar CLR function that ships with SQL Server Master Data Services. In this post I will provide instructions for setting it up. The process is fast and painless (less than one minute provided you have the necessary credentials). If you are new to CLRs or XML transforms I suggest testing this on your own PC or in a Sandbox environment. This post won’t be very technical but you should have a basic understanding of SQL Server functions, the XML data type and Common Language Runtime (CLR) functions.


Setting up mdq.XmlTransform

mdq.XmlTransform will work on any version of SQL Server that supports CLRs. This means it can run on SQL Server 2005 through 2012 (Developer, Express, Enterprise, etc). Setup involves four simple steps: (1) creating the mdq schema, (2) enabling CLR integration, (3) creating the assembly, and then (4) creating mdq.XmlTransform. You can copy/paste the code below into SSMS except for the code in step 2; for that that I provided a link to where you can get the code.

1. Create the mdq schema
See this article for more details about creating schemas. The schema name does not need to be named "mdq" for this function to work (I am using "mdq" because everyone else does).

2. Enable CLR integration
To create and execute CLR functions you need CLR integration enabled. You can enable CLR integration by executing the following code:

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO

See this article for more information about CLR integration.

3. Create the MDQ assembly
The code to create the assembly (Microsoft.MasterDataServices.DataQuality) looks like this (truncated for readability):


CREATE ASSEMBLY [Microsoft.MasterDataServices.DataQuality]
AUTHORIZATION dbo
FROM 0x4D5A90000300000004000000FFFF0000B80000000000000040000000....
WITH PERMISSION_SET = SAFE
GO

For the complete version of the required code: Steps to create [Microsoft.MasterDataServices.DataQuality]

4. Create the CLR Function
mdq.XmlTransform is a Scalar CLR. To create it run the following code:


CREATE FUNCTION mdq.[XmlTransform](@xml XML, @xslt XML)
RETURNS NVARCHAR(MAX) WITH EXECUTE AS CALLER, RETURNS NULL ON NULL INPUT
AS
EXTERNAL NAME [Microsoft.MasterDataServices.DataQuality].[Microsoft.MasterDataServices.DataQuality.SqlClr].[XmlTransform]
GO

If you have completed steps 1 through 4 without any errors then you have successfully installed mdq.XmlTransform.

Using mdq.XmlTransform

mdq.XmlTransform takes two parameters: @xml and @xslt. The data type for both is XML. The first parameter, @xml can be an XML document, an XML fragment or an atomic value such as a string, date or any type of number. The second parameter, @xslt, must be an XML Transform (AKA XSLT stylesheet) and it must be version 1.0. The @xml parameter is what you want to transform, @xslt is how you want to transform it. XSLT is great for stuffing and splitting strings which means that the both the XML input and XSLT output can be a delimited sequence.

For testing I created a query that uses mdq.XmlTransform to calculate a factorial. @xml will be the number we want to calculate, @xslt is that code that will perform the calculation. To keep things simple I am not discussing performance tuning. The query below can be optimized in several ways but, for now, we just want to make sure that the CLR is working. I will address performance in future posts. mdq.XmlTransform will take the apply @xslt to @xml and return the result.

/************************************************************

Created by: Alan Burstein

Created on: 4/22/2013

 

How it works:

@xml can be xml, an xml fragment or an atomic value such

as a string, number or a delimited sequence.

 

@xslt needs to be a well-formed XML style sheet (XSLT).

 

mdq.XmlTransform will take the apply @xslt to @xml

and return the result.

 

This will work for numbers up to 170

************************************************************/

 

DECLARE @xml xml='17'

DECLARE @xslt xml='

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

        <xsl:template match="/" name="factorial">

          <xsl:param name="number" select="text()"/>

          <xsl:choose>

                <xsl:when test="$number &lt;= 1">1</xsl:when>

                <xsl:otherwise>

                  <xsl:variable name="recursive_result">

                        <xsl:call-template name="factorial">

                          <xsl:with-param name="number" select="$number - 1"/>

                        </xsl:call-template>

                  </xsl:variable>

                  <xsl:value-of select="$number * $recursive_result"/>

                </xsl:otherwise>

          </xsl:choose>

        </xsl:template>

</xsl:stylesheet>'

 

SELECT mdq.XmlTransform(@xml,@xslt) AS factorial

 



Summary

In this post we reviewed the steps for setting up and using mdq.XmlTransform. Come back soon for more examples of what you can do with this bad dog. Thanks for reading!


--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')

Last Updated: 11/13/2013 (added example)

Sunday, April 14, 2013

Missing CLR -- Part 2 of 2: mdq.xmlTransform


Intro

In my previous post I raised the question of a possible missing CLR on MSDN's Master Data Services CLR Functions page. It turns out that there was a missing CLR (there are actually quite a few new CLRs not listed but this is a topic for another time). The missing guy I'm talking about is, IMHO, the baddest CLR ever. Before I talk about this nasty new CLR let me, first, say a couple things about functional programming; it will matter in a moment. I promise.


Functional Programming

Functional Programming (FP) is very power full and elegant stuff. At Wikipedia, functional programming is defined as follows (emphasis mine):

In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state.[1] Functional programming has its roots in lambda calculus, a formal system developed in the 1930s to investigate computability, the Entscheidungsproblem, function definition, function application, and recursion. Many functional programming languages can be viewed as elaborations on the lambda calculus.

In the MSDN article I posted earlier today: Functional Programming vs. Imperative Programming FP is described a little differently (emphasis mine):

The functional programming paradigm was explicitly created to support a pure functional approach to problem solving. Functional programming is a form of declarative programming.

The article continues by discussing Functional Programming Using XSLT.

Many XSLT developers are familiar with the pure functional approach. The most effective way to develop an XSLT style sheet is to treat each template as an isolated, composable transformation.The order of execution is completely de-emphasized. XSLT does not allow side effects (with the exception that escaping mechanisms for executing procedural code can introduce side effects that result in functional impurity).


Is XSLT a Functional Programming Language?

There are some that still argue that XSLT is not a functional programming language. I disagree. In a November, 2001 article by Dimitre Novatchev titled, The Functional Programming Language XSLT - A proof through examples Novatchev demonstrates beyond any doubt that XSLT is a functional programming language by implementing many major functional programming design patterns. There were 35 functions in total that illustrated the usefulness of higher order functions using XSLT 1.0.


And the missing CLR is…

So, why all the blather about functional programming? Because the mysterious magical missing CLR is mdq.XmlTransform, you can read more about it here. Why is this thing "the baddest CLR ever?" mdq.XmlTransform is the baddest CLR ever because it does not just solve a specific problem, it extends your SQL server instance to support a whole new, super-powerful functional programming language. Furthermore, it does so without requiring you to compile any new code for each new function. Now you can implement pure functions in SQL server: functions where tasks can be executed asynchronously and where the order of execution can be completely de-emphasized. All this using a well-tested, reliable and proven open-source language which has been used with great success since last century. Not too Kludgy, eh?

The other bonus is that this bad dog was developed, tested, QA’d and deployed by Microsoft (so you know it's good!). It's so good in fact that, beginning with SQL Server 2008 R2, it ships with Microsoft's new EIM software: Master Data Services and Data Quality Services. This CLR is solid, trustworthy and does more for your SQL server instance than any CLR I have ever seen.

Come back soon for some examples of what you can do with this guy and thanks for reading.


Click to enlarge:

--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')


Last Updated: 4/19/2013 (code cleanup)

Saturday, April 13, 2013

Dodd-Frank#

Intro

I promise not to mix politics into this blog and I don't normally post poetry but, as someone who once worked at a Big Bank, I enjoyed this and thought it was worth posting.

<Dodd-Frank#>
I used to write code at the Bank
...and then along came dodd-frank
...and then my job really stank
...I no longer write code at the Bank

--anonymous
</Dodd-Frank#>


--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')

Missing CLR -- Part 1 of 2

Intro

Master Data Services ships with some nice, new common language runtime functions; click this link for more details. My question is this: take a look at the screenshot below; did MDS ship with only 11 CLRs? ...or did the folks at Microsoft forget to include one when they prepared this list?

Click to zoom:

Check back tomorrow.


--ab

The new xmlsqlninja logo ('X-M-L'-'See-Quel' 'ninja')


Last Updated: 4/19/2013 (code cleanup)

Monday, August 20, 2012

My Reusable, Element-Name Agnostic, XML to HTML table XSLT Transform - Part 1


Special Thanks

Like I said in my first post - this is my first blog. The best experience so far has been seeing where traffic to my site is coming from. Let me extend a special "Hello" to my readers in Hong Kong, Germany, Russia, Australia, South Africa, Indonesia, England, India (Hi Anu), Chicago, Bolingbrook, Woodridge and France. How cool is the Internet?!?! You say something in Chicago and someone listens in Bavaria. In some cases it's just one person but I will take it    :^))..

Intro

Ahhh... XML and SQL. As I have said before, none of this (blogs, the ability to communicate and collaborate globally with ease using the Internet) would be possible if not for the wonders of XML and SQL. I have written some posts about SQL but nothing yet about XML. Today that changes as I introduce my Reusable, Element-Name Agnostic, XML to HTML table XSLT Transform.

What it Does

You can attach any XML file that has the same format/hierarchey structure as an HTML table and attach it to my transform to create an HTML table populated with the with your XML data. It accomplishes this very quickly, regardless of the element names, using some XSLT best practices and with approx 30 lines of XSLT code.

It will take this...

Source XML data

... and turn it into this...

XML data transformed into HTML table

... which, in a HTML browser, will produce this

HTML in browser

... and will do so regardless of the names used in the XML file passed to it.

Background

When doing XML XSLT development (or any kind of development) one of my primary objectives is to accomplish the task at-hand with as little code as possible. This makes debugging easier and reduces the footprint for potential human error. My rule of thumb is “no solution is correct if a more elegant solution is available.” By elegant I mean: surprisingly simple yet highly effective. If you can get the same performance and accurate results then you have more work to do.

To demonstrate I will start by taking a basic transform that performs this task for a specific XML file/structure with static element names and re-write it so that it is re-usable and takes advantage of the functional programming power of XSLT.

Example XML (Catalog.xml)

I took this right from W3Schools.com. This is the file they use in many of their examples.

Catalog.xml


Desired Result (truncated for readability)

Title Artist Company Country Price Year
Empire Burlesque Bob Dylan USA Columbia 10.90 1985
Hide your heart Bonnie Tyler UK CBS Records 9.90 v1988
Greatest Hits Dolly Parton USA RCA 9.90 1982

Original Transform (Transform V1)

This is the transform before applying some XSLT development best practices to it. It is simple and easy-to-understand but can be improved. 

Transform V1:


Newly Updated Transform

Below (Transform V7) is the finished product. The most notable change is that I removed the FOR-EACH loop for building columns(td) and rows(tr); using FOR-EACH is not the best choice in XSLT for iterating through a node set (I still use a FOR-EACH to get the column headings). For the rest we are using XSLT templates. All explicit references to any element names (such as artist, price, year, etc) are removed. Instead the transform has been updated to return values based on their location in the node tree. This is done using path expressions and predicates. Writing transforms in this manner makes them much more reusable because you are not married XML structures based on element names.

Transform V7:

In the next post (Part 2) we will examine how we made the original more effective and reusable.


Updated on 8/27/2012 at 8:49PM