I have classes full of xpaths that now needs a specfic namespace. How can I accomplish this? What would be the easiest way to refactor this code? find replace?
What would be the best way to grab specific nodes in the future, if I don't know the namespaces ahead of time?
susr1 = root.SelectSingleNode("/PurchaseOrderRequest/DocumentHeader/DocumentInformation/DocumentIdentification/Type");
susr1 = root.SelectSingleNode("/PurchaseOrderRequest/ssdh:DocumentHeader/ssdh:DocumentInformation/ssdh:DocumentIdentification/ssdh:Type");
You can try this XML Library. Use XPathElement(). This is a .Net 3.5 solution if you can use it.
XElement root = XElement.Load(file) or .Parse(string)
Then either of your xpath's should work as long as there are not conflicting nodes with the same name (but different namespaces).
XElement susr1 = root.XPathElement("/PurchaseOrderRequest/DocumentHeader/DocumentInformation/DocumentIdentification/Type");
XElement susr1 = root.XPathElement("/PurchaseOrderRequest/ssdh:DocumentHeader/ssdh:DocumentInformation/ssdh:DocumentIdentification/ssdh:Type");
The library should figure out the namespace for you. I cannot test it without example xml to be sure.
Related
I have already deserialized a json-file to c#-objects. This has been done by the following:
JsonSerializer<FooClass>().DeserializeFromString(json)
and it all works well. I now want to change the json to xml and do the exact same, keeping all the classes and setup, that has already been made inside the solution.
The conversion from json to xml is easy, but I cant figure out how to deserialize the xml so that I dont need to change a lot of code.
Is it possible to keep the whole setup, but somehow change few lines of code such as
JsonSerializer<FooClass>().DeserializeFromString(json)
to something alike, but that deserializes the xml instead?
I've found the following solutions in here, but they don't seem to solve the problem:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
but the SerializeXmlNode isn't possible?
The other solutions I have found in here use arguments and stuff like that, which again will force me to change some of the setup, which I am not interested in, if possible.
Also I am aware, that a direct transformation from json to xml has its cons, but if we look aside from that and focus on the xml part, then it would be nice.
This because we are writing in xml instead of json from now on and therefore the change needed.
One easy route I can see is to leverage the XmlClass Attributes and use XmlSerializer.
In order to manipulate the dlls thats used inside of my VS project I have to update the reference that the dll is pointed to. I do this via modifying the XML of the csproh (yes this works).
However, this time around I want to add the a SpecificVersion reference so <SpecificVersion xmlns="">False</SpecificVersion> however you cannot build using microsoft build engine when you have a custom xml namespace beneath the Reference element. How do you remove the xmlns="" inside of the SpecificVersion node?
<SpecificVersion xmlns="">False</SpecificVersion>
XmlElement SpecificVersionElement = refNode.OwnerDocument.CreateElement("SpecificVersion");
SpecificVersionElement.InnerText = "False";
refNode.AppendChild(SpecificVersionElement);
Remarkable, like usual 30 seconds after I post something I figure it out. And in this case it makes no sense. By specifying a namespace, the createelement effectively removes the namespace.
XmlElement SpecificVersionElement = refNode.OwnerDocument.CreateElement("SpecificVersion","http://schemas.microsoft.com/developer/msbuild/2003");
SpecificVersionElement.InnerText = "False";
refNode.AppendChild(SpecificVersionElement);
Of course this is probably hidden somewhere deep in a MSDN article
I use C# code more-or-less like this to serialize an object to XML:
XmlSerializer xs1 = new XmlSerializer(typeof(YourClassName));
StreamWriter sw1 = new StreamWriter(#"c:\DeserializeYourObject.xml");
xs1.Serialize(sw1, objYourObjectFromYourClassName);
sw1.Close();
I want it to serialize like this:
<ns0:Header xmlns:ns0="https://mynamespace/">
<SchemaVersion>1.09</SchemaVersion>
<DateTime>2009-12-15T00:00:01-08:00</DateTime>
but instead, it is doing this:
<Header xmlns="https://mynamespace/">
<SchemaVersion xmlns="">V109</SchemaVersion>
<DateTime xmlns="">2010-03-08T18:21:09.100125-08:00</DateTime>
The way it is serializing doesn't work with the XPath I had planned to use, and doesn't match my BizTalk schema. Originally I built the class using XSD.exe from a BizTalk 2006 schema, then I use it for an argument to a WCF web service.
This might be related to an option called element FormDefault = Qualified or Unqualified. In BizTalk, my I have the schema set to "Unqualfiied" which is what I want.
Is there any way for the serializer to output "unqualified" results?
Thanks,
Neal Walters
Update:
Sample attribute on DateTime:
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public System.DateTime DateTime
{
get
{
return this.dateTimeField;
}
set
{
this.dateTimeField = value;
}
}
BizTalk provides for what it calls promoted (or distinguished) fields, which use XPath to pull out values of individual elements. I checked the XPath of BizTalk in a tool called StylusStudio, and Biztalk'x xpath didn't work with the xmlns='' fields above.
The first thing my WCF web service does is to serialize the object to a string (using UTF16 encoding) and store it in an XML column in a SQL database. It is from there I am seeing the above xml sample with the xmlns="".
XPath:
/*[local-name()='Header' and namespace-uri()='https://mynamespace/']/*[local-name()='DateTime' and namespace-uri()='']
The XPATH you're using does not match the namespaces of your XML. Your Header element, for instance, in in the https://mynamespace/, but your XPATH is searching in the http://mynamespace/ namespace.
My question was a bit muddled, so this answer may or may not help someone.
This is a fairly complex scenario, and half of my issues came from trying to simplify it to make an easy post here.
I was actually adding a new element programmatically with a C# routine (see "NewElement" below). The C# code did not set its namespace to an empty string, therefore I believe it is inheriting the namespace of the "Header" element.
I freaked out a little because I was jumping to the conclusion that DateTime should not have the "xmlns=""' when in fact it should. Even though DateTime falls under Header, it does not nor should not inherit the Header's namespace.
In BizTalk, typically only complex types have their own namespace, and DateTime as well as NewElement are simple types.
<Header xmlns="https://mynamespace/">
<SchemaVersion xmlns="">V109</SchemaVersion>
<DateTime xmlns="">2010-03-08T18:21:09.100125-08:00</DateTime>
<NewElement>myvalue</NewElement>
So in effect, the two XML's I posted originally are identical as far as XPath goes. If I insert a new element, I need to make sure it follows the same pattern.
I had written the C# routine to add the element more than a year ago, and it worked fine then, so I wasn't suspect that it was causing this problem.
If I am dealing with several standard xml formats what would be the best practice way of encapsulating them in C# 3.5? I'd like to end up with something similar to the System.ServiceModel.Syndication namespace.
A class that encapsulates the ADF 1.0 XML standard would be one example. It has the main XML root node, 6 child elements, 4 of which are required IIRC, several required and optional elements and attributes further down the tree. I'd like the class to create, at a minimum, the XML for all the required pieces all the way up to a full XML representation. (Make sense).
With LINQ 4 XML and extension classes, etc, etc, there has to be some ideas on quickly generating a class structure for use. Yes? No? :)
Am not sure if I gave enough details to get one correct answer but am willing to entertain ideas right now.
TIA
XML serialization seems a good approach. You could even use xsd.exe to generate the classes automatically...
EDIT
Note that the class names generated by the tool are usually not very convenient, so you might want to rename them. You might also want to change arrays of T to List<T>, so that you can easily add items where needed.
Assuming the class for the root element is named ADF, you can load an ADF document as follows :
ADF adf = null;
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlReader reader = XmlReader.Create(fileName))
{
adf = (ADF)xs.Deserialize(reader);
}
And to save it :
ADF adf = ...; // create or modify your document
...
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlWriter writer = XmlWriter.Create(fileName))
{
xs.Serialize(writer, adf);
}
Why not just follow the pattern of the SyndicationFeed object in the Syndication namespace? Create a class that takes in a Uri to the xml document or just takes in the document fragment.
Then parse the document based on your standards (this parsing can be done using LinqToXml if you wanted to, though regEx might be faster if you are comfortable with them). Throw exceptions or track errors appropriately when the document doesn't pass the specification rules.
If the document passes the parse step then break the pieces of the document out into public getter properties of your object. Then return the fully hydrated object back to the consumer for use
Seems pretty straight forward to me. Is that what you are after or are you looking for something more than this?
I know, where is XmlSchema class in dot net, but it does not allow to load file into it. Is there a clean solution to load xsd file and travel between elements?
You need to use XmlSchemaSet, e.g.:
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(targetNamespace, schemaUri);
schemaSet.Compile();
foreach(XmlSchemaElement element in schemaSet.GlobalElements.Values)
{
// do stuff...
}
EDIT: Sorry for not being clearer.
Where the comment says // do stuff..., what you need to do is traverse the inherited types of each element, which are available under XmlSchemaElement.SchemaType, and the inline type of the element, which is available under XmlSchemaElement.ElementSchemaType.
The MSDN does contain all the the information you're after, but it is somewhat maze-like and requires digging around plus a bit of trial-and-error to work it out.
As per my comment, the following class from one of my open-source side-projects may be of use to you here:
http://bitbucket.org/philbooth/schemabrute/src/tip/LibSchemaBrute/Navigator.cs
I suggest checking out this tool: http://www.altova.com/xmlspy.html. You can create a data model from any XSD file. I've used it in many XML projects.