25
Extending System.Xml Ted Neward http://www.tedneward.com

Extending System.Xml Ted Neward

Embed Size (px)

Citation preview

Page 1: Extending System.Xml Ted Neward

Extending System.Xml

Ted Neward

http://www.tedneward.com

Page 2: Extending System.Xml Ted Neward

XML in .NET

• .NET has tremendous XML support “out of the box” Both Infoset-based and stream-based parser support XPath navigation across Infosets Schema-to-object support XML Serialization … and so on

Page 3: Extending System.Xml Ted Neward

XML in .NET

• Despite this, sometimes it’s just not enough Working with XML in a strongly-typed language is awkward XSLT doesn’t have all the behavior we want We need to “reach out” from an XSLT to someplace else (database?) We want to “extend” XPath to other hierarchical storage (Registry?

filesystem? database? XML database?)

• Fortunately, System.Xml provides for this

Page 4: Extending System.Xml Ted Neward

Extending System.Xml

• The .NET XML classes are highly extensible We’ll look at four ways to extend the XML support in .NET Extend XmlDocument and friends Extend XmlPathNavigator to navigate across other hierarchies Extend XmlReader/XmlWriter to produce/consume XML Extend XslTransform to include custom behavior

Page 5: Extending System.Xml Ted Neward

Extending XmlDocument

• XmlDocument is a concrete, non-sealed class LoadXml() parses XML into Infoset form Uses various CreateXXX() methods to create the Infoset tree Some methods are marked virtual for easy overriding Allow for creation of objects which can plug into Infoset tree

Page 6: Extending System.Xml Ted Neward

Extending XmlDocument

• Start with your basic Personpublic class Person{ public string FirstName { get { return “Fred”; } } public string LastName { get { return “Wesley”; } } public override string ToString() { return FirstName + " " + LastName; }}

Page 7: Extending System.Xml Ted Neward

Extending XmlDocument

