I'm trying to obtain the value of the logicalName attribute of the main node of this xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ticketlayout xmlns="http://www.example.com/ticketlayout" logicalName="target.xml" deviceCode="1" measurement="mm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/ticketlayout">
<fontdefinition id="BarCode">
<fontname>Code128bWin</fontname>
<size measure="pt">16</size>
</fontdefinition>
</ticketlayout>
I've tried to add the namespace "xsi", "http://www.w3.org/2001/XMLSchema-instance" this way:
XmlDocument fLayout = new XmlDocument();
fLayout.Load("myFile.xml");
XmlNamespaceManager nsmRequestLayout = new XmlNamespaceManager(fLayout.NameTable);
nsmRequestLayout.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
string sValue = fLayout.SelectNodes("//ticketlayout", nsmRequestLayout)[0].Attributes["name"].Value;
But I get no nodes. I've tried without namespace and no nodes again, and son on.
¿Could please anyone help me?
Thanks in advance.
If you want to get the value : target.xml
Try this code
XmlDocument fLayout = new XmlDocument();
fLayout.Load("myFile.xml"); // your XML file
var attrib = fLayout["ticketlayout"].Attributes["logicalName"].Value;
First of all your XML is not valid.
I modified to look this way in order to achieve what you are looking for.
XML File :
<?xml version="1.0" encoding="UTF-8"?>
<ticketlayout xmlns="http://www.example.com/ticketlayout" logicalName="target.xml" deviceCode="1" measurement="mm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/ticketlayout">
<fontdefinition id="BarCode">
<fontname>Code128bWin</fontname>
<size measure="pt">16</size>
</fontdefinition>
</ticketlayout>
I am not sure why you would not have a model structure to deserialize you xml, and then access whatever property/attribute you need.
Example :
Classes:
[XmlRoot(ElementName = "size", Namespace = "http://www.example.com/ticketlayout")]
public class Size
{
[XmlAttribute(AttributeName = "measure")]
public string Measure { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "fontdefinition", Namespace = "http://www.example.com/ticketlayout")]
public class Fontdefinition
{
[XmlElement(ElementName = "fontname", Namespace = "http://www.example.com/ticketlayout")]
public string Fontname { get; set; }
[XmlElement(ElementName = "size", Namespace = "http://www.example.com/ticketlayout")]
public Size Size { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
[XmlRoot(ElementName = "ticketlayout", Namespace = "http://www.example.com/ticketlayout")]
public class Ticketlayout
{
[XmlElement(ElementName = "fontdefinition", Namespace = "http://www.example.com/ticketlayout")]
public Fontdefinition Fontdefinition { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
[XmlAttribute(AttributeName = "logicalName")]
public string LogicalName { get; set; }
[XmlAttribute(AttributeName = "deviceCode")]
public string DeviceCode { get; set; }
[XmlAttribute(AttributeName = "measurement")]
public string Measurement { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string SchemaLocation { get; set; }
}
Then you could use a serializer :
public class Serializer
{
public T Deserialize<T>(string input) where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader stringReader = new StringReader(input))
{
return (T)xmlSerializer.Deserialize(stringReader);
}
}
public string Serialize<T>(T ObjectToSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());
StringBuilder builder = new StringBuilder();
using (StringWriterWithEncoding textWriter = new StringWriterWithEncoding(builder, Encoding.UTF8))
{
xmlSerializer.Serialize(textWriter, ObjectToSerialize);
return textWriter.ToString();
}
}
}
public class StringWriterWithEncoding : StringWriter
{
Encoding encoding;
public StringWriterWithEncoding(StringBuilder builder, Encoding encoding)
: base(builder)
{
this.encoding = encoding;
}
public override Encoding Encoding
{
get { return encoding; }
}
}
And finally you can access whatever you want by doing the following :
var serializer = new Serializer();
//I used a local file for testing, but it should be the same thing with your file
var xmlInputData = File.ReadAllText(#"MyXmlPath");
var output = serializer.Deserialize<Ticketlayout >(xmlInputData);
var logicalName = output.LogicalName;
Related
I'm deserialization the results of a request that has the same tag repeated at multiple levels, I have it working but to do so I'm changing the format of the XML before attempting to deserialize it.
I'm not able to edit the source of the XML to change it to only have Diary at one level.
Is there a way to adjust my XML attributes to handle the deserialization without needing to adjust the response?
XML Response
<?xml version="1.0" ?>
<Root>
<DiaryDetails>
<Diary>
<Diary created_user="value1" created_date="value2" long_text="value3" short_text="value4" entry_type="value5" >Value6</Diary>
</Diary>
<Diary>
<Diary created_user="value7" created_date="value8" long_text="value9" short_text="value10" entry_type="value11" >Value12</Diary>
</Diary>
</DiaryDetails>
</Root>
Class definition
[XmlRoot("DiaryDetails")]
public class Diaries : List<Diary> { }
[XmlRoot("Diary")]
public class Diary
{
[XmlAttribute("created_user")]
public string CreatedBy { get; set; }
[XmlAttribute("created_date")]
public string CreatedDate { get; set; }
[XmlAttribute("long_text")]
public string LongText { get; set; }
[XmlAttribute("short_text")]
public string ShortText { get; set; }
[XmlAttribute("entry_type")]
public string Type { get; set; }
}
Deserialization Method
internal T DeserilaiseObject<T>(string response)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
T DeserilaisedObject;
using (TextReader reader = new StringReader(response))
{
DeserilaisedObject = (T)serializer.Deserialize(reader);
}
return DeserilaisedObject;
}
I'm currently handling this with a string replace:
response = response.Replace("<Diary><Diary", "<Diary").Replace("</Diary></Diary>", "</Diary>");
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication40
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
[XmlRoot("Root")]
public class Root
{
[XmlArray("DiaryDetails")]
[XmlArrayItem("Diary")]
public List<DiaryMain> diaries { get; set; }
}
public class DiaryMain
{
public Diary Diary { get; set; }
}
[XmlRoot("Diary")]
public class Diary
{
[XmlAttribute("created_user")]
public string CreatedBy { get; set; }
[XmlAttribute("created_date")]
public string CreatedDate { get; set; }
[XmlAttribute("long_text")]
public string LongText { get; set; }
[XmlAttribute("short_text")]
public string ShortText { get; set; }
[XmlAttribute("entry_type")]
public string Type { get; set; }
}
}
Assuming that you are only interested at the attributed Diary elements at the second nesting level you could do this:
// load your xml into a document
var doc = new XmlDocument();
doc.Load("your_xml_file.xml");
// extract the interesting nodes using xpath
var nodes = doc.SelectNodes("//Diary/Diary");
// deserialize the filtered NodeList (yes it's that clunky)
var serializer = new XmlSerializer(typeof(Diary));
var diaries = nodes.Cast<XmlNode>().Select(x => serializer.Deserialize(new XmlNodeReader(x))).Cast<Diary>().ToArray();
I need to serialize a class to xml. If a certain condition is met at run-time, I want to add an XML attribute to an element and assign it a value. Sometimes, the "Error" attribute will appear and sometimes it won't.
My code that serializes my objects:
public class XmlToolsRepo : IXmlTools
{
public string SerializeToXML<T>(object obj)
{
string results = null;
Encoding enc = Encoding.UTF8;
using (MemoryStream ms = new MemoryStream())
{
using (XmlTextWriter xw = new XmlTextWriter(ms, enc))
{
xw.Formatting = Formatting.None;
XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
XmlSerializer xSerializer = new XmlSerializer(typeof(T));
xSerializer.Serialize(xw, obj, emptyNS);
}
results = enc.GetString(ms.ToArray());
}
return results;
}
}
A class with a property that could have a new attribute at run-time:
[DataContract]
public class H204
{
[DataMember]
[XmlAttribute]
public string Code { get; set; }
[DataMember]
public string DW { get; set; }
}
When a condition is met I need for the XML to look like this:
<?xml version="1.0" encoding="UTF-8"?>
<H204 Code="A">
<DW Error="test" />
</H204>
Try following :
public class H204
{
[XmlAttribute(AttributeName = "Code")]
public string Code { get; set; }
[XmlElement(ElementName = "DW")]
public DW dw{ get; set; }
}
public class DW
{
[XmlAttribute(AttributeName = "Error")]
public string text { get; set; }
}
I am trying to read a xml file and deserialize it to my InsertSensorType class and than read VALUE1,VALUE2 .. .I tried to add XmlElement name to my InsertionMetadata attribute in InsertSensorTypeMetadata class, but it doesn't work.I have searched and found solutions but they were not valid for this problem. Can anyone please tell me what i am doing wrong.
Xml File :
<?xml version="1.0" encoding="utf-8" ?>
<swes:InsertSensor
xmlns:swes="http://www.opengis.net/swes/2.0"
xmlns:sos="http://www.opengis.net/sos/2.0" >
<swes:metadata>
<sos:SosInsertionMetadata>
<sos:observationType>VALUE1</sos:observationType>
<sos:observationType>VALUE2</sos:observationType>
<sos:featureOfInterestType>VALUE3</sos:featureOfInterestType>
<sos:featureOfInterestType>VALUE4</sos:featureOfInterestType>
</sos:SosInsertionMetadata>
</swes:metadata>
</swes:InsertSensor>
My Classes :
namespace Problem1.Classes
{
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/swes/2.0")]
[XmlRootAttribute("InsertSensor", Namespace = "http://www.opengis.net/swes/2.0", IsNullable = false)]
public class InsertSensorType
{
[System.Xml.Serialization.XmlElementAttribute("metadata")]
public InsertSensorTypeMetadata[] metadata { get; set; }
}
[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.opengis.net/swes/2.0")]
public class InsertSensorTypeMetadata
{
[XmlElement(ElementName = "SosInsertionMetadata", Type = typeof(SosInsertionMetadataType))]
public InsertionMetadataType InsertionMetadata { get; set; }
}
[XmlIncludeAttribute(typeof(SosInsertionMetadataType))]
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/swes/2.0")]
public abstract partial class InsertionMetadataType
{
}
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/sos/2.0")]
public partial class SosInsertionMetadataType : InsertionMetadataType
{
[System.Xml.Serialization.XmlElementAttribute("observationType", DataType = "anyURI")]
public string[] observationType { get; set; }
[System.Xml.Serialization.XmlElementAttribute("featureOfInterestType", DataType = "anyURI")]
public string[] featureOfInterestType { get; set; }
}
}
And here is my main code :
static void Main(string[] args)
{
XmlElement xmlRequest = null;
XmlDocument doc = new XmlDocument();
doc.Load("request.xml");
xmlRequest = doc.DocumentElement;
executeRequest(xmlRequest);
}
static void executeRequest(XmlElement xmlRequest)
{
InsertSensorType insertSensorRequest = ValidateRequest<InsertSensorType>(xmlRequest);
InsertSensorTypeMetadata[] _InsertSensorTypeMetadata = insertSensorRequest.metadata;
Console.WriteLine("Length of metadata :" + _InsertSensorTypeMetadata.Length);//1
foreach (InsertSensorTypeMetadata istm in _InsertSensorTypeMetadata)
{
SosInsertionMetadataType sos = istm.InsertionMetadata as SosInsertionMetadataType;
//sos is null
}
Console.Read();
}
static T ValidateRequest<T>(XmlElement xmlRequest) where T : class
{
string xml = xmlRequest.OuterXml;
StringReader reader = new StringReader(xml);
XmlSerializer serializer = new XmlSerializer(typeof(T));
//XmlSerializer serializer = new XmlSerializer(typeof(T), new Type[] { typeof(SosInsertionMetadataType) });
T typeInstance = (T)serializer.Deserialize(reader);
return typeInstance;
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
InsertSensorType insertSensorType = new InsertSensorType() {
metadata = new Metadata() {
insertSensorTypeMetadata = new InsertSensorTypeMetadata() {
InsertionMetadata = new List<InsertionMetadataType>() {
new ObservationType() { value = "Value1"},
new ObservationType() { value = "Value2"},
new FeatureOfInterestType() { value = "Value3"},
new FeatureOfInterestType() { value = "Value4"}
}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(InsertSensorType));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("swes","http://www.opengis.net/swes/2.0");
ns.Add("sos","http://www.opengis.net/sos/2.0");
StreamWriter writer = new StreamWriter(FILENAME);
serializer.Serialize(writer, insertSensorType, ns);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(InsertSensorType));
XmlTextReader reader = new XmlTextReader(FILENAME);
InsertSensorType newInsertSensorType = (InsertSensorType)xs.Deserialize(reader);
}
}
[XmlRoot(ElementName = "InsertSensor")]
public class InsertSensorType
{
[XmlElement("metadata")]
public Metadata metadata { get; set; }
}
[XmlRoot("metadata", Namespace = "http://www.opengis.net/swes/2.0")]
public class Metadata
{
[XmlElement("SosInsertionMetadata")]
public InsertSensorTypeMetadata insertSensorTypeMetadata { get; set; }
}
[XmlRoot("SosInsertionMetadata", Namespace = "http://www.opengis.net/sos/2.0")]
public class InsertSensorTypeMetadata
{
[XmlElement()]
public List<InsertionMetadataType> InsertionMetadata { get; set; }
}
[XmlInclude(typeof(ObservationType))]
[XmlInclude(typeof(FeatureOfInterestType))]
[Serializable]
[XmlRoot(Namespace = "http://www.opengis.net/sos/2.0")]
public class InsertionMetadataType
{
public string value { get; set; }
}
[Serializable]
[XmlRoot(ElementName = "observationType", Namespace = "http://www.opengis.net/sos/2.0")]
public class ObservationType : InsertionMetadataType
{
}
[Serializable]
[XmlRoot(ElementName = "featureOfInterestType", Namespace = "http://www.opengis.net/sos/2.0")]
public class FeatureOfInterestType : InsertionMetadataType
{
}
}
My solution is that :
added this line to over InsertionMetadata attribute in InsertSensorTypeMetadata class
[System.Xml.Serialization.XmlElement(ElementName = "SosInsertionMetadata", Type = typeof(SosInsertionMetadataType), Namespace = "http://www.opengis.net/sos/2.0")] // added
change my deserialize method
public static T ValidateRequest<T>(XmlElement element) where T : class
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new XmlNodeReader(element));
}
and changed way to print values
static void executeRequest(XmlElement xmlRequest)
{
InsertSensorType insertSensorRequest = ValidateRequest<InsertSensorType>(xmlRequest);
foreach (InsertSensorTypeMetadata istm in insertSensorRequest.metadata)
{
SosInsertionMetadataType sos = (SosInsertionMetadataType)istm.InsertionMetadata;
foreach(string s in sos.featureOfInterestType)
Console.WriteLine(s);
foreach (string s in sos.observationType)
Console.WriteLine(s);
}
}
I'm using HttpClient to post xml to a rest service. The problem is the service expects namespace prefix's in fashion that I'm unable to achieve with DataContractSerializer.
Expected xml:
<gto:createRequest xmlns:gto="http://www...com/sign">
<userId></userId>
<visibleDataContentType></visibleDataContentType>
<visibleData></visibleData>
<hiddenData></hiddenData>
<expiryInSeconds></expiryInSeconds>
</gto:createRequest>
The object i'm serialzing:
namespace ABC
{
[DataContract(Name = "createRequest", Namespace = "http://www...com/sign")]
public class CreateRequest
{
[DataMember(Name = "userId")]
public string UserId { get; set; }
[DataMember(Name = "visibleDataContentType")]
public string VisibleDataContentType { get; set; }
[DataMember(Name = "visibleData")]
public string VisibleData { get; set; }
[DataMember(Name = "hiddenData")]
public string HiddenData { get; set; }
[DataMember(Name = "expiryInSeconds")]
public int ExpiryInSeconds { get; set; }
}
}
I can't get the prefix "gto: createRequest", this what DataContractSerializer outputs:
<createRequest xmlns="http://www...com/sign" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<expiryInSeconds></expiryInSeconds>
<hiddenData></hiddenData>
<userId></userId>
<visibleData></visibleData>
<visibleDataContentType></visibleDataContentType>
</createRequest>
I have tried the old XmlSerializer but with no luck. Any ideas!?
Update: The namespace prefix does not have to be gto: but i has to be there!
Update: the output from Ondrej Svejdars answer that the server doesn't accept:
<gto:createRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:gto="http://www.test.com/sign">
<gto:expiryInSeconds>60</gto:expiryInSeconds>
<gto:hiddenData>hidden</gto:hiddenData>
<gto:userId>123456</gto:userId>
<gto:visibleData>visible</gto:visibleData>
<gto:visibleDataContentType>text/plain</gto:visibleDataContentType>
</gto:createRequest>
[Edited to match the gto: only on top element]
You can tweak xml writer:
public class XmlProxyWritter : XmlTextWriter {
private string m_NS;
public XmlProxyWritter(string ns, TextWriter w)
: base(w) {
m_NS = ns;
}
public XmlProxyWritter(string ns, Stream w, Encoding encoding)
: base(w, encoding) {
m_NS = ns;
}
public XmlProxyWritter(string ns, string filename, Encoding encoding)
: base(filename, encoding) {
m_NS = ns;
}
public override string LookupPrefix(string ns) {
if (string.Compare(ns, m_NS, StringComparison.OrdinalIgnoreCase) == 0) {
return "gto";
}
return base.LookupPrefix(ns);
}
public override void WriteStartElement(string prefix, string localName, string ns) {
if (string.IsNullOrEmpty(prefix) && !string.IsNullOrEmpty(ns)) {
prefix = LookupPrefix(ns);
}
base.WriteStartElement(prefix, localName, ns);
}
}
Business class:
[XmlRoot(ElementName = "createRequest", Namespace = "http://www.test.com/sign")]
public class CreateRequest {
[XmlElement(ElementName="userId", Namespace = "")]
public string UserId { get; set; }
[XmlElement(ElementName = "visibleDataContentType", Namespace = "")]
public string VisibleDataContentType { get; set; }
[XmlElement(ElementName = "visibleData", Namespace = "")]
public string VisibleData { get; set; }
[XmlElement(ElementName = "hiddenData", Namespace = "")]
public string HiddenData { get; set; }
[XmlElement(ElementName = "expiryInSeconds", Namespace = "")]
public int ExpiryInSeconds { get; set; }
}
Call example (where http://www.test.com/sign is the namespace of CreateRequest)
string result;
var serXml = new XmlSerializer(typeof(CreateRequest));
using (var stream = new MemoryStream()) {
using (var writer = new XmlProxyWritter("http://www.test.com/sign", stream, Encoding.UTF8)) {
serXml.Serialize(writer, new CreateRequest {
ExpiryInSeconds = 1,
HiddenData = "my preasures",
UserId = "Pepa"
});
}
result = Encoding.UTF8.GetString(stream.ToArray());
}
Output:
<?xml version="1.0" encoding="utf-8"?>
<gto:createRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gto="http://www.test.com/sign">
<userId>Pepa</userId>
<hiddenData>my preasures</hiddenData>
<expiryInSeconds>1</expiryInSeconds>
</gto:createRequest>
Which works for you (I hope) but it feels like kind of hacking; maybe the proper solution here would be to "teach" server the correct xml format ? :)
is there a simple way to remove the namespace from the XML root element. I have tried with
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
on the serializable class. But no use. still getting the same result.
sample class
[Serializable]
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
public class BINDRequest
{
public BINDRequest()
{
}
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
public BINDRequestBody BIND { get; set; }
}
result xml
<?xml version="1.0" encoding="utf-8"?>
<MCP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CLIENT_REQUEST_ID="1">
<BIND CLIENT_ID="test" PASSWORD="test" />
</MCP>
i don't understand then whats the use of specifying namsespace in XmlRootAttribute??
Try this:
public class BINDRequest
{
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
}
class Program
{
static void Main()
{
var request = new BINDRequest
{
CLIENT_REQUEST_ID = "123"
};
var serializer = new XmlSerializer(request.GetType());
var xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
using (var writer = XmlWriter.Create("result.xml"))
{
serializer.Serialize(writer, request, xmlnsEmpty);
}
}
}