Issue with adding a new node in XML - c#

I am trying to add a new node in my XML file, but I get InvalidOperationException due to the current position of the navigator.
This is my XML file:
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns="RecnikSema.xsd">
<sentiments>
<sentiment word="napustiti">-2</sentiment>
</sentiments>
</dictionary>
and schema:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="dictionary">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiments">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiment">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="word"/>
<xs:attribute type="xs:double" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The code in C# which I am using to add a new node looks like this:
XmlDocument dictionary= new XmlDocument();
dictionary.Load(#"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\Dictionary.xml");
XPathNavigator navigator = dictionary.CreateNavigator();
navigator.MoveToChild("dictionary", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.MoveToChild("sentiments", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.MoveToChild("sentiment", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.InsertAfter("<sentiment word=\"" + token + "\">" + value + "</sentiment>");
The exception is occuring on the last line, on InsertAfter.
What am I doing wrong here?

Why don't you make it simple mate by using XDocument.
The new version of C# has got this class that makes it easy to manipulate Xml. Thus, it also supports Xml Linq as well.
Here is the quick solution that may be useful for you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
XDocument document = XDocument.Load(#"C:\Users\amit\SkyDrive\code\WebApplication1\ConsoleApplication1\xml.xml");
XElement root = new XElement("sentiment");
root.Value = "3";
root.Add(new XAttribute("word", "napustiti"));
XNamespace nsSys = "RecnikSema.xsd";
document.Element(nsSys + "dictionary").Element(nsSys + "sentiments").Add(root);
document.Save("c:\newFile.xml");
}
}
}

I think your problem is that you did not specify the maxOccurs (default is 1) and you allready added on element. See http://www.w3schools.com/schema/el_sequence.asp
maxOccurs Optional. Specifies the maximum number of times the sequence
element can occur in the parent element. The value can be any number>=
0, or if you want to set no limit on the maximum number, use the value
"unbounded". Default value is 1
so your Solution for multiple sentiments:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="dictionary">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiments">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="sentiment">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="word"/>
<xs:attribute type="xs:double" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I would prefer using Microsoft xsd tool to generate a CLR Class -> http://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx and using XMLSerializer -> http://msdn.microsoft.com/de-de/library/system.xml.serialization.xmlserializer(v=vs.110).aspx

In MoveToChild(), the second argument is the XML namespace, not the location of your document. In your case, you have set xmlns="RecnikSema.xsd". This means MoveToChild cannot find a match, so when you get to insertAfter, the current node is still the root node <dictionary>, and it attempts to create XML like this:
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns="RecnikSema.xsd">
<sentiment word="napustiti">-2</sentiment>
</dictionary>
<sentiment word="foo">5</sentiment>
This has 2 root elements and so you get the error
Instead you need to pass "RecnikSema.xsd" as the argument.:
navigator.MoveToChild("dictionary", "RecnikSema.xsd");
navigator.MoveToChild("sentiments", "RecnikSema.xsd");
navigator.MoveToChild("sentiment", "RecnikSema.xsd");
I'm not sure you meant to set this as the namespace as it is the Schema file, so maybe you mean this?:
XML
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="RecnikSema.xsd">
<sentiments>
<sentiment word="napustiti">-2</sentiment>
</sentiments>
</dictionary>
C#
XmlDocument dictionary= new XmlDocument();
dictionary.Load(#"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\Dictionary.xml");
XPathNavigator navigator = dictionary.CreateNavigator();
navigator.MoveToChild("dictionary", "");
navigator.MoveToChild("sentiments", "");
navigator.MoveToChild("sentiment", "");
navigator.InsertAfter("<sentiment word=\"" + token + "\">" + value + "</sentiment>");

Related

How to add the xmlElement from one xsd file within the xmlElement of another xsd file using XmlSampleGenerator?

I'm using XmlSampleGenerator to generate the xml file from xsd. I'm able to generate the xml file from single xsd file directly using bellow code.
using (var stream = new MemoryStream(File.ReadAllBytes("platform-container.xsd")))
{
var schema = XmlSchema.Read(XmlReader.Create(stream), null);
var gen = new XmlSampleGenerator(schema, new XmlQualifiedName("Document"));
gen.WriteXml(XmlWriter.Create(#"C:\SCIP\SCIP-Phase-1\SCIPAppPrj\XmlFiles\dossier.i6d"));
Console.WriteLine("Autogenerated file is here : C:\\SCIP\\SCIP-Phase-1\\SCIPAppPrj\\XmlFiles\\dossier.i6d");
}
But I'm facing the issue when I have to combine the elements from multiple xsd files and generate one single xml file.
For example my generated xml should look like below:
<?xml version="1.0" encoding="UTF-8"?>
<i6c:Document xmlns:i6c="http://iuclid6.echa.europa.eu/namespaces/platform-container/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://iuclid6.echa.europa.eu/namespaces/platform-container/v1 container.xsd">
<i6c:PlatformMetadata xmlns:i6m="http://iuclid6.echa.europa.eu/namespaces/platform-metadata/v1" xsi:schemaLocation="http://iuclid6.echa.europa.eu/namespaces/platform-container/v1 container.xsd">
<i6m:iuclidVersion>1.0</i6m:iuclidVersion>
<i6m:documentKey>ABC</i6m:documentKey>
<i6m:documentType>DOSSIER</i6m:documentType>
</i6c:PlatformMetadata>
<i6c:Content>
<DOSSIER.SCIP xmlns="http://iuclid6.echa.europa.eu/namespaces/DOSSIER-SCIP/1.0" xmlns:i6="http://iuclid6.echa.europa.eu/namespaces/platform-fields/v1" />
</i6c:Content>
</i6c:Document>
I have main xsd called container.xsd, which has skeleton for my xml file. Also metaData.xsd and content.xsd which contains elements that should be included as a child under one of the element present in container.xsd.
container.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://iuclid6.echa.europa.eu/namespaces/platform-container/v1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://iuclid6.echa.europa.eu/namespaces/platform-container/v1"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:element name="Document">
<xs:complexType>
<xs:sequence>
<xs:element name="PlatformMetadata">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:any namespace="##other" processContents="lax" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Content">
<xs:complexType>
<xs:sequence>
<xs:any namespace="##other" processContents="strict" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
metaData.xsd
<xs:schema xmlns="http://iuclid6.echa.europa.eu/namespaces/platform-metadata/v1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://iuclid6.echa.europa.eu/namespaces/platform-metadata/v1"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:element name="iuclidVersion" type="xs:string">
</xs:element>
<xs:element name="documentKey" type="xs:string">
</xs:element>
<xs:element name="documentType" type="xs:string">
</xs:element>
</xs:schema>
content.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://iuclid6.echa.europa.eu/namespaces/DOSSIER-SCIP/1.0" xmlns:ct="http://iuclid6.echa.europa.eu/namespaces/scip/v1" xmlns:i6="http://iuclid6.echa.europa.eu/namespaces/platform-fields/v1" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://iuclid6.echa.europa.eu/namespaces/DOSSIER-SCIP/1.0">
<xs:import namespace="http://iuclid6.echa.europa.eu/namespaces/platform-fields/v1" schemaLocation="platform-fields.xsd"/>
<xs:import namespace="http://iuclid6.echa.europa.eu/namespaces/scip/v1" schemaLocation="commonTypesScipV1.xsd"/>
<xs:element name="DOSSIER.SCIP">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="remarks" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Can anyone suggest me how to handle this using XmlSampleGenerator? How to read the elements from multiple xsd's and genrate single xml file ? How to append the data for each element ?

How to generate .NET 4.0 classes from xsd with more than 1 element to class?

I'm following the solution from this question How to generate .NET 4.0 classes from xsd? to generate C# classes. But somehow it only generates the first element. Is there any way that I can generate all elements at same time?
Xsd doc looks like below:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="advice_file">
</xs:element>
<xs:element name="vendorMerchID" type="xs:string">
</xs:element>
</xs:schema>
The reason you only get 1 element is because to be valid the xml must always have a single outer root node. What is suprising to me is that the second node was just ignored completely and no exception was thrown.
Your xsd represents the following xml
<advice_file/>
To have both elements, you need to write you xsd as follows:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="myRoot">
<xs:complexType>
<xs:sequence>
<xs:element name="advice_file" type="xs:string"/>
<xs:element name="vendorMerchID" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
for the xml structure as:
<myRoot>
<advice_file/>
<vendorMerchID/>
</myRoot>
Alternatively, if your xml is like this:
<advice_file>
<vendorMerchID/>
</advice_file>
Use the xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="advice_file">
<xs:complexType>
<xs:sequence>
<xs:element name="vendorMerchID" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Upload XSD elements in a List

I am Working on Visual-studio 2012 in C#.
I have a xsd file abc.xsd as mentioned below.
I want to add its element names(Class and Place here) in a List.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DocumentElement" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="DocumentElement" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="PositionMaster">
<xs:complexType>
<xs:all>
<xs:element name="Class" type="xs:string" minOccurs="0" />
<xs:element name="Place" type="xs:string" minOccurs="0" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
Code written is below
List listData = new List();
XmlDocument xslDoc = new XmlDocument();
xslDoc.Load(abc.xsd);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xslDoc.NameTable);
nsMgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
What should i write further so that my list contains these xsd elements? These elements may vary in number.
Try this...
using System.Xml.Linq;
XDocument xDoc = XDocument.Load(#"C:\abc.xsd");
var t = xDoc.Descendants().Elements().Attributes().Where(x => x.Name == "name");
You can add more to the where condition to filter out the results as you need

XML DATASET to be Validated

Hello all i have a scenario where i have
TWO XML FILES
one xml say "Books.xml" will create the schema for DATASET and i will use other XML file to load data into DATASET and all data in 2nd file will be inserted into DATASET
I have done these things but i m stuck at validating XML i want to validate 2nd xml file
means data entered into dataset should be exactly valid according to DATASET schema which will be according to First XML
i have tried it using XSD but i am not sure if XSD will be able to validate TYPE of data say if i have to input number and i have a string in my xml ,it should throw an exception
i have my xml like this
<DATA>
<HISTORY>
<book1>SOmebook</book1>
</HISTORY>
<POETRY>
<book2>Books</book2>
</POETRY>
</DATA>
and i am generating my XSD Using VisualStudio
to validate it im using a method something like this
XmlReaderSettings settings = //dont know exact settings
string data = null;
XmlReader Reader = XmlReader.Create(File.Open("C:\books.XML", FileMode.Open), settings, data);
DataSet ds = new DataSet();
ds.ReadXml(Reader);
Here's a quick example on how you can use a schema to validate. I'm using the shiporder example from W3Schools.
Schema:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<shiporder orderid="889923">
<orderperson>John Smith</orderperson>
<shipto>
<name>Ola Nordmann</name>
<address>Langgt 23</address>
<city>4000 Stavanger</city>
<country>Norway</country>
</shipto>
<item>
<title>Empire Burlesque</title>
<note>Special Edition</note>
<quantity>1</quantity>
<price>10.90</price>
</item>
<item>
<title>Hide your heart</title>
<quantity>1</quantity> <!--Change to "one" to see validation error-->
<price>9.90</price>
</item>
</shiporder>
And here's the validation using Linq2XML:
XDocument document = XDocument.Load("shiporder.xml");
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", XmlReader.Create("schema.xsd"));
bool errors = false;
document.Validate(schemas, (o, e) =>
{
Console.WriteLine("Validation error: {0}", e.Message);
errors = true;
});
if (!errors)
{
Console.WriteLine("XML document successfully validated.");
}
else
{
Console.WriteLine("XML document does not validate.");
}
Change the value of of the <quantity> node as mentioned in the comment in order to see how the XML does not validate because of invalid type.

Extracting specific nodes from an XML file

I want to read a section from the XML file below with C#.
<?xml version="1.0" encoding="utf-8" >
<DataSet>
<xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Table">
<xs:complexType>
<xs:sequence>
<xs:element name="Column1" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<NewDataSet>
<Table diffgr:id="Table1" msdata:rowOrder="0">
<Column1><Properties><Property>.....
I want to extract the nodes below the Column1 nodes. The Properties node has lots of Property nodes, so I want the Properties node with all the Property nodes.
Please let me know the easiest and efficient way to get the nodes in C#.
You can use an Linq-to-XML classes to parse the string and then XPath expression to select the nodes that you want:
XElement doc = XElement.Parse(s); //where s is a string containing the XML
var properties = doc.XPathSelectElements("//Column1/Properties");
Now properties contains a enumerable of the nodes that you want.
If you want to iterate through all the Property nodes you can do so like this:
foreach(var pp in properties)
{
foreach(var p in pp.Elements("Property"))
{
//do something
}
}

Categories

Resources