VB XML Cookbook, Recipe 1: XML Transformations using XML Literals (Doug Rothaus)

VB XML Cookbook, Recipe 1: XML Transformations using XML Literals (Doug Rothaus)

  • Comments 12

I was working on a blog entry about replacing XSLT transforms with Visual Basic XML Literals. As the entry progressed, I noticed that it was really, really long. So, Avner Aharoni and I talked things over and we decided to break it up into multiple entries and start a series, much like the LINQ Cookbook that was started a few months back.

Introducing the VB XML Cookbook. We’ll use these entries to show quick and easy solutions using XML Literals in Visual Basic. In many cases we’ll reference XSLT and XPath where there’s a direct (or very close) replacement of functionality. You’ll find that consuming and transforming XML is quick and easy using XML Literals, XML Axis Properties, and LINQ to XML—all of which are available starting with Visual Basic 2008.

In this first entry, we’ll show how you can perform simple XML transformations using XML Literals and LINQ. Each sample uses an embedded expression that returns a collection of XML Literals from a LINQ query or another source, such as a property or function that returns a collection of XML Literals. You will see how you can replace an entire XSLT transform with just a few lines of Visual Basic code.

Let’s look at our first example. Attached to this blog entry is an XML file that contains a portion of the Contacts from the AdventureWorks sample database for SQL Server in an XML document (AWContacts.xml). Each <Contact> element has an <EmailAddress> sub-element. The following code creates a new XML document with just the e-mail addresses from the source document.

Imports <xmlns="http://SampleSchema/AWContacts">

 

Public Class XMLCookbook

  Private Sub Recipe1()

    Dim xmlDoc = XDocument.Load("AWContacts.xml")

 

    Dim emailDoc = <?xml version="1.0"?>

                   <EmailAddresses>

                       <%= xmlDoc.<Contacts>.<Contact>.<EmailAddress> %>

                   </EmailAddresses>

 

    emailDoc.Save("EmailAddresses.xml")

  End Sub

End Class

 

This would take considerably more effort using an XSLT transform. Here, you simply use Visual Basic to create a “template” function, and use XML Literals to load and save the XML, as well as create the new XML document. The XML Child Axis property references the collection of <EmailAddress> sub-elements. In place of the <xsl:copy-of> element, you use an embedded expression to add the collection of elements to the new document. In the end, you’ve transformed the document without XSLT or XPath. Let’s take a look at what the XSLT (and Visual Basic Code) would look like for the same sample.

Recipe1.xslt

<?xml version='1.0'?>

<xsl:stylesheet

  version="1.0"

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

  xmlns:aw="http://SampleSchema/AWContacts"

  xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"

  xmlns:crm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactRecord"

  xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="aw:Contacts">

    <EmailAddresses>

      <xsl:copy-of select="aw:Contact/aw:EmailAddress"/>

    </EmailAddresses>

  </xsl:template>

</xsl:stylesheet>

Recipe1_XSLT Visual Basic Code

 

Public Class XMLCookbook

    Sub Recipe1_XSLT()

        Dim xslTransform As New System.Xml.Xsl.XslCompiledTransform

        xslTransform.Load("recipe1.xslt")

 

        Dim reader = Xml.XmlReader.Create("AWContacts.xml")

        Dim sw As New System.IO.StreamWriter("Recipe1.xml")

        Dim writer = Xml.XmlWriter.Create(sw)

 

        xslTransform.Transform(reader, writer)

        sw.Close()

    End Sub

End Class

 

The XSLT version turns out to be about twice the amount of code and, to be honest, took me much longer to create than the VB version. Notice that the XML namespace support in Visual Basic is simpler than XSLT (1.0) as I can define a default XML namespace for XML elements that do not have an XML namespace identified.

Another important thing to mention is that part of the productivity gain comes from the Intellisense support provided with XML Literals in Visual Basic. By adding the schema files that are also attached to this blog entry and then importing the namespaces for the schemas, I get word completion lists for XML child and descendant elements as well as attributes. For more information, see XML Intellisense in Visual Basic.

Using LINQ

To go further, you can add query functionality to your transform using LINQ. In XSLT, you might use the <xsl:for-each> element to loop through results and the <xsl:if> element to test for a particular condition. Using LINQ, you can accomplish this rather easily.

For example, in our source document, each <Contact> element has an <EmailPromotion> sub-element that identifies whether the contact would like to receive promotion e-mails from the company. The following code creates the same document, but only containing e-mail addresses of contacts that want to receive e-mail promotions.

  Dim promoList = <?xml version="1.0"?>

                  <EmailPromotionList>

                      <%= From contact In xmlDoc.<Contacts>.<Contact> _

                          Where contact.<EmailPromotion>.Value > 0 _

                          Select contact.<EmailAddress> %>

                  </EmailPromotionList>

Comparable XSLT code would look like the following.

  <xsl:template match="aw:Contacts">

    <EmailAddresses>

      <xsl:for-each select="aw:Contact">

        <xsl:if test="aw:EmailPromotion &gt; 0">

          <xsl:copy-of select="aw:EmailAddress"/>

        </xsl:if>

      </xsl:for-each>

    </EmailAddresses>

  </xsl:template>

