Get Resutls from XML with more than one line - c#

I want get Order Lines for each Order and bring them to an EMail Body as Table like
Value 1 | Value 2 | Value 3
12345 ABC X1_
XML Code:
<?xml version="1.0" encoding="utf-8"?><UniversalInterchange xmlns= "http://www.designworker/namespace" version="1.1">
<Header> </Header>
<Body>
<UniversalShipment xmlns="http://www.designworker/namespace" version="1.1">
<Shipment>
<DataContext>
<DataTargetCollection>
<DataTarget>
<Type>SMTPTYPE</Type>
</DataTarget>
</DataTargetCollection>
</DataContext>
<Order>
<OrderNumber>99348234234</OrderNumber>
<OrderLineCollection>
<OrderLine>
<LineNumber>1</LineNumber>
<OrderedQty>455.000</OrderedQty>
<OrderedQtyUnit>
<Code>MORE</Code>
</OrderedQtyUnit>
<Product>
<Code>999LAM01</Code>
<Description>New Design Work</Description>
</Product>
<QuantityMet>1.000</QuantityMet>
<ShortfallQuantity>0</ShortfallQuantity>
</OrderLine>
<OrderLine>
<LineNumber>2</LineNumber>
<OrderedQty>655.000</OrderedQty>
<OrderedQtyUnit>
<Code>SOME</Code>
</OrderedQtyUnit>
<Product>
<Code>999LAM02</Code>
<Description>OLD Design Work </Description>
</Product>
<QuantityMet>3.000</QuantityMet>
<ShortfallQuantity>45</ShortfallQuantity>
</OrderLine>
</OrderLineCollection>
</Order>
</Shipment>
</UniversalShipment>
</Body>
</UniversalInterchange>
I have tried to solve this with this code:
var xDoc = XDocument.Parse(xmlValue);
XNamespace nsp = ns;
try
{
var value = xDoc
.Element(nsp + "UniversalInterchange")
.Element(nsp + "Body")
.Element(nsp + "UniversalShipment")
.Element(nsp + "Order")
.Element(nsp + "OrderLine")
.Element(nsp + "LineNumber")
.Value;
return value;
But when I have more than one Line in the Order it won't work.
How can I solve this on a better way ?

Looks like the navigation path is missing a few .Element()-calls.
var orderLines = xDoc
.Element(nsp + "UniversalInterchange")
.Element(nsp + "Body")
.Element(nsp + "UniversalShipment")
.Element(nsp + "Shipment")
.Element(nsp + "Order")
.Element(nsp + "OrderLineCollection")
.Elements(nsp + "OrderLine");
// 1, 2
var lineNumbers = orderLines.Select(x => x.Element(nsp + "LineNumber").Value);
Whenever an element isn't found, null is returned from .Element(). You should also use .Elements() instead of .Element() if you expect multiple entries.

Related

Find translation unit pairs in tmx file

I have a Translation Memory which is essentially an XML file based on Translation Memory eXchange format specifications and I am trying to find a specific translation unit for editing. This is an example of the structure:
<?xml version="1.0" encoding="utf-8"?>
<tmx version="1.4">
<header creationtool="xxx" .... />
<body>
<tu tuid="1">
<tuv xml:lang="en-US">
<seg>sample source</seg>
</tuv>
<tuv xml:lang="de-DE">
<seg>sample translation</seg>
</tuv>
</tu>
<tu tuid="2">
<tuv xml:lang="en-US">
<seg>Address</seg>
</tuv>
<tuv xml:lang="de-DE">
<seg>Adresse</seg>
</tuv>
</tu>
.....
</body>
</tmx>
What I want is to be able to find all the translation units (tu) that have a specific source translation and a specific target translation. So for example I want to find all translation units where the xml language attribute value is "en-US" and the seg element value is "sample source" and the xml language attribute value is "de-DE" and its seg element value is "sample translation". I want to find
<tu tuid="18">
<tuv xml:lang="en-AU">
<seg>sample source</seg>
</tuv>
<tuv xml:lang="de-DE">
<seg>sample translation</seg>
</tuv>
</tu>
It is possible as well there is more than one translation unit (tu) that fits the criteria - that is there is possibly duplicates in the translation memory.
I have tried to get a collection I could iterate through e.g.
XElement root = XElement.Load(#"sample.tmx");
IEnumerable<XElement> translationUnits =
from el in root.Elements("tu")
where
(from tuv in el.Elements("tuv")
where
(string)tuv.Attribute(XNamespace.Xml + "lang") == "en-US" &&
(string)tuv.Element("seg") == "sample source"
select tuv)
.Any()
select el;
foreach (XElement el in translationUnits)
Console.WriteLine((string)el.Attribute("tuid"));
However I am obviously doing something wrong however I think I am on the right track. Once I find the collection I then want to update the target translation.
The way I eventually solved this for future reference is using XmlDocument
XmlDocument document = new XmlDocument();
document.Load(this.fileName);
string nodeSelect = "/tmx/body/tu/tuv[lang('" + this.sourceLanguage + "') and seg = '" + this.originalSourceText + "']";
XmlNodeList nodes = document.DocumentElement.SelectNodes(nodeSelect);
foreach (XmlNode node in nodes) {
XmlNode parent = node.ParentNode;
foreach (XmlNode translationNode in parent) {
string searchNode = "*[lang('" + this.targetLanguage + "') and //seg = '" + this.originalTranslationText + "']";
XmlNode test = translationNode.SelectSingleNode(searchNode);
if (test != null) {
if (test.InnerText.Equals(this.originalTranslationText, StringComparison.Ordinal)) {
test.InnerText = this.newTranslation;
}
}
}
}

Parsing XML with XElement results in Object reference not set to an instance of an object

The XML below is being returned from a web service. However, I cannot seem to get the value of or when using XElement.
<ResponseArray xmlns="urn:mdWebServiceAddress" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Version>2.0.62</Version>
<TransmissionReference></TransmissionReference>
<Results></Results>
<TotalRecords>1</TotalRecords>
<Record>
<RecordID>1</RecordID>
<Results>AC01,AS01</Results>
<Address>
<Address1>22382 Avenida Empresa</Address1>
<Address2></Address2>
<Suite></Suite>
<PrivateMailBox></PrivateMailBox>
<City>
<Name>Rancho Santa Margarita</Name>
<Abbreviation>Rcho Sta Marg</Abbreviation>
</City>
<State>
<Name>California</Name>
<Abbreviation>CA</Abbreviation>
</State>
<Zip>92688</Zip>
<Plus4>2112</Plus4>
<AddressKey>92688211282</AddressKey>
</Address>
</Record>
</ResponseArray>
Below is the code I am using to collect the values. Is the namespace being set incorrectly? How do I access the values of these elements in the XML.
XElement xelement = XElement.Parse(xmlString);
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
IEnumerable<XElement> records = xelement.Elements();
foreach (var record in records)
{
Console.WriteLine(record.Element(ns + "RecordID").Value);
Console.WriteLine(record.Element(ns + "Address").Element(ns + "AddressKey").Value);
}
a) change namespace
b) use Descendants
XNamespace ns = "urn:mdWebServiceAddress";
IEnumerable<XElement> records = xelement.Descendants(ns + "Record");
foreach (var record in records)
{
Console.WriteLine(record.Element(ns + "RecordID").Value);
Console.WriteLine(record.Element(ns + "Address").Element(ns + "AddressKey").Value);
}
PS: Safe way to use xml namespaces can be
XNamespace ns = xelement.GetDefaultNamespace();

