Load XML file add Values and Save - c#

I have an XML file that we are using systemlink for in AS400. I have the working XML file and if I just do a load document on the button click it writes to the database the hard coded values. However, I would like to patch values from textboxes in. Here is my XML:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE System-Link SYSTEM 'SystemLinkRequest.dtd'>
<System-Link>
<Login userId='' password='' maxIdle='900000'
properties='com.pjx.cas.domain.EnvironmentId=RN,
com.pjx.cas.domain.SystemName=,
com.pjx.cas.user.LanguageId=en'/>
<Request sessionHandle='*current' workHandle='*new'
broker='EJB' maxIdle='1000'>
<Create name='newObject_ITItemLocation_Default' domainClass='EXT0149' retainResult='false'>
<ApplyTemplate clientClass='EXT0149'>
<![CDATA[Asset]]>
</ApplyTemplate>
<DomainEntity>
<Property path='ponum'>
<Value><![CDATA[P21851]]></Value>
</Property>
<Property path='itmnbr'>
<Value><![CDATA[909520]]></Value>
</Property>
<Property path='itmcls'>
<Value><![CDATA[1]]></Value>
</Property>
<Property path='itmloc'>
<Value><![CDATA[1]]></Value>
</Property>
<Property path='srnum'>
<Value><![CDATA[]]></Value>
</Property>
</DomainEntity>
</Create>
And here is my C#:
enterXmlDocument document = new XmlDocument();
document.Load(Server.MapPath("~/addNew.xml"));
XmlElement po = document.GetElementById("ponum");
po.Value = poTextBox.Text;
document.Save(Server.MapPath("~/addNew.xml"));
Every time I try and run it I get an object not found so I'm guessing it can't find the ponum field. I'd like to patch the poTextBox.Text in where it is currently P21851. Any suggestions like I said if I just do the document.Load on button click it writes to the DB just fine, I just want to patch my values in.

Why dont you use serialization for converting the xml into an object so you can do what ever you want? Do you have the xsd?

Decided to take a different approach and just put it into a string and did an HttpWebRequest so that I could just patch in my values into my string. Thanks for the answers one day I'll mess with how to make that work in an XML document.
string asset = "<?xml version='1.0' encoding='UTF-8'?>" + "<!DOCTYPE System-Link SYSTEM 'SystemLinkRequest.dtd'>" + "<System-Link>" + "<Login userId='' password='' maxIdle='900000' properties='com.pjx.cas.domain.EnvironmentId=RN, com.pjx.cas.domain.SystemName=,com.pjx.cas.user.LanguageId=en'/>" + "<Request sessionHandle='*current' workHandle='*new' broker='EJB' maxIdle='1000'>" + "<Create name='newObject_ITItemLocation_Default' domainClass='EXT0149' retainResult='false'>" + "<ApplyTemplate clientClass='EXT0149'>" + "<![CDATA[Asset]]>" + "</ApplyTemplate>" + "<DomainEntity>" + "<Property path='ponum'><Value><![CDATA[" + poTextBox.Text + "]]></Value></Property>" + "<Property path='itmnbr'><Value><![CDATA[" + itemNoTextBox.Text + "]]></Value></Property>" + "<Property path='itmcls'><Value><![CDATA[" + classDropDown.SelectedValue +"]]></Value></Property>" + "<Property path='itmloc'><Value><![CDATA[" + locationDropDown.SelectedValue + "]]></Value></Property>" + "<Property path='srnum'><Value><![CDATA["+ serialTextBox.Text +"]]></Value></Property>" + "</DomainEntity>" + "</Create>" + "</Request>" + "</System-Link>";
String wRequestString = "SystemLinkRequest=" + HttpUtility.UrlEncode(asset);

Related

getting the attribute values of XML node