• We want to create Persons from XMLstatic void Main(string[] args){ XmlDocument doc = new XmlDocument(); string xml = "<person>” + “<firstName>Fred</firstName>” + “<lastName>Wesley</lastName>” + “</person>“; doc.LoadXml(xml); Person p = // ???}

Page 8: Extending System.Xml Ted Neward

Extending XmlDocument

• Solution: Person IS-A XmlElement...class Person : XmlElement { internal Person(string prefix, string lname, string nsuri, XmlDocument doc) : base(prefix, lname, nsuri, doc) { } public string FirstName { get { return this["firstName"].InnerText; } } public string LastName { get { return this["lastName"].InnerText; } } public override string ToString() { return FirstName + " " + LastName; }}

Page 9: Extending System.Xml Ted Neward

Extending XmlDocument

• ... and we use a custom XmlDocument to create themclass PersonDocument : XmlDocument{ public override XmlElement CreateElement(string prefix, string lname, string nsuri) { if (lname=="person") return new Person(prefix, lname, nsuri, this); else return base.CreateElement(prefix, lname, nsuri); }}

Page 10: Extending System.Xml Ted Neward

Extending XmlDocument

• ... and now we can create Persons from XMLstatic void Main(){ string XML = // as before PersonDocument pdoc = new PersonDocument(); pdoc.LoadXml(XML);

Person p = (Person)pdoc.DocumentElement; Console.WriteLine(p);}

Page 11: Extending System.Xml Ted Neward

Extending XmlDocument

• So what? We can already do XML-to-object-to-XML mappings with xsd.exe Why bother overriding XmlDocument?

No schema definition required Flexible creation: what if we want to change types based on the XML? We want to work with both XML and type representations at once Allows for objects to be extensible; unrecognized elements (age?

SSN?) are still part of Person, just not captured strongly Requires extending XmlElement (implementation inheritance)

Page 12: Extending System.Xml Ted Neward

Extending XPathNavigator

• XPathNavigator: abstract class providing XPath cursor Provides ability to execute XPath queries on hierarchical storage XPathDocument provides XPathNavigator for XmlDocument objects Extend XPathNavigator and override as necessary to provide customization (See Aaron Skonnard’s “XML Files” article in MSDN for examples)

public static void Main(){ XPathDocument doc = new XPathDocument("books.xml"); XPathNavigator nav = doc.CreateNavigator();

XPathNodeIterator ni = nav.Select("/bookstore/book/title"); while (ni.MoveNext()) Console.WriteLine(ni.Current.Value);}

Page 13: Extending System.Xml Ted Neward

Extending XPathNavigator

• So what? XPath provides powerful hierarchical query API Extend that to other hierarchical storage systems for ease-of-use Because XslTransform takes XPathNavigator as source argument, use

custom XPathNavigator to do transforms on non-XML sources

Page 14: Extending System.Xml Ted Neward

Extending XmlReader/XmlWriter

• XmlReader and XmlWriter “Source” and “sink” for XML, respectively Abstract base classes with numerous abstract methods

• XmlTextReader and XmlTextWriter Derivatives of XmlReader and XmlWriter, respectively Specifically deal with producing/consuming XML from text streams Useful as templates for creating customized reader/writer classes

Page 15: Extending System.Xml Ted Neward

Extending XmlReader/XmlWriter

• So what? We have XmlTextReader/XmlTextWriter, what else do we need? XML may come in forms other than plain text

encrypted compressed

XML may come from other sources than files Fixed-length flat files CSV files

XML could be processed entirely in-proc: no storage whatsoever

Page 16: Extending System.Xml Ted Neward

Extending XslTransform

• XslTransform does XSLT processing programmatically Create an XslTransform object Call Transform(), passing in source and output:

public static void Main(){ XslTransform xslt = new XslTransform();

XmlUrlResolver resolver = new XmlUrlResolver(); resolver.Credentials = new NetworkCredential("username","password","domain"); xslt.Load(“stylesheet.xsl", resolver); xslt.Transform(new XPathDocument("test.xml"), null, new XmlTextWriter(Console.Out), resolver);}

Page 17: Extending System.Xml Ted Neward

Extending XslTransform

• Two ways to add behavior to XSLT processing: Add extensions as “script” within XSLT stylesheet itself Add objects to XSLT arguments passed into Transform()

Page 18: Extending System.Xml Ted Neward

Extending XslTransform

• Add script extensions to stylesheet<xsl:stylesheet version=“1.0” xmlns:xsl=“...” xmlns:msxsl=“urn:schemas-microsoft-com:xslt” xmlns:ted=“http://www.clrgeeks.com/xsl-extensions”>

<msxsl:script implements-prefix=“ted” language=“C#”> public string Concat(string lhs, string rhs) { return lhs + “ “ + rhs; } </msxsl:script>

<xsl:template match=“/”> <xsl:value-of select=“ted:Concat(‘Hello’, ‘world’)” /> </xsl:template>

</xsl:stylesheet>

Page 19: Extending System.Xml Ted Neward

Extending XslTransform

• Add objects to argument list to Transform() First, create an “extension object”: methods will be called from XSLT

public class Extension { public string Concat(string s1, string s2) { return s1 + " " + s2; }}

Page 20: Extending System.Xml Ted Neward

Extending XslTransform

• Add objects to argument list to Transform() Add extension objects to XsltArgumentList and pass to Transform()

public static void Main(){ XslTransform xslt = new XslTransform(); XsltArgumentList args = new XsltArgumentList(); Extension obj = new Extension(); args.AddExtensionObject("http://www.clrgeeks.com/Extension", obj);

xslt.Load("extended.xsl", resolver); xslt.Transform(new XPathDocument("test.xml"), args, new XmlTextWriter(Console.Out), resolver);}

Page 21: Extending System.Xml Ted Neward

Extending XslTransform

• Add objects to argument list to Transform() Use the called method in the stylesheet

<xsl:stylesheet version="1.0“ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ted="http://www.clrgeeks.com/Extension">

<xsl:template match="/"> <xsl:value-of select="ted:Concat('Hello', 'world')" /> </xsl:template>

</xsl:stylesheet>

Page 22: Extending System.Xml Ted Neward

Extending XslTransform

• So what? XSLT has a lot of built-in behavior; what more do we need? Extensions can provide additional “reach” to XSLT

database network (FTP, HTTP, WebServices/SOAP, ...) other web services

Extensions can also provide similar-yet-different behavior Such as concat-with-whitespace, concat-without-whitespace, etc. Best of both worlds: XSLT + the .NET FCL

Page 23: Extending System.Xml Ted Neward

Summary

• Extending System.Xml is a lot easier than you might think• Look for ways to use this flexibility

Custom XmlDocument types to provide type-safety and Infoset APIs Custom XPathNavigators to allow for easy access and XSLT transformation Custom XML sources and sinks Custom behavior in XSL transformations

Page 24: Extending System.Xml Ted Neward

Questions

?

Page 25: Extending System.Xml Ted Neward

Credentials

• Who is this guy? Independent consultant Author

C# in a Nutshell (O’Reilly, with Drayton, Albahari, 2001) Server-Based Java Programming (Manning, 2000) SSCLI Essentials (O’Reilly, with Stutz, Shilling, 2003) Effective Enterprise Java (Addison-Wesley, 3Q 2003)

Papers at http://www.neward.net Blog at http://blogs.tedneward.com