|
#region Copyright
/*********************************************************************************
* Copyright (c) 2004 by Martin Friedrich *
* Permission to freely distribute, modify and compile these sources and *
* binaries as long as this copyright notice is included. *
* Use of code on your risk! *
* *******************************************************************************/
#endregion
using System;
using System.Collections;
using System.Reflection;
namespace SaxParserSupport
{
namespace Impl
{
/// <summary>
/// <p>Implements the <i>XMLSimpleElement</i> interface.</p>
/// <p>By convention, the alias for the XMLSchema-instance
/// namespace is assumed to be "xsi".</p>
/// <p>Attribute names are mapped in the following way:
/// <list type="bullet">
/// <item>An attribute is mapped to a C# property with the same name as
/// the attribute, except for the character ":" being repaced by "_". If
/// no such property is found, an exception is thrown.</item>
/// <item>The class of the property must provide a constructor taking a string
/// as parameter. Each value of this string must be a valid representation of
/// a property instance. Constructors may throw any exceptions.</item>
/// <item>Attribute names beginning with "xmlns:" are treated differently in
/// that they are not mapped to any property, but instead are internally processed
/// for namespace specification.</item>
/// <item>Also, the "xsi:schemaLocation" and "xsi:noNamespaceSchemaLocation"
/// attributes are processed internally and are not mapped to any property.</item>
/// </list></p>
/// </summary>
public abstract class XMLSimpleElementImpl : XMLSimpleElement
{
/// <summary>
/// Constructs a new instance
/// </summary>
protected XMLSimpleElementImpl()
{
}
/// <summary>
/// <p>Sets a value for a given attribute. The attrbute name is in the
/// same form as it appears in a XML content.</p>
/// </summary>
/// <remarks>
/// This method may throw exceptions related to the reflective interface of
/// C#. Additionally, arbitrary exceptions may be thrown by the attribute's
/// constructor.
/// </remarks>
/// <param name="name">The name of the attribute</param>
/// <param name="value">The value of the attribute in a string form.</param>
public void setAttribute( string name, string value )
{
switch ( name )
{
case "xsi:schemaLocation":
string[] tokens = value.Split( null );
for ( int i = 0; i < tokens.Length; i += 2 )
{
_namespacelocations.Add( tokens[ i ], tokens[ i + 1 ] );
}
break;
case "xsi:noNamespaceSchemaLocation":
_namespacelocations.Add( "", value );
break;
default:
if ( name.StartsWith( "xmlns:" ) )
{
string nsname = name.Substring( 6 );
_namespaces.Add( nsname, value );
}
else
{
Type thistype = GetType();
string tgtname = transcodeAttributeName( name, true );
PropertyInfo pi = thistype.GetProperty( tgtname );
if ( pi != null )
{
Type[] argtypes = new Type[ 1 ];
argtypes[ 0 ] = typeof( string );
ConstructorInfo ci = pi.PropertyType.GetConstructor( argtypes );
if ( ci != null )
{
object[] args = new object[ 1 ];
args[ 0 ] = value;
pi.SetValue( this, ci.Invoke( args ), null );
} else throw new NotImplementedException( "Property \'" + name + "\' ctor is missing" );
} else throw new NotImplementedException( "Property \'" + name + "\' not found" );
}
break;
}
}
/// <summary>
/// Returns the qualified tag name as it appears in XML content, i.e.
/// prefixed with namespace alias instead of the namespace itself.
/// </summary>
/// <returns>The fully qualified tag name</returns>
public string getName()
{
return _name;
}
/// <summary>
/// Sets the fully qualified tag name. If the XML element represented
/// belongs to the default namespace, the tag name is the local name.
/// </summary>
/// <param name="n">The tag name</param>
public void setName( string n )
{
_name = n;
}
/// <summary>
/// Returns the owning (parent) <tt>XMLElement</tt> instance. For
/// instances of <tt>XMLDocument</tt> this is <tt>null</tt>.
/// </summary>
/// <returns>The owning element</returns>
public XMLElement getOwner()
{
return _owner;
}
/// <summary>
/// Sets the owning <tt>XMLElement</tt> instance.
/// </summary>
/// <param name="se">The owning <tt>XMLElement</tt> instance. If
/// <tt>this</tt> previous ownership relations are erased.</param>
public void setOwner( XMLElement se )
{
if ( _owner != null ) _owner.removeElement( this );
_owner = se;
if ( _owner != null ) _owner.addElement( this );
}
/// <summary>
/// Outputs this instance to a stream. The stream must be opened for
/// writing. All attributes including namespace declarations etc. are
/// written out.
/// </summary>
/// <remarks>
/// This method may throw any exception related to stream output.
/// </remarks>
/// <param name="ostr">The stream to be used for output</param>
public virtual void write( System.IO.StreamWriter ostr )
{
ostr.Write( "<{0}", getName() );
writeAttributes( ostr );
ostr.WriteLine( " />" );
}
/// <summary>
/// Writes all attributes of this <tt>XMLSimpleAttribute</tt> instance
/// to a stream
/// </summary>
/// <remarks>
/// This method may throw any exception related to stream output
/// </remarks>
/// <param name="ostr">The stream to be used for output</param>
protected void writeAttributes( System.IO.StreamWriter ostr )
{
foreach ( string i in _namespaces.Keys )
{
ostr.Write( " xmlns:{0}=\"{1}\"", i, _namespaces[ i ] );
}
if ( _namespacelocations.Count > 0 ) {
string ntns = (string ) _namespacelocations[ "" ];
if ( ntns != null ) ostr.Write( "xsi:noTargetNamespaceLocation=\"{0}\"", ntns );
System.Text.StringBuilder buff = new System.Text.StringBuilder();
foreach ( string i in _namespacelocations.Keys )
{
if ( i != string.Empty )
{
buff.Append( i ).Append( ' ' ).Append( _namespacelocations[ i ] );
}
}
if ( buff.Length > 0 ) ostr.Write( " xsi:schemaLocation=\"{0}\"", buff );
}
Type thistype = GetType();
foreach( PropertyInfo i in thistype.GetProperties(BindingFlags.Instance|BindingFlags.Public) )
{
object val = i.GetValue( this, null );
if ( val != null ) ostr.Write( " {0}=\"{1}\"", transcodeAttributeName( i.Name, false ), transcode( val.ToString() ) );
}
}
/// <summary>
/// This method is called when the current elements is closed. Inheriting
/// classes can override this method to process an element in the context
/// of it's parent element.
/// </summary>
/// <param name="owner">The parent, i.e. owning, instance of <tt>XMLElement</tt></param>
public virtual void onElementEnd( SaxParserSupport.XMLElement owner )
{
}
/// <summary>
/// Replaces characters ", <, > and & in the given string
/// </summary>
/// <param name="s">The string to be transcoded</param>
/// <returns></returns>
protected virtual string transcode( string s )
{
return s.Replace( "\"", """ ).Replace( "<", "<" ).Replace( ">", ">" )
.Replace( "&", "&" );
}
/// <summary>
/// Converts a XML attribute name into a valid C# member name or vice versa
/// </summary>
/// <param name="n">The attribute name</param>
/// <param name="fromXML">The direction ov conversion</param>
/// <returns></returns>
protected string transcodeAttributeName( string n, bool fromXML )
{
if ( fromXML )
{
return n.Replace( ":", "_" );
}
else
{
return n.Replace( "_", ":" );
}
}
/// <summary>
/// ***PRIVATE***
/// </summary>
private XMLElement _owner = null;
/// <summary>
/// ***PRIVATE***
/// </summary>
private string _name;
/// <summary>
/// ***PRIVATE***
/// </summary>
private Hashtable _namespacelocations = new Hashtable();
/// <summary>
/// ***PRIVATE***
/// </summary>
private Hashtable _namespaces = new Hashtable();
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Still lacking an university degree in computer science, I have 20 years of experience in software development and implementation. Having expert knowledge in object-oriented programming languages like C++, Java and C# on Windows, LINUX and UNIX platforms, I participated in multiple research projects at the University of Oldenburg. During these assignments, I was trusted with implementation of a graphical editor for specification languages like CSP or Z and a prototypical tool for workflow data distribution and analysis. I gained experiences in a widespread spectrum of CS and software development topics, ranging from compiler construction across data base programming to MDA. My research interests include questions of graphical user interface design and component-based systems.
I consider myself an old-school CS geek. While I admit that simple tasks do not pose much of a problem and can be done in quick and efficient manner, it's the challenging ones that appeal to me. If you are looking for a skillful employee - be it on a permanent, contract or freelance basis - and if you can live with a lacking university degree, why not contacting me?