i am trying to get the values of the Arg1,2 and 3 attributes of the below XML...in the XML, there are 2 different values and the iteration through the code has been verified to iterate twice. but the same answer is displayed twice and i don't know what is missing...!!!
this is the XML:
-<event type="2VO">
-<properties>
<schedule endOffset="00:00:22:00" endType="Duration" startOffset="00:00:33:00" startType="-ParentEnd"/>
<event title="Pixel VO" reconcileKey="106251137"/>
+<mediaStream>
<media Arg8="" Arg7="" Arg6="" Arg5="" Arg4="" Arg3="O1T13810" Arg2="1910" Arg1="TON" RuleCode="2VO"/>
</properties>
</event>
-<event type="2VO">
-<properties>
<schedule endOffset="00:00:22:00" endType="Duration" startOffset="00:00:33:00" startType="-ParentEnd"/>
<event title="Pixel VO" reconcileKey="106251137"/>
+<mediaStream>
<media Arg8="" Arg7="" Arg6="" Arg5="" Arg4="" Arg3="O1T13810" Arg2="1932" Arg1="TUE" RuleCode="2VO"/>
</properties>
</event>
and the code is below here:
static void Main(string[] args)
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(#"C:\Users\namokhtar\Desktop\testxml.xml");
foreach (XmlNode node in xdoc.SelectNodes("//event[#type='2VO']")) //or /CATALOG/CD
{
var x = node.SelectSingleNode("//#Arg1").Value;
var y = node.SelectSingleNode("//#Arg2").Value;
var z = node.SelectSingleNode("//#Arg3").Value;
Console.WriteLine("The first parameter is: " + x);
Console.WriteLine("The first parameter is: " + y);
Console.WriteLine("The first parameter is: " + z);
Console.ReadKey();
}
The problem is that the "//" in "//#Arg1" is telling it to look anywhere in the document not specifically the node you have selected so even thought you extract each <event> node, you then always get the first "//#Arg1" attribute value in the document.
Either use ".//#Arg1" to tell it to search relative to the current node or be more specific with your XPath and use "./properties/media/#Arg1"
If it's any consolation, I don't find this "//" behaviour intuitive!

NullReferenceException unhandled by user code while changing XML document

I am getting the error : NullReferenceException was unhandled by user code , object reference not set to an instance of an object. While I want to change the element of an xml file. this is the code the error is generated on :
doc2.SelectSingleNode("/Document/CstmrCdtTrfInitn/GrpHdr/MsgId", nsmgr).InnerText = bank.Afkorting + "-0001";
This is the previous code :
XmlDocument doc2 = new XmlDocument();
doc2.Load(#"C:\Users\Kevin\Desktop\xsd\betalingen_sepa.xml");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc2.NameTable);
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
DagboekFinancieel bank = os.FindObject<DagboekFinancieel>(CriteriaOperator.Parse("[Omschrijving] = ?", opdracht.Bank));
doc2.SelectSingleNode("/Document/CstmrCdtTrfInitn/GrpHdr/MsgId", nsmgr).InnerText = bank.Afkorting + "-0001";
string naamFile = bank.Afkorting + "-0001";
doc2.Save(#"C:\" + naamFile + ".xml");
This is the original XML file I got :
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>#ref_xml#</MsgId>
<CreDtTm>#datum_tijd_xml#</CreDtTm>
<NbOfTxs>#aantal_transacties#</NbOfTxs>
<InitgPty>
<Nm>#afzender_naam#</Nm>
<Id>
<OrgId>
<Othr>
<Id>#afzender_btw_nr#</Id>
<Issr>KBO-BCE</Issr>
</Othr>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>#ref_payment_block#</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>true</BtchBookg>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>#datum_uitvoering#</ReqdExctnDt>
<Dbtr>
<Nm>#afzender_naam#</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>#afzender_iban#</IBAN>
</Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BIC>#afzender_bic#</BIC>
</FinInstnId>
</DbtrAgt>
<ChrgBr>#kosten#</ChrgBr>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>#ref_end_to_end#</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="#munt#">#bedrag#</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>#leveran_bic#</BIC>
</FinInstnId>
</CdtrAgt>
<Cdtr>
<Nm>#leveran_naam#</Nm>
<PstlAdr>
<Ctry>#leveran_land#</Ctry>
<AdrLine>#leveran_straat#</AdrLine>
<AdrLine>#leveran_wpl#</AdrLine>
</PstlAdr>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>#leveran_iban#</IBAN>
</Id>
</CdtrAcct>
<RmtInf>
<Ustrd>#leveran_ref#</Ustrd>
<Strd>
<CdtrRefInf>
<Tp>
<CdOrPrtry>
<Cd>#gestruct_mededeling_soort1#</Cd>
</CdOrPrtry>
<Issr>#gestruct_mededeling_soort2#</Issr>
</Tp>
<Ref>#gestruct_mededeling#</Ref>
</CdtrRefInf>
</Strd>
</RmtInf>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>
Your xml namespace is not correct. Use it like
nsmgr.AddNamespace("ns", "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03");
doc2.SelectSingleNode("/ns:Document/ns:CstmrCdtTrfInitn/ns:GrpHdr/ns:MsgId", nsmgr).InnerText = "some text";

delete child node with specific value

Am trying to delete a list name containing the value "dfdfdfd" from an XPath
XmlNode names = LoadDocument(xml).DocumentElement.SelectSingleNode("//Class[#Name='" + getCurClass() + "']/Property[#Id='" + i + "']/Lists[contains(ListName,'ws_Users')]");
after I execute this statement:
names.RemoveChild(names.FirstChild);
but I nothing happens.
My XML :
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Class Name="ECMInstruction" Style="Top">
<Entity Id="1" Name="DocumentInformation" />
<Property Id="1">
</Property>
<Property Id="2">
<Lists>
<ListName>ws_Users</ListName>
<ListName>dfdfdfd</ListName>
</Lists>
</Property>
</Class>
</Root>
Thanks for the help
You need to save the modified XmlDocument object back to file :
XmlDocument doc = LoadDocument(xml);
XmlNode names = doc.DocumentElement.SelectSingleNode("//Class[#Name='" + getCurClass() + "']/Property[#Id='" + i + "']/Lists[contains(ListName,'ws_Users')]");
names.RemoveChild(names.FirstChild);
//save `doc` back to file :
doc.Save("path_to_the_xml_file.xml");
or this way :
XmlNode names = LoadDocument(xml).DocumentElement.SelectSingleNode("//Class[#Name='" + getCurClass() + "']/Property[#Id='" + i + "']/Lists[contains(ListName,'ws_Users')]");
names.RemoveChild(names.FirstChild);
//save owner `XmlDocument` back to file :
names.OwnerDocument.Save("path_to_the_xml_file.xml");

Select subset of XML

I know this is a very basic question but I'm new to XML and while it seems simple, I can't find a simple answer anywhere. I have an XML document that looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<root version="1">
<targets>
<target type="email">
<property name="to">b1q23#email.com</property>
</target>
<target type="fob"/>
</targets>
<observation uniqueID="00A60D" deviceID="308610ea23">
<field name="field1">test1</field>
<field name="field2">test2</field>
</observation>
and I'm trying to either select a subset of that xml, or remove nodes, to get it pared down to:
<observation uniqueID="00A60D" deviceID="308610ea23">
<field name="attachments">
<string>1910.jpg</string>
</field>
<field name="field1">test1</field>
<field name="field2">test2</field>
</observation>
So that I can deserialize it into an object. Any help is greatly appreciated.
You can use XPath:
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<root version=\"1\">" +
"<targets>" +
"<target type=\"email\">" +
"<property name=\"to\">b1q23#email.com</property>" +
"</target>" +
"<target type=\"fob\"/>" +
"</targets>" +
"<observation uniqueID=\"00A60D\" deviceID=\"308610ea23\">" +
"<field name=\"field1\">test1</field>" +
"<field name=\"field2\">test2</field>" +
"</observation>" +
"</root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlElement root = doc.DocumentElement;
var observationNode = root.SelectSingleNode("/root/observation");
var observationXml = observationNode.OuterXml;
Here is a XML to LINQ Version:
dynamic root= XElement.Load(dataStream).Descendants("root")
.Select(element => element.Value).ToArray();
This will give all the root element from the document.And you can access root
XElement root = XElement.Parse("<root version ..." // etc. to parse a string.
// Use XElement.Load to load a file.
var observations = root.Elements("observation");
It assumes one root (by definition) and possibly multiple observation elements.

Build SOAP envelope with XDocument instead of string

currently I have this code to build a soap envelope:
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body> " +
"<ABRSearchByABN xmlns=\"http://abr.business.gov.au/ABRXMLSearch/\"> " +
"<searchString>" + searchValue + "</searchString>" +
"<includeHistoricalDetails>" + history + "</includeHistoricalDetails>" +
"<authenticationGuid>" + guid + "</authenticationGuid>" +
"</ABRSearchByABN>" +
"</soap:Body>" +
"</soap:Envelope>";
I am trying to create an XML document instead but I am not sure on how to go on with the namespaces.
Code that obiously doesn't work:
XNamespace soap = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xmlns = "http://abr.business.gov.au/ABRXMLSearch/";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
XDocument xd = new XDocument(
new XDeclaration("1.0","utf-8",""),
new XElement("soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"",
new XElement("soap:Body",
new XElement("ABRSearchByABN xmlns=\"http://abr.business.gov.au/ABRXMLSearch/\"",
new XElement("searchString", searchValue),
new XElement("includeHistoricalDetails", history),
new XElement("authenticationGuid", guid)))));
How can I complete this?
Thanks in advance.
You could use the XmlDocument class and continue to append children.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.AppendChild(xmlDoc.CreateNode(XmlNodeType.Element, "soap", "Envelope", "http://www.w3.org/2001/XMLSchema-instance"));
Also, assuming you already have your xml stored as a string, an even simpler although potentially less manageable solution would be to simply declare a new XmlDocument and load the string to it.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(yourString);
This covers everything in pretty good detail: http://msdn.microsoft.com/en-us/library/bb387042.aspx
You can't think of a DOM API (like L2XML or XmlDocument) the same way as you think of your string-concatenating code. When working with L2XML, namespace declarations and attributes are "things" that need to be handled explicitly, not just extra characters that go between angle brackets. Consequently, the XElement constructor isn't as simple as "here is the string I want to go between the angle brackets." Instead, you need to use an alternate XElement constructor that handles namespaces.

Categories