I try to dynamically create an XML schema (XSD) from C#, using the conventional XElement and XAttribute classes, but it is not valid to specify any names with colons. That is, I cannot create the element <xs:element> using the code
... = new XElement("xs:element");
because ":" is not allowed.
What is the correct way of dynamically building a schema in C# then?
To create schemas, you should be using the XmlSchema class. The link below provides a comprehensive example of creating one programmatically:
http://msdn.microsoft.com/en-us/library/9ta3w88s.aspx
Example:
static void Main(string[] args)
{
var schema = new XmlSchema();
// <xs:element name="myElement" type="xs:string"/>
var myElement = new XmlSchemaElement();
schema.Items.Add(myElement);
elementCat.Name = "myElement";
elementCat.SchemaTypeName =
new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");
// writing it out to any stream
var nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");
schema.Write(Console.Out, nsmgr);
Console.ReadLine();
}
When creating new XML elements, you should be aware that the part before the colon (in this case, xs) is actually an alias for the XML namespace (in the case of an XSD, xs usually refers to http://www.w3.org/2001/XMLSchema). So, to continue using XDocument to build your XSD, you would want to use:
XNamespace ns = new XNamespace("http://www.w3.org/2001/XMLSchema");
... = new XElement(ns + "element");
See the example here:
http://msdn.microsoft.com/en-us/library/bb292758.aspx
I wrote a blog about that very subject. You can use a DataTable to save a schema.
If you want to create xml, you should use XmlWriter class
Related
I have an XML file which looks like this
<SendInvoiceResult xmlns="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsSucceded="true">
<Value Id="123456" Number="1" InvoiceScenario="Scenario" />
</SendInvoiceResult>
I'm trying to read the attributes of this file but so far all my tries based on other questions on Stackoverflow either returned null or "Object reference not set to an instance of an object" error.
My latest try is this:
var testXml = new XmlDocument();
testXml.LoadXml(test);
var node = testXml.SelectSingleNode("/SendInvoiceResult/Value");
var id = node.Attributes["Id"].Value;
This approach returns "Object reference not set to an instance of an object" too. I'm wondering if something is wrong with the way XML is structures at this point.
I'm open to new methods and suggestions of course, all I need is to read the values of attributes in this and other similar XML files.
Use XDocument. It is much more modern and capable.
var doc = XElement.Load(test);
var id = doc.Root.Element("Value").Attribute("Id").Value;
You must define xml namespace.
var doc = new XmlDocument();
doc.Load("test.txt");
var manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("ns", "http://tempuri.org/");
var node = doc.SelectSingleNode("/ns:SendInvoiceResult/ns:Value", manager);
var id = node.Attributes["Id"].Value;
Console.WriteLine(id);
Better use modern and more convenient linq to xml.
using System.Xml.Linq;
var doc = XDocument.Load("test.txt");
XNamespace ns = "http://tempuri.org/";
var id = doc.Root.Element(ns + "Value").Attribute("Id").Value;
Console.WriteLine(id);
i have a LINQ query like this, i need to remove the XML Declaration tag which is getting added automatically.
var cubbingmessagexml = new XDocument(
new XElement("MESSAGE", new XAttribute("ID", "CUB"),
new XElement("RECORD", new XAttribute("STORENO", cubing.StoreID),
new XAttribute("TPNB", cubing.ProductCode),
new XAttribute("QUANTITY", cubing.Quantity),
new XAttribute("CUBINGTIME", cubing.CubingDateTime.ToString("yyyyMMddHHmmss")),
new XAttribute("SHELFFACING", cubing.ShelfFacing)
)));
xml = cubbingmessagexml.ToString();
pls help
I dont want to save the XML file, just need to return the XML as a string
If you are referring the xml version and stuff at the top, there is an xml writer setting to turn that off.
var writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
using (var buffer = new StringWriter())
using (var writer = XmlWriter.Create(buffer, writerSettings))
{
cubbingmessagexml.Save(writer);
writer.Flush();
string result = buffer.ToString();
}
Skip the XDocument:
var cubbingmessagexml =
new XElement("MESSAGE", new XAttribute("ID", "CUB"),
new XElement("RECORD",
new XAttribute("STORENO", cubing.StoreID),
new XAttribute("TPNB", cubing.ProductCode),
new XAttribute("QUANTITY", cubing.Quantity),
new XAttribute("CUBINGTIME", cubing.CubingDateTime.ToString("yyyyMMddHHmmss")),
new XAttribute("SHELFFACING", cubing.ShelfFacing)
)
);
xml = cubbingmessagexml.ToString();
From MSDN:
Note that you only have to create XDocument objects if you require the specific functionality provided by the XDocument class. In many circumstances, you can work directly with XElement. Working directly with XElement is a simpler programming model.
and
As previously mentioned, the XElement class is the main class in the LINQ to XML programming interface. In many cases, your application will not require that you create a document. By using the XElement class, you can create an XML tree, add other XML trees to it, modify the XML tree, and save it.
Even with XDocument the declaration is not displayed.
I'm trying to load a node (in string format) into a XElement.
Although this should be easy enough i'm finding some problems:
The node I'm trying to load contains namespace references in some sub-nodes
When I try to use XElement.Load() or Xelement.Parse() I get the expected not defined namespace error
I know the solution is to create a surrounding node with the namespace definitions and then load the whole thing, but I was wondering if there is a more elegant solution that doesn't involve string operations.
Here's my failed attempt :(
I have a collection of namespace attributes:
private readonly List<XAttribute> _namespaces;
This is already populated and contains all the necesary namespaces.
So, to embed my XML string into another node I was doing this:
var temp = new XElement("root", (from ns in _namespaces select ns), MyXMLString);
But as I expected as well, the content of MyXMLString gets escaped and becomes a text node.
The result I get is something like:
<root xmlns:mynamespace="http://mynamespace.com"><mynamespace:node>node text</node></root>
And the result I'm looking for is:
<root xmlns:mynamespace="http://mynamespace.com">
<mynamespace:node>node text</node>
</root>
Is there a neat way to do this?
Thanks in advance
Presumably your XML text is actually well formed (note the namespace qualifier on the closing tag):
var xml = "<mynamespace:node>node text</mynamespace:node>";
In which case you can use this to manually specify the namespaces:
var mngr = new XmlNamespaceManager( new NameTable() );
mngr.AddNamespace( "mynamespace", "urn:ignore" ); // or proper URL
var parserContext = new XmlParserContext(null, mngr, null, XmlSpace.None, null);
Now read and load:
var txtReader = new XmlTextReader( xml, XmlNodeType.Element, parserContext );
var ele = XElement.Load( txtReader );
Works as expected. And you don't need a wrapper 'root' node. Now this can be inserted into any as an XElement anywhere.
I want to make xml element like this:
<ElementName Type="FirstAttribute" Name="SecondAttribute">Value</Atrybut>
Now I'm doing this in this way:
XmlNode xmlAtrybutNode = xmlDoc.CreateElement("ElementName ");
_xmlAttr = xmlDoc.CreateAttribute("Type");
_xmlAttr.Value = "FirstAttribute";
xmlAtrybutNode.Attributes.Append(_xmlAttr);
_xmlAttr = xmlDoc.CreateAttribute("Name");
_xmlAttr.Value = "SecondAttribute";
xmlAtrybutNode.Attributes.Append(_xmlAttr);
xmlAtrybutNode.InnerText = !string.IsNullOrEmpty(Value)
? SetTextLength(Name, ValueLength)
: string.Empty;
Value is input variable in method.
Is there possibility to make this in another way?
More efficiently?
Can I use xmlWriter? Now i'm using xmlDocument.
You can use Linq to XML.
Basically
XDocument doc = new XDocument();
doc.Add(
new XElement("ElementName", "Value",
new XAttribute("Type", "FirstAttribute"),
new XAttribute("Name", "SecondAttribute")));
will give this xml document
<ElementName Type="FirstAttribute" Name="SecondAttribute">Value</ElementName>
How about tweaking your existing code:
XmlElement el = xmlDoc.CreateElement("ElementName");
el.SetAttribute("Type", "FirstAttribute");
el.SetAttribute("Name", "SecondAttribute");
el.InnerText = ...;
Additional thoughts:
XElement
XmlSerializer (from a class instance)
If you’re on .NET 3.5 (or later), you could use LINQ to XML. Make sure that the System.Xml.Linq assembly is referenced, and that you have a using directive for its eponymous namespace.
XDocument document = new XDocument(
new XElement("ElementName",
new XAttribute("Type", "FirstAttribute"),
new XAttribute("Name", "SecondAttribute"),
value));
If you subsequently want to write the XDocument to a target, you can use its Save method. For debugging, it’s useful to call its ToString method, which returns its XML representation as a string.
Edit: Replying to comment:
If you need to convert the XDocument created above into an XmlDocument instance, you may use code similar to the following:
XmlDocument xmlDocument = new XmlDocument();
using (XmlReader xmlReader = document.CreateReader())
xmlDocument.Load(xmlReader);
What about using LINQ to XML as in this article. That can be very elegant - it can all be done on one line.
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("element",
new XAttribute("attribute1", "val1"),
new XAttribute("attribute2", "val2"),
)
);
I have an existing XDocument object that I would like to add an XML doctype to. For example:
XDocument doc = XDocument.Parse("<a>test</a>");
I can create an XDocumentType using:
XDocumentType doctype = new XDocumentType("a", "-//TEST//", "test.dtd", "");
But how do I apply that to the existing XDocument?
You can add an XDocumentType to an existing XDocument, but it must be the first element added. The documentation surrounding this is vague.
Thanks to Jeroen for pointing out the convenient approach of using AddFirst in the comments. This approach allows you to write the following code, which shows how to add the XDocumentType after the XDocument already has elements:
var doc = XDocument.Parse("<a>test</a>");
var doctype = new XDocumentType("a", "-//TEST//", "test.dtd", "");
doc.AddFirst(doctype);
Alternately, you could use the Add method to add an XDocumentType to an existing XDocument, but the caveat is that no other element should exist since it has to be first.
XDocument xDocument = new XDocument();
XDocumentType documentType = new XDocumentType("Books", null, "Books.dtd", null);
xDocument.Add(documentType);
On the other hand, the following is invalid and would result in an InvalidOperationException: "This operation would create an incorrectly structured document."
xDocument.Add(new XElement("Books"));
xDocument.Add(documentType); // invalid, element added before doctype
Just pass it to the XDocument constructor (full example):
XDocument doc = new XDocument(
new XDocumentType("a", "-//TEST//", "test.dtd", ""),
new XElement("a", "test")
);
or use XDocument.Add (the XDocumentType has to be added before the root element):
XDocument doc = new XDocument();
doc.Add(new XDocumentType("a", "-//TEST//", "test.dtd", ""));
doc.Add(XElement.Parse("<a>test</a>"));