XElement get start Tag string

Is possible to get the start tag string of an XElement?
For example, if i have an xml element like this
<Product Id="101" Name="Product 1">
<Images>
// ..
</Images>
<Description>
// ..
</Description>
</Product>
i want to get only the start tag:
<Product Id="101" Name="Product 1">
I use this for validation feedback purposes.
use query like
XElement xele = XElement.Load("xmlfilename");
XNamespace _XNamespace = XNamespace.Get("namespace url");
IEnumerable<XElement> ProductAttribute = from ele in xele .Descendants(_XNamespace + "Product ")
where ele.Attribute("Id").Value =="101" && ele.Attribute("Name") == "Product 1"
select ele;
Hope it will work for you

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.

Using Linq to return a list of attributes in a node

I am attempting to write a LINQ query to pull `ows_Alert="This is the text for an alert" into a list. there may be more than 1 "ows_Alert" so what I'm trying to do is retrieve a list of alerts, and place them as items of a split button drop-down menu.
I tried, attributes, and I tried elements, but htey are neither? How do I retrieve the ows_Alert value?
My code is as follows:
pAlerts= xDocument.Elements().ToList();
pAlerts.ForEach(item => tsSplitBtnAlerts.DropDownItems
.Add(item.Attribute("ows_Alert").ToString()));
The XML File
<?xml version="1.0" encoding="utf-8" ?>
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="1">
<z:row ows_ContentTypeId="0x0100D2769100E1771B4A94C86F01916A3C4F"
ows_Title="Alert Test"
ows_Alert="This is the text for an alert"
ows_ID="1" ows_ContentType="Item"
ows_Modified="2013-08-02 11:19:07" ows_Created="2013-08-02 11:19:07" ows_Author="1;#REDACTED" ows_Editor="1;#REDACTED"
ows_owshiddenversion="1" ows_WorkflowVersion="1" ows__UIVersion="512" ows__UIVersionString="1.0"
ows_Attachments="0" ows__ModerationStatus="0" ows_LinkTitleNoMenu="Alert Test" ows_LinkTitle="Alert Test"
ows_LinkTitle2="Alert Test" ows_SelectTitle="1" ows_Order="100.000000000000" ows_GUID="{77BD9162-461F-4A97-89E3-033E387E76A9}"
ows_FileRef="1;#Lists/PortalToolbarAlerts/1_.000" ows_FileDirRef="1;#Lists/PortalToolbarAlerts"
ows_Last_x0020_Modified="1;#2013-08-02 11:19:07" ows_Created_x0020_Date="1;#2013-08-02 11:19:07" ows_FSObjType="1;#0"
ows_SortBehavior="1;#0" ows_PermMask="0xb008431061" ows_FileLeafRef="1;#1_.000" ows_UniqueId="1;#{3E3EA8F8-16B2-4DD0-81B1-BAA9592302E9}"
ows_ProgId="1;#" ows_ScopeId="1;#{4310D927-E486-4B8C-8034-52937AC5A6D8}" ows__EditMenuTableStart="1_.000" ows__EditMenuTableStart2="1"
ows__EditMenuTableEnd="1" ows_LinkFilenameNoMenu="1_.000" ows_LinkFilename="1_.000" ows_LinkFilename2="1_.000"
ows_ServerUrl="/Lists/PortalToolbarAlerts/1_.000" ows_EncodedAbsUrl="http://REDACTEDSITE/1_.000"
ows_BaseName="1_" ows_MetaInfo="1;#" ows__Level="1" ows__IsCurrentVersion="1" ows_ItemChildCount="1;#0" ows_FolderChildCount="1;#0" />
</rs:data>
</listitems>
XNamespace z = "#RowsetSchema";
var alerts = xDocument.Descendants(z + "row")
.Select(row => (string)row.Attribute("ows_Alert"))
.ToList();
var ns = XNamespace.Get("#RowsetSchema");
var alerts = xml
.Descendants(ns + "row")
.Select(row => row.Attribute("ows_Alert").Value);
You have to include the namespaces when traversing the document. I tried this when using your xml in "test.xml" and it worked.
XDocument document = XDocument.Load(Server.MapPath("~/test.xml"), LoadOptions.None);
XNamespace ns = "urn:schemas-microsoft-com:rowset";
XNamespace z = "#RowsetSchema";
IEnumerable<XElement> datas = document.Root.Elements(ns + "data");
foreach (XElement data in datas)
{
IEnumerable<XElement> rows = data.Elements(z + "row");
string alerts = "";
foreach (XElement row in rows)
{
alerts += row.Attribute("ows_Alert").Value + "<br />";
}
Test.Text = alerts;
}

Categories