For the last example, we’ll go one step further and transform the contents of the source XML document to a new format. You can accomplish this by having a LINQ query return a collection of XML Literals. You can use embedded expressions to copy values from the source document into elements and attributes of the new XML Literal. For this example, the transformed document will rename the <EmailAddress> element to <Email>, and include the value of the <EmailPromotion> element as an attribute of the transformed <Email> element.

  Dim transformList = <?xml version="1.0"?>

                      <EmailPromotionList>

                          <%= From contact In xmlDoc.<Contacts>.<Contact> _

                              Where contact.<EmailPromotion>.Value > 0 _

                              Select <Email

                                       promotion=<%= contact.<EmailPromotion>.Value %>>

                                       <%= contact.<EmailAddress>.Value %>

                                     </Email> %>

                      </EmailPromotionList>

Comparable XSLT code would look like the following.

  <xsl:template match="aw:Contacts">

    <EmailPromotionList>

      <xsl:for-each select="aw:Contact">

        <xsl:if test="aw:EmailPromotion &gt; 0">

          <Email>

            <xsl:attribute name="promotion">

              <xsl:value-of select="aw:EmailPromotion"/>

            </xsl:attribute>

            <xsl:value-of select="aw:EmailAddress"/>

          </Email>

        </xsl:if>

      </xsl:for-each>

    </EmailPromotionList>

  </xsl:template>

To sum things up, we’ve seen how Visual Basic, XML Literals and LINQ can be used in place of the <xsl:copy-of>, <xsl:for-each>, <xsl:template>, <xsl:if>, <xsl:value-of>, and <xsl:attribute> elements as well as using XML Axis Properties in place of XPath to create a powerful, yet simple tool for XML transformations.

Stay tuned for more...

Attachment: AdventureWorksContacts.zip
Leave a Comment
  • Please add 3 and 8 and type the answer here:
  • Post
  • Después de la serie de artículos publicados por el equipo de Visual Basic sobre el aprendizaje de LINQ

  • Thanks for your examples, they clarify the appealing aspect of this approach.

    But I am not fully convinced that this approach can replace XSLT at all.

    For instance, how do you implement the identity transformation pattern? It's a very commonly used way in XSLT tp modify only parts of a document of you which you know little to start with. For instance, if the source document is an XHTML page, replacing all the instances of <br/> with <p>text</p>.

    The

    And, can you write code that parses this code? One of the many reasons why XSLT is useful is the ability to process itself, since its grammar is an XML application.

    I have the feeling that parsing the VB/XML literals/LINQ above would not be as easy.

    I realize that XSLT meta programming could be considered an "advanced" technique, but as a matter of fact becomes very useful as your code base grows.

    Regards,

    Alessandro

  • It's pretty simple to implement an identity transform pattern to do things like replace nodes. Your example of replacing all of the break nodes in an XHTML page with paragraphs could be as simple as a LINQ query to return the <br/> elements, then a call to the ReplaceWith method for each element and supply the new XML Literal (<p>Test</p>). For example...

           Dim xhtmlDoc = XDocument.Load(xhtmlFilePath)

           Dim breaks = (From element In xhtmlDoc.<html>...<br>).ToList()

           For Each break In breaks

               break.ReplaceWith(<p>Test</p>)

           Next

    Regarding parsing, true, you can't have XML Literals parse VB code like you can have XSLT parse itself. That is a nice advantage for management of a large code base.

  • This entry in the cookbook shows how you can access descendant and ancestor elements in an XML document

  • An identity transform in XSLT does just what the name implies: replace the identity of an element or

  • Recipe 3 showed one way to work with mixed XML content using the XML Descendant axis property and the

  • Visual Basic XML リテラルを使用した XSLT 変換の置き換えに関するブログを書いていたのですが、あまりにも長くなってしまいました。そこで Avner Aharoni と話し合って、いくつかのエントリに分割してシリーズ物にすることにしました。数か月前に始まった

  • 料理ブックのこのレシピでは、 XML ドキュメント内の子孫要素と先祖要素に Visual Basic 、 XML 軸プロパティ、および LINQ to XML オブジェクトを使用してアクセスする方法を紹介します。

  • XSLT の ID 変換は、その名称が示すとおり、ある要素または属性の ID を新しい ID で置き換えます。 ID 変換は、構造があまり固定されていない XML マークアップを操作するときに特に重要です。ニュース記事の文書構造を考えてみましょう。タイトルが記事内で参照されると、そのタイトルは斜体で強調表示されます。ただし、その記事の

  • 「 レシピ 3 」では、混在 XML コンテンツを XML 子孫軸プロパティ と ReplaceWith メソッドを使用して操作する 1 つの方法を紹介しました。これは ID 変換の 1 つの方法であり、今後の投稿で別の方法を取り上げます。完全に機能する

  • Most XSLT programmers are familiar with this XSLT transform to copy an XML file. &lt;? xml version =

  • Most XSLT programmers are familiar with this XSLT transform to copy an XML file. &lt;? xml version =

Page 1 of 1 (12 items)