This question already has answers here:
Calling a function from a string in C#
(5 answers)
Closed 5 years ago.
I am creating a game where you have to code to move a block around the screen in visual studio community 2015. The goal of this project is to create a game to teach people how to code. I have created a method to move the block (just up so far).
private void move(string dir)
{
if(dir=="up"&& pbxBot.Location.Y != 12)
{
this.pbxBot.Top = this.pbxBot.Top - 30;
}
}
I have a textbox(textBox1) and a button (btnGo), I want to set it so when the user types in textBox1 an clicks the go button the code is executed.
For example the user types in "move(up);" in textBox1 and clicks btnGo, the block will move 1 space up(the block is 30x30 pixels hence 30 pixels=1 space)
(This post has been changed so that the text to be compiled is displayed in an editable text box) all that has to be done is create a new Windows form project, and overwrite the project files by using copy and paste from this article into the project files indicated by name)
First things first:
First thing you need to do is load the Roslyn compiler package.
In Visual Studio, Tools/NuGet Package Manager/Package Manager Console
at the PM> prompt, enter Install-Package Microsoft.CodeAnalysis
When you create your project, target .NET Framework 4.6.1 in project/properties/application/Target framework
This code has been tested with Visual Studio 2015 and .NET Framework 4.6.1
Program.cs
using System;
using System.Windows.Forms;
namespace ExecuteText {
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System.Reflection;
namespace ExecuteText
{
/**************************************************************************************************
* A form 1.
*
* #sa System.Windows.Forms.Form
**************************************************************************************************/
public partial class Form1 : Form
{
/**************************************************************************************************
* Default constructor.
**************************************************************************************************/
public Form1()
{
InitializeComponent();
}
/**************************************************************************************************
* Gets the assembly files in this collection.
*
* #param assembly The assembly.
*
* #return An enumerator that allows foreach to be used to process the assembly files in this
* collection.
**************************************************************************************************/
IEnumerable<string> GetAssemblyFiles(Assembly assembly)
{
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assemblyName in assembly.GetReferencedAssemblies())
yield return loadedAssemblies.SingleOrDefault(a => a.FullName == assemblyName.FullName)?.Location;
}
/**************************************************************************************************
* Creates compiler context.
*
* #return The new compiler context.
**************************************************************************************************/
private CSharpCompilation CreateCompilerContext()
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(TextBox.Text);
var assemblyName = Path.GetRandomFileName();
Assembly a = typeof(Form1).Assembly;
var refs = GetMetadataReferencesInAssembly(a);
var compilation = CSharpCompilation.Create(
assemblyName,
new[] {syntaxTree},
refs.ToArray(),
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
return compilation;
}
/**************************************************************************************************
* Console write errors.
*
* #param result The result.
**************************************************************************************************/
private void ConsoleWriteErrors(EmitResult result)
{
var failures = result.Diagnostics.Where(CodeHasError);
var err = "";
foreach (var diagnostic in failures)
err += $"{diagnostic.Id}: {diagnostic.GetMessage()}";
ErrorTextBox.AppendText(err);
}
/**************************************************************************************************
* Executes the compiled code operation.
*
* #param ms The milliseconds.
**************************************************************************************************/
private void ExecuteCompiledCode(MemoryStream ms)
{
ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray());
var type = assembly.GetType("AStringOfCode.FunctionClass");
var obj = Activator.CreateInstance(type);
type.InvokeMember("Run",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] {Block});
ShowPosition();
}
/**************************************************************************************************
* Gets metadata references in assembly.
*
* #param assembly The assembly.
*
* #return The metadata references in assembly.
**************************************************************************************************/
private List<MetadataReference> GetMetadataReferencesInAssembly(Assembly assembly)
{
var assemblyFiles = GetAssemblyFiles(assembly);
Console.WriteLine(assemblyFiles);
List<MetadataReference> refs = new List<MetadataReference>();
foreach (var assemblyname in assemblyFiles)
refs.Add(MetadataReference.CreateFromFile(assemblyname));
return refs;
}
/**************************************************************************************************
* Code has error.
*
* #param diagnostic The diagnostic.
*
* #return True if it succeeds, false if it fails.
**************************************************************************************************/
private bool CodeHasError(Diagnostic diagnostic)
{
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
}
private void ShowPosition()
{
PositionTextBox.Text = Block.Location.X + "," + Block.Location.Y;
}
private void Form1_Load(object sender, EventArgs e)
{
ShowPosition();
}
private void Run_Click(object sender, EventArgs e)
{
var compilation = CreateCompilerContext();
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
if (result.Success)
{
ExecuteCompiledCode(ms);
}
else
{
ConsoleWriteErrors(result);
}
}
}
private void TextBox_TextChanged(object sender, EventArgs e)
{
}
}
}
Form1.Designer.cs
namespace ExecuteText
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.TextBox = new System.Windows.Forms.RichTextBox();
this.Block = new System.Windows.Forms.PictureBox();
this.Run = new System.Windows.Forms.Button();
this.ErrorTextBox = new System.Windows.Forms.RichTextBox();
this.PositionTextBox = new System.Windows.Forms.RichTextBox();
((System.ComponentModel.ISupportInitialize)(this.Block)).BeginInit();
this.SuspendLayout();
//
// TextBox
//
this.TextBox.Location = new System.Drawing.Point(12, 43);
this.TextBox.Name = "TextBox";
this.TextBox.Size = new System.Drawing.Size(400, 605);
this.TextBox.TabIndex = 0;
this.TextBox.Text = resources.GetString("TextBox.Text");
this.TextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged);
//
// Block
//
this.Block.BackColor = System.Drawing.Color.DodgerBlue;
this.Block.Location = new System.Drawing.Point(591, 314);
this.Block.Name = "Block";
this.Block.Size = new System.Drawing.Size(52, 50);
this.Block.TabIndex = 1;
this.Block.TabStop = false;
//
// Run
//
this.Run.Location = new System.Drawing.Point(12, 12);
this.Run.Name = "Run";
this.Run.Size = new System.Drawing.Size(75, 23);
this.Run.TabIndex = 2;
this.Run.Text = "Run";
this.Run.UseVisualStyleBackColor = true;
this.Run.Click += new System.EventHandler(this.Run_Click);
//
// ErrorTextBox
//
this.ErrorTextBox.Location = new System.Drawing.Point(12, 665);
this.ErrorTextBox.Name = "ErrorTextBox";
this.ErrorTextBox.Size = new System.Drawing.Size(747, 96);
this.ErrorTextBox.TabIndex = 3;
this.ErrorTextBox.Text = "";
//
// PositionTextBox
//
this.PositionTextBox.Location = new System.Drawing.Point(418, 43);
this.PositionTextBox.Name = "PositionTextBox";
this.PositionTextBox.Size = new System.Drawing.Size(341, 44);
this.PositionTextBox.TabIndex = 4;
this.PositionTextBox.Text = "";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(771, 773);
this.Controls.Add(this.PositionTextBox);
this.Controls.Add(this.ErrorTextBox);
this.Controls.Add(this.Run);
this.Controls.Add(this.Block);
this.Controls.Add(this.TextBox);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.Block)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.RichTextBox TextBox;
private System.Windows.Forms.Button Run;
public System.Windows.Forms.PictureBox Block;
private System.Windows.Forms.RichTextBox ErrorTextBox;
private System.Windows.Forms.RichTextBox PositionTextBox;
}
}
Form1.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="TextBox.Text" xml:space="preserve">
<value>using System;
using System.Drawing;
using System.Windows.Forms;
namespace AStringOfCode
{
public class FunctionClass
{
enum Directions
{
e_Up,
e_Down,
e_Left,
e_Right
};
private void Move(PictureBox p, Directions direction)
{
var fromPoint = p.Location;
var toPoint = p.Location;
switch (direction)
{
case Directions.e_Up:
toPoint = new Point(fromPoint.X, fromPoint.Y - 1);
break;
case Directions.e_Down:
toPoint = new Point(fromPoint.X, fromPoint.Y + 1);
break;
case Directions.e_Left:
toPoint = new Point(fromPoint.X - 1, fromPoint.Y);
break;
case Directions.e_Right:
toPoint = new Point(fromPoint.X + 1, fromPoint.Y);
break;
}
p.Location = toPoint;
}
public void Run(PictureBox p)
{
Move(p, Directions.e_Up);
}
}
}</value>
</data>
</root>
This should be what you're looking for.
When you run the application, you will see three windows and a button
1. the code window
2. the position window
3. the error window
and the "Run" Button.
...oh yes, let's not forget the "Block" we're moving!
you can modify the call to "move" by changing the second parameter to one of the 4 defined directions. When the "run" button is clicked, the code in the code window will be compiled and run (if there are no errors), the blue block will move one pixel in the direction indicated by the parameter to Move(), and the new position will be displayed in the Position window.
If there are errors in the compilation, they will be displayed in the Error window.
Hope this helps
If you're checking the parameter value in your move function, why not just check for the command itself?
Take the value in the text box and split it by the "(" symbol, then take the first part of your new list, in this case "move" and perform logic according to that value:
switch (textBoxValue.split("(")[0])
{
case "Move":
move();
break;
and so on.
Start by Extracting the method name from the string using string.Split or regex.
Then you can use reflection to invoke the method, something like this:
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod("MethodName");
theMethod.Invoke(this, parameters, ...);
This requires a using System.Reflection; Reference.
You can get the parameters just by using regex or string.Split to get what's inside the brackets. Chuck it in a try catch statement to handle when the function does not exist.
Related
I have an XSD schema that has been given to us by a data provider. I cannot modify it. I generated the classes using the XSD.exe command line tool. For everything it works perfectly, I can create my objects in C#, serialize it in XML and validate it against the XSD.
I have a problem with a small portion of it. The expected output is:
<Physical>
<Class>P</Class>
<Capacity>14</Capacity>
<Class>J</Class>
<Capacity>64</Capacity>
<Class>W</Class>
<Capacity>1</Capacity>
<Class>Y</Class>
<Capacity>2</Capacity>
</Physical>
<Saleable Protected="true">
<Class>P</Class>
<Capacity>14</Capacity>
<Class>J</Class>
<Capacity>64</Capacity>
<Class>W</Class>
<Capacity>1</Capacity>
<Class>Y</Class>
<Capacity>2</Capacity>
</Saleable>
As you can see, the child elements of Physical and Sealable alternate (i.e. Class, then Capacity, then Class, then Capacity, etc.).
This is the code of the class that was generated by XSD.exe:
public partial class ClassA
{
private string[] classField;
private Integerctype[] capacityField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Class", DataType = "token")]
public string[] Class
{
get
{
return this.classField;
}
set
{
this.classField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Capacity", IsNullable = true)]
public Integerctype[] Capacity
{
get
{
return this.capacityField;
}
set
{
this.capacityField = value;
}
}
}
And the output I receive after the serialization:
<Physical>
<Class>P</Class>
<Class>J</Class>
<Class>W</Class>
<Class>Y</Class>
<Capacity>14</Capacity>
<Capacity>64</Capacity>
<Capacity>1</Capacity>
<Capacity>2</Capacity>
</Physical>
<Saleable>
<Class>P</Class>
<Class>J</Class>
<Class>W</Class>
<Class>Y</Class>
<Capacity>14</Capacity>
<Capacity>64</Capacity>
<Capacity>1</Capacity>
<Capacity>2</Capacity>
</Saleable>
As you can see, we lost the alternation between Class and Capacity...
I tried to use the Order property of the XmlElementAttribute: the Class property was decorated with Order = 1, and the Capacity property was decorated with Order = 2, but it did not help. Example:
[System.Xml.Serialization.XmlElementAttribute("Class", DataType = "token", Order = 1)]
public string[] Class
During the validation, with or without the Order property, I receive errors as follow:
The element 'Physical' in namespace 'xxx' has invalid child element
'Class' in namespace 'xxx'. List of possible elements expected:
'Capacity' in namespace 'xxx'.
Finally, here is the portion of the XSD:
<xsd:element name="ClassA" minOccurs="0">
<xsd:complexType>
<xsd:all>
<xsd:element name="Physical" minOccurs="0">
<xsd:annotation>
<xsd:documentation>True, physical class A configuration</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Class" type="CabinClass.type" />
<xsd:element name="Capacity" type="Integer.ctype" nillable="true" />
</xsd:sequence>
<xsd:attributeGroup ref="Array.attgroup" />
</xsd:complexType>
</xsd:element>
<xsd:element name="Saleable" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Class A configuration for sales purposes</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Class" type="CabinClass.type" />
<xsd:element name="Capacity" type="Integer.ctype" nillable="true" />
</xsd:sequence>
<xsd:attributeGroup ref="Array.attgroup" />
</xsd:complexType>
</xsd:element>
</xsd:all>
<xsd:attributeGroup ref="Container.attgroup" />
</xsd:complexType>
</xsd:element>
My guess is that it is related to the presence of xsd:sequence. But as I said, I do not want to modify the XSD as it is provided by a data provider and we must ensure that the XML we generate is fully compatible.
Any idea how can I solve this problem?
Simplified code could be this:
public class Physical
{
[XmlElement("Capacity", typeof(int))]
[XmlElement("Class", typeof(string))]
public object[] Items { get; set; }
}
This will ensure correct deserialization and give the serialization of the elements in the order in which they are placed in the array.
A working version might look like this:
public class Physical
{
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("Capacity", typeof(int))]
[XmlElement("Class", typeof(string))]
public object[] Items
{
get
{
object[] items = new object[Class.Length * 2];
for (int i = 0; i < items.Length; i += 2)
{
items[i] = Class[i / 2];
items[i + 1] = Capacity[i / 2];
}
return items;
}
set
{
Class = new string[value.Length / 2];
Capacity = new int[value.Length / 2];
for (int i = 0; i < value.Length; i += 2)
{
Class[i / 2] = (string)value[i];
Capacity[i / 2] = (int)value[i + 1];
}
}
}
[XmlIgnore]
public string[] Class { get; set; }
[XmlIgnore]
public int[] Capacity { get; set; }
}
Change int to Integerctype, add DataType parameter.
Similarly, change the second class.
I have a very valid XMl string in memory downloaded from an OGC complaint web feature service.
When I use the following code to create am XmlTextReader to parse to my parser,
using (var sr = new StringReader(schemaString))
{
using (var reader = new XmlTextReader(sr))
{
try
{
schema = new GML2Parser().GetClassDefinition(reader, schema);
}
catch (Exception ex)
{
error = ex.Message;
}
}
}
I get an exception indicating Data at rool level is invalid. If I save this string to a local file say feature_desc.xsd the use File.ReadAllText and call the aforementioned routine, I run into a similar problem.
However, if I use XmlReader.Create(feature_desc.xsd), my parser does not throw an exception when it starts traversing the XML nodes. This is a method that summarizes these actions;
private void ParseFeatureDescription(DataTableInfo schema, string featureDescription, string featureFileName, string featureName)
{
var schemaLocation = string.Empty;
if (featureFileName != null)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(featureDescription);
schemaLocation = infrut.Utilities.CreateTempFilePath(featureFileName, FileExtension.xsd, false);
doc.Save(schemaLocation);
}
var error = DeserializeTableSchema(schema, featureDescription, featureName);
if (!string.IsNullOrEmpty(error))
{
var fromFileFeatureDesc = File.ReadAllText(schemaLocation);
if (featureDescription == fromFileFeatureDesc){}
error = DeserializeTableSchema(schema, fromFileFeatureDesc, featureName);
if (!string.IsNullOrEmpty(error))
{
// last resort
var reader = XmlReader.Create(schemaLocation);
schema = new GML2Parser().GetClassDefinition(reader, schema);
if (schema.Columns.Count == 0)
{
// trouble
ActionResponse.LogError("Error parsing description of " + featureName + ". Inner exception is \r\n" + error
+ " " + " for content \r\n" + fromFileFeatureDesc, "WFS Worker");
}
}
}
}
In memory representation of the string is:
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:ems=\"http://www.emssatcom.com\" xmlns:gml=\"http://www.opengis.net/gml\" elementFormDefault=\"qualified\" targetNamespace=\"http://www.emssatcom.com\">\r\n <xsd:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://10.25.131.62:8091/geoserver/schemas/gml/2.1.2/feature.xsd\" />\r\n <xsd:complexType name=\"asmcc_srr_viewType\">\r\n <xsd:complexContent>\r\n <xsd:extension base=\"gml:AbstractFeatureType\">\r\n <xsd:sequence>\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"gid\" nillable=\"true\" type=\"xsd:int\" />\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"srr_name\" nillable=\"true\" type=\"xsd:string\" />\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"the_geom\" nillable=\"true\" type=\"gml:PolygonPropertyType\" />\r\n </xsd:sequence>\r\n </xsd:extension>\r\n </xsd:complexContent>\r\n </xsd:complexType>\r\n <xsd:element name=\"asmcc_srr_view\" substitutionGroup=\"gml:_Feature\" type=\"ems:asmcc_srr_viewType\" />\r\n</xsd:schema>"
and persisted file is:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ems="http://www.emssatcom.com" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" targetNamespace="http://www.emssatcom.com">
<xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://10.25.131.62:8091/geoserver/schemas/gml/2.1.2/feature.xsd" />
<xsd:complexType name="asmcc_srr_viewType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="gid" nillable="true" type="xsd:int" />
<xsd:element maxOccurs="1" minOccurs="0" name="srr_name" nillable="true" type="xsd:string" />
<xsd:element maxOccurs="1" minOccurs="0" name="the_geom" nillable="true" type="gml:PolygonPropertyType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="asmcc_srr_view" substitutionGroup="gml:_Feature" type="ems:asmcc_srr_viewType" />
</xsd:schema>
Any one run into this?
Wild guess here: sometimes I get this error (line 1 col 1) in different applications because they stored in UTF-8 encoding and they have byte order mark at the very beginning of the text/file.
http://en.wikipedia.org/wiki/Byte_order_mark
Try to read file as ANSI string, not unicode
I have been tasked with finding out why a program passes an XML unit test when the attributes in the xsd portion do not match the values in the unit test. The problem is I know next to nothing about XML or xsd. I have read up on it in various places but nohing has helped me understand why the test is failing.
It seems that before I can figure out why it's not working, I need to understand what is happening in the method doing the unit testing. I think I grasp most of it, but there is a portion that I'm not sure I understand. This portion also deals with the xsd.
Here is my xsd:
public static class Constants
{
public const string Xsd = #"
<xs:schema elementFormDefault=""qualified"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:element name=""Datas"">
<xs:complexType>
<xs:sequence>
<xs:element name=""Data"">
<xs:attributeGroup ref=""allocData""/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:attributeGroup id=""allocData"">
<xs:attribute name=""Site"" type=""string""/>
<xs:attribute name=""MonthNum"" type=""string""/>
<xs:attribute name=""Department"" type=""string""/>
<xs:attribute name=""Numerator"" type=""float""/>
<xs:attribute name=""Data_Indicator"" type=""string""/>
<xs:attribute name=""Industry_Benchmark"" type=""int""/>
<xs:attribute name=""OSHA_Benchmark"" type=""int""/>
<!--xs:attribute name=""Comments"" type=""string""/-->
<xs:attribute name=""Executive_Comments"" type=""string""/>
<xs:attribute name=""Fleet_Executive_Comments"" type=""string""/>
</xs:attributeGroup>
</xs:schema>";
and here is the method for my unit test:
public void XMLTest()
{
List<DataResults> ListOfResults = new List<DataResults>();
DataResults r1 = new DataResults();
DataResults r2 = new DataResults();
HarvesterHandle testData = new HarvesterHandle();
r1.Site = "Springfield Site";
r1.Department = "Freak";
r1.MonthNum = "8";
r1.Numerator = 65807;
r1.Data_Indicator = "A12";
// r1.Comments = "Hello, World";
r1.Industry_Benchmark = 23;
r1.OSHA_Benchmark = 2;
r1.ExecutiveComments = "It costs HOW MUCH?";
r1.FleetExecComments = "No you can't have a new car";
r2.Site = "Joplin Site";
r2.Department = "Rock";
r2.MonthNum = "12";
r2.Numerator = 65625;
r2.Data_Indicator = "Ou812";
r2.Industry_Benchmark = 523;
r2.OSHA_Benchmark = 2456;
// r2.Comments = "GoodBye, World!";
r2.ExecutiveComments = "Cut it!";
r2.FleetExecComments = "It only has 250,000 miles";
ListOfResults.Add(r1);
ListOfResults.Add(r2);
var test = testData.XMLTest(ListOfResults);
var xmlDoc = XDocument.Parse(test.ToString());
XmlSchemaSet set = new XmlSchemaSet();
set.Add(XmlSchema.Read(XElement.Parse(Constants.Xsd).CreateReader(), (o, e) => { })); bool valid = true;
xmlDoc.Validate(set, (o, e) =>
{
valid = false;
});
Assert.IsTrue(valid);
var element = test.Descendants("Data").FirstOrDefault(x => x.Attribute("Site").Value.Equals(r1.Site));
Assert.IsNotNull(element);
Assert.AreEqual(r1.Site, element.Attribute("Site").Value);
Assert.AreEqual(r1.Department, element.Attribute("Department").Value);
Assert.AreEqual(r1.MonthNum.ToString(), element.Attribute("MonthNum").Value);
Assert.AreEqual(r1.Numerator.ToString(), element.Attribute("Numerator").Value);
Assert.AreEqual(r1.Data_Indicator, element.Attribute("Data_Indicator").Value);
Assert.AreEqual(r1.Industry_Benchmark.ToString(), element.Attribute("Industry_Benchmark").Value);
Assert.AreEqual(r1.OSHA_Benchmark.ToString(), element.Attribute("OSHA_Benchmark").Value);
// Assert.AreEqual(r1.Comments.ToString(), element.Attribute(
// "Comments").Value);
Assert.AreEqual(r1.ExecutiveComments.ToString(), element.Attribute("Executive_Comments").Value);
Assert.AreEqual(r1.FleetExecComments.ToString(), element.Attribute("Fleet_Executive_Comments").Value);
element = test.Descendants("Data").FirstOrDefault(x => x.Attribute("Site").Value.Equals(r2.Site));
Assert.IsNotNull(element);
Assert.AreEqual(r2.Site, element.Attribute("Site").Value);
Assert.AreEqual(r2.Department, element.Attribute("Department").Value);
Assert.AreEqual(r2.MonthNum.ToString(), element.Attribute("MonthNum").Value);
Assert.AreEqual(r2.Numerator.ToString(), element.Attribute("Numerator").Value);
Assert.AreEqual(r2.Data_Indicator, element.Attribute("Data_Indicator").Value);
Assert.AreEqual(r2.Industry_Benchmark.ToString(), element.Attribute("Industry_Benchmark").Value);
Assert.AreEqual(r2.OSHA_Benchmark.ToString(), element.Attribute("OSHA_Benchmark").Value);
// Assert.AreEqual(r2.Comments.ToString(), element.Attribute(
// "Comments").Value);
Assert.AreEqual(r2.ExecutiveComments.ToString(), element.Attribute(Executive_Comments").Value);
Assert.AreEqual(r2.FleetExecComments.ToString(), element.Attribute("Fleet_Executive_Comments").Value);
}
the part that appear to be dealing with the xsd is this:
XmlSchemaSet set = new XmlSchemaSet();
set.Add(XmlSchema.Read(XElement.Parse(Constants.Xsd).CreateReader(), (o, e) => { })); bool valid = true;
xmlDoc.Validate(set, (o, e) =>
{
valid = false;
});
Assert.IsTrue(valid);
The problem is if the attribute data types in the xsd do not match the actual data, the test still passes. For instance, if any of the string attributes (MonthNum, Site, etc) are changed to float, the test still passes. Also, if the .xsd element names Datas and Data are changed to something like Fred and Ethyl, the test still passes.
I am assuming that whatever the xsd portion of the code in the xml unit test method is doing, it is not checking for correct datatypes or element names
per request, here is my xml:
public const string XSLT = #"
<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
<xsl:output method=""text"" encoding=""us-ascii"" />
<xsl:template match=""/"">Site, MonthNum, Department, Numerator, Denominator, Data_Indicator, Industry_Benchmark, OSHA_Benchmark, <!--Comments--> Executive_Comments, Fleet_Executive_Comments,
<xsl:for-each select=""Datas/Data"">
<xsl:text>'</xsl:text>
<xsl:value-of select=""#site""/>
<xsl:text>','</xsl:text>
<xsl:value-of select=""#monthNum""/>
<xsl:text>','</xsl:text>
<xsl:value-of select=""#Department""/>
<xsl:text>','</xsl:text>
<xsl:value-of select=""#numerator""/>
<xsl:text>','</xsl:text>,
<xsl:value-of select=""Industry_Benchmark""/>
<xsl:text>'</xsl:text>,
<xsl:value-of select=""OSHA_Benchmark""/>
<xsl:text>'</xsl:text>,
<!--xsl:value-of select=""Comments""/-->
<!--xsl:text>'</xsl:text-->,
<xsl:value-of select=""Executive_Comments""/>
<xsl:text>'</xsl:text>,
<xsl:value-of select=""Fleet_Executive_Comments""/>
<xsl:text>'</xsl:text>,
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>";
}
}
edit: This is the XML generated when running the test:
<Data>
<Data Site="Springfield Site" MonthNum="8" Department="Freak" Numerator="65807" Data_Indicator="A12" Industry_Benchmark="23" OSHA_Benchmark="2" Executive_Comments="It costs HOW MUCH?" Fleet_Executive_Comments="No you can't have a new car" />
<Data Site="Joplin Site" MonthNum="12" Department="Rock" Numerator="65625" Data_Indicator="Ou812" Industry_Benchmark="523" OSHA_Benchmark="2456" Executive_Comments="Cut it!" Fleet_Executive_Comments="It only has 250,000 miles" />
</Data>
It appears that the problem was that the xsd was not correct. It was written as:
<xs:attribute name=""Site"" type=""string""/>
when it should have been written as
<xs:attribute name=""Site"" type=""xs:string""/>
I am trying to consume a Java web service but get an exception System.InvalidCastException: Cannot assign object of type ValueArrayType to an object of type ValueArrayType[]
I am consuming a third party service so cannot change the service and have been informed that they can consume the service ok with php and java.
Value Array type is complex type
<xsd:complexType name="ValueArrayType">
<xsd:sequence>
<xsd:element name="ValueName" type="xsd:string"/>
<xsd:element name="ValueType" type="xsd:string"/>
<xsd:element name="ValueValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
It is an element in the response DetailsType that can have several occurrences as it has max = unbound and is wrapped by a sequence attribute.
<xsd:complexType name="DetailsType">
<xsd:sequence>
<xsd:element name="Id" type="xsd:int"/>
<xsd:element name="MobileName" type="xsd:string"/>
<xsd:element name="ValueArray" type="tns:ValueArrayType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
I have tried wsdll.exe and svrcutil.exe to try and generate client code.
the ValueArrayType is defined in the generated code as an array.
public ValueArrayType[] ValueArray
{
get
{
return this.valueArrayField;
}
set
{
this.valueArrayField = value;
}
}
an example of the data coming back is.
....
<Details xsi:type="tns:DetailsType">
<Id xsi:type="xsd:int">9999</Id>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">Count</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">11</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">Start</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">31</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">A1</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">23</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">A2</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">0</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">X1</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">0</ValueValue>
</ValueArray>
.....
If I change the client code to public ValueArrayType ValueArray
instead of an array then the client works but only gets the first ValueArray returned.
Have tried suggestions from http://blogs.msdn.com/b/netcfteam/archive/2007/02/01/why-your-netcf-apps-fail-to-call-some-web-services.aspx.
Update
I have generated a WCF Service with the proxyclass generated from scvutil.
When I consume and check the xml with WCFTestCLient.exe.
An Array type is sent back as
<ValueArray>
<ValueArrayType>
<ValueName>a</ValueName>
<ValueType>string</ValueType>
<ValueValue>1</ValueValue>
</ValueArrayType>
<ValueArrayType>
<ValueName>a</ValueName>
<ValueType>string</ValueType>
<ValueValue>2</ValueValue>
</ValueArrayType>
</ValueArray>
I assume either the data being sent does not match the WSDL or there is a bug in the C# scvutil, or System.ServiceModel.
Try to specify your element type inside the generated code
[XmlElement(ElementName = "ValueArray", Type = typeof(ValueArrayType), Namespace = "YourSchemaNamespace")]
public ValueArrayType[] ValueArray
{
get
{
return this.valueArrayField;
}
set
{
this.valueArrayField = value;
}
}
More information is available at MSDN
The problem is caused by incorrect xsi:type values that mislead WCF deserialization (described here).
The workaround is to use OperationFormatUse.Literal instead of OperationFormatUse.Encoded on all operations.
Can you try something like this ?
JavaServecie js= new JavaService();
js.ValueArrayType arr= js.GetValues(.....
if the class is public.
Good day.
I got a problem about the attribute of "ref" for my XSD file.
My code :
using System;
using System.Collections;
using System.Xml;
using System.Xml.Schema;
class XmlSchemaTraverseExample
{
static void Main()
{
// Add the customer schema to a new XmlSchemaSet and compile it.
// Any schema validation warnings and errors encountered reading or
// compiling the schema are handled by the ValidationEventHandler delegate.
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.ValidationEventHandler += new ValidationEventHandler(ValidationCallback);
schemaSet.Add("http://www.w3.org/2001/XMLSchema", "recipe.xsd");
schemaSet.Compile();
// Retrieve the compiled XmlSchema object from the XmlSchemaSet
// by iterating over the Schemas property.
XmlSchema customerSchema = null;
foreach (XmlSchema schema in schemaSet.Schemas())
{
customerSchema = schema;
}
// Iterate over each XmlSchemaElement in the Values collection
// of the Elements property.
foreach (XmlSchemaElement element in customerSchema.Elements.Values)
{
Console.WriteLine("Element: {0}", element.Name);
// Get the complex type of the Customer element.
XmlSchemaComplexType complexType = element.ElementSchemaType as XmlSchemaComplexType;
// If the complex type has any attributes, get an enumerator
// and write each attribute name to the console.
if (complexType.AttributeUses.Count > 0)
{
IDictionaryEnumerator enumerator =
complexType.AttributeUses.GetEnumerator();
while (enumerator.MoveNext())
{
XmlSchemaAttribute attribute =
(XmlSchemaAttribute)enumerator.Value;
Console.WriteLine("Attribute: {0}", attribute.Name);
}
}
// Get the sequence particle of the complex type.
XmlSchemaSequence sequence = complexType.ContentTypeParticle as XmlSchemaSequence;
// Iterate over each XmlSchemaElement in the Items collection.
foreach (XmlSchemaElement childElement in sequence.Items)
{
Console.WriteLine("Element: {0}, {1}, {2}", childElement.RefName, childElement.MinOccurs, childElement.MaxOccurs);
}
}
}
static void ValidationCallback(object sender, ValidationEventArgs args)
{
if (args.Severity == XmlSeverityType.Warning)
Console.Write("WARNING: ");
else if (args.Severity == XmlSeverityType.Error)
Console.Write("ERROR: ");
Console.WriteLine(args.Message);
}
}
my XSD file
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Recipe">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="DocumentInfo" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!-- Element of DocumentInfo -->
<xsd:element name="DocumentInfo">
<xsd:complexType>
<xsd:attribute name="Name" type="xsd:string" />
<xsd:attribute name="Description" type="xsd:string" />
<xsd:attribute name="Creator" type="xsd:string" />
<xsd:attribute name="CreateTime" type="xsd:string" />
<xsd:attribute name="Revisor" type="xsd:string" />
<xsd:attribute name="ReviseTime" type="xsd:string" />
<xsd:attribute name="Version" type="xsd:string" />
<xsd:attribute name="Frozen" type="xsd:boolean" />
<xsd:attribute name="ASCSVersion" type="xsd:string" use="optional"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Now when i got the output below:
Element: Recipe
Element: http://www.w3.org/2001/XMLSchema:DocumentInfo, 1, 1
Element: http://www.w3.org/2001/XMLSchema:Prerequisite, 1, 1
Element: http://www.w3.org/2001/XMLSchema:Headers, 0, 1
Element: http://www.w3.org/2001/XMLSchema:Steps, 1, 1
How to remove the prefix of "http://www.w3.org/2001/XMLSchema" ?
I can only take use of the Attribute of "childElement.RefName", I can't find "childElement.Ref".
DEV IDE: VS2005. .NET 2.0.
Thanks in advance here.
BR!
Nano
You can either use childElement.Name or childElement.QualifiedName.Name
XmlSchemaElement.Name
XmlSchemaElement.QualifiedName