how to make checks in xml? - c#

i have method which create xml:
var xml = new XmlDocument();
var head = xml.CreateElement("Head");
var uniqueIdentifier = xml.CreateElement("Unique_identifier");
var documentDate = xml.CreateElement("Document_date");
var documentNumber = xml.CreateElement("Document_number");
uniqueIdentifier.InnerText = "1";
documentDate.InnerText = "2019-01-01";
documentNumber.InnerText = "2";
xml.AppendChild(head);
head.AppendChild(uniqueIdentifier);
head.AppendChild(documentDate);
head.AppendChild(documentNumber);
InnerText Values i get from db and this fields can be null or empty. so, each variable needs checked for null and an empty string
like this
var uniqueIdentifier = xml.CreateElement("Unique_identifier");
var r = reader.GetFieldValue("Unique_identifier");
if (r is string)
{
if (!string.IsNullOrWhiteSpace(r))
{
uniqueIdentifier.InnerText = Text.Convert(r);
}
}
I get a lot of extra lines(5 variable and 10 check). How clean it?

Related

AWS .NET SDK DynamoDB Filter expression by Map values doesn't return any data

I'm trying to load data from DynamoDB.
I use FilterExpression and KeyExpression.
If I search by simple value on the top level everything works fine.
However, when I try to filter records by nested map values, I get 0 records.
CurrentCase is an object, Assignments is Dictionary, Setup is Enum.
Here is my code:
`Expression filterExpression = new ();
filterExpression.ExpressionAttributeNames["#Setup"] = "CurrentCase.Assignments.Setup";
filterExpression.ExpressionAttributeValues[":userId"] = userId;
filterExpression.ExpressionStatement = "#Setup = :userId";`
I tried another way, didn't help. (WHERE CurrentCase.Assignments['Setup'] = 'Id' works in PartyQL):
`Expression filterExpression = new ();
filterExpression.ExpressionAttributeNames["#Setup"] = "CurrentCase.Assignments['Setup']";
filterExpression.ExpressionAttributeValues[":userId"] = userId;
filterExpression.ExpressionStatement = "#Setup = :userId";`
This is how i call query
var queryOperationConfig = new QueryOperationConfig
{
PaginationToken = paginationToken,
Limit = pageSize,
IndexName = GlobalIndexNames.Cases,
KeyExpression = keyExpression,
FilterExpression = filterExpression
};
Search search = _dbContext.GetTargetTable<CaseEntity>().Query(queryOperationConfig);
List<Document> documents = await search.GetNextSetAsync(cancellationToken);
I expect that this request return all records where CurrentCase.Assignments['Setup'] equals userId
Forgive me, im not a .Net coder, but your issue is this:
filterExpression.ExpressionAttributeNames["#Setup"] = "CurrentCase.Assignments.Setup";
You are essentially setting your var #Setup to a String "CurrentCase.Assignments.Setup"
It should be:
ExpressionAttributeNames = new Dictionary<string, string>
{
{ "#CurrentCase", "CurrentCase" },
{ "#Assignments", "Assignments" },
{ "#Setup", "Setup" }
}
filterExpression.ExpressionStatement = "#CurrentCase.#Assignments#Setup = :userId";`
You may need to restructure the example I gave, but you should get the idea.

Assigning values from a object with known properties

Im writing a class with witch creates a overview over the employees phones.
I am getting the info form Activesync object containing phones as children.
This is my current code. It works if the child dont contain any nulls.
foreach (DirectoryEntry child in directoryObject.Children)
{
var activeSyncPhone = new ActiveSync.Phone();
activeSyncPhone.Cn = child.Properties["cn"].Value.ToString(); //string
activeSyncPhone.DistinguishedName = child.Properties["distinguishedName"].Value.ToString(); //sting
activeSyncPhone.InstanceType = (int)child.Properties["instanceType"].Value; //int
activeSyncPhone.WhenCreated = (DateTime)child.Properties["whenCreated"].Value; //datetime
activeSyncPhone.WhenChanged = (DateTime)child.Properties["whenChanged"].Value; //datetime
activeSyncPhone.Name = child.Properties["name"].Value.ToString(); //string
activeSyncPhone.ObjectCategory = child.Properties["objectCategory"].Value.ToString(); //string
activeSyncPhone.MsExchFirstSyncTime = (DateTime)child.Properties["msExchFirstSyncTime"].Value;//datetime
activeSyncPhone.MsExchDeviceEASVersion = child.Properties["msExchDeviceEASVersion"].Value.ToString();//string
activeSyncPhone.MsExchDeviceFriendlyName = child.Properties["msExchDeviceFriendlyName"].Value.ToString(); //string
activeSyncPhone.MsExchDeviceAccessState = (ActiveSync.Phone.DeviceAccessState)child.Properties["msExchDeviceAccessState"].Value; //int
activeSyncPhone.MsExchDeviceID = child.Properties["msExchDeviceID"].Value.ToString(); //string
activeSyncPhone.MsExchDeviceType = child.Properties["msExchDeviceType"].Value.ToString(); //string
try
{
activeSyncPhone.MsExchDeviceIMEI = child.Properties["msExchDeviceIMEI"]?.Value.ToString(); //string
}
catch
{
activeSyncPhone.MsExchDeviceIMEI = "Could not find IMEI";
}
activeSyncPhone.MsExchDeviceUserAgent = child.Properties["msExchDeviceUserAgent"].Value.ToString(); //string
activeSyncPhone.MsExchVersion = child.Properties["msExchVersion"].Value.ToString(); //string
activeSyncPhone.MsExchDeviceAccessStateReason = (ActiveSync.Phone.DeviceAccessStateReason)child.Properties["msExchDeviceAccessStateReason"].Value; //string
activeSyncPhone.MsExchUserDisplayName = child.Properties["msExchUserDisplayName"].Value.ToString(); //string
activeSyncPhone.MsExchDeviceModel = child.Properties["msExchDeviceModel"].Value.ToString(); //string
activeSyncPhone.MsExchDeviceOS = child.Properties["msExchDeviceOS"].Value.ToString(); //string
activeSyncPhone.ObjectGUID = child.Properties["objectGUID"].Value.ToString(); //string
activeSyncUnits.PhoneList.Add(activeSyncPhone);
child.Close();
}
directoryObject.Close();
I was wondering if there was any way to make this a bit more robust. I was looking into setting the ActiveSyncPhone's propertys dynamically and then with a list set all the properties. But C# is a strongly-typed language and I figured id take advantage of the type safety and performance advantages that accompany that aspect. I think there might be a better way then checking every child.property for null with if statements? and aslo is there a better way for getting the child properties?
You could create a generic function for that:
// you'll have to figure out the type of the `child.Properties`
public static T GetValue<T>(TypeOfChildProperties properties, string name, T defaultValue = default(T))
{
var value = properties[name];
if (value == null)
return defaultValue;
return (T)value;
// if you have some cast problems, you could use this:
return (T)Convert.ChangeType(value, typeof(T));
}
activeSyncPhone.Cn = GetValue<string>(child.Properties, "cn");
activeSyncPhone.DistinguishedName = GetValue<string>(child.Properties, "distinguishedName");
activeSyncPhone.InstanceType = GetValue<int>(child.Properties, "instanceType");
activeSyncPhone.MsExchDeviceIMEI = GetValue<string>(child.Properties, "msExchDeviceIMEI", "Could not find IMEI");

Check for missing elements while using LINQ to XML

I am trying get data from the xml. Below is the code which
gets data from the XDocument and return list<t>.
However, p.Element("Sponsor") can sometimes be null. How can I check for the null values
var atClauseList = doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG).Select(p => new AtClause()
{
ClauseNumber = (string)p.Element("Number"),
Sponsors = p.Element("Sponsor").Elements(SPONSOR_TAG).Select(y => y.Value)
.ToList(),
Page = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Page").ElementValueNull(),
Line = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Line").ElementValueNull(),
LineText = p.Element("Sponsor").Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull(),
ItalicText = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Italic").ElementValueNull(),
ParaList = p.Element("Sponsor").Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}
).ToList()
}).ToList();
move your code out of an object initializer, and add some logic to it:
var atClauseList = new List<AtClause>();
foreach(var item in doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG))
{
var atClause = new AtClause();
atClause.ClauseNumber = (string)item.Element("Number");
var sponsor = item.Element("Sponsor");
if (sponsor != null)
{
atClause.Sponsors = sponsor.Elements(SPONSOR_TAG).Select(y => y.Value).ToList();
atClause.Page = sponsor.Element("aItem").Element("AmendText").Element("Page").ElementValueNull();
atClause.Line = sponsor.Element("aItem").Element("AmendText").Element("Line").ElementValueNull();
atClause.LineText = sponsor.Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull();
atClause.ItalicText = sponsor.Element("aItem").Element("AmendText").Element("Italic").ElementValueNull();
atClause.ParaList = sponsor.Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}).ToList();
atClauseList.Add(atClause);
}
You can use sequences rather than leaving the IEnumerable immediately:
var value = (string)p.Elements("Sponsor")
.Elements("aItem")
.Elements("AmendText")
.Elements("Page")
.SingleOrDefault()

Upload XLSX to XDocument changes the number format

I have the following method to take an XLSX file and convert it to an XDocument:
public static XDocument ConvertXlsx2Xml(string fileName, string sheetName)
{
// Return the value of the specified cell.
const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string worksheetSchema = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
const string sharedStringsRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
const string sharedStringSchema = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
string cellValue = null;
var xsurvey = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"));
var xroot = new XElement("Root"); //Create the root
using (Package xlPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read))
{
PackagePart documentPart = null;
Uri documentUri = null;
// Get the main document part (workbook.xml).
foreach (System.IO.Packaging.PackageRelationship relationship in xlPackage.GetRelationshipsByType(documentRelationshipType))
{
// There should only be one document part in the package.
documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
documentPart = xlPackage.GetPart(documentUri);
// There should only be one instance, but get out no matter what.
break;
}
if (documentPart != null)
{
// Load the contents of the workbook.
var doc = new XmlDocument();
doc.Load(documentPart.GetStream());
/*
doc now contains the following important nodes:
<bookViews>
<workbookView xWindow="-15615" yWindow="2535" windowWidth="26835" windowHeight="13095" activeTab="2" />
<sheets>
<sheet name="Sheet1" sheetId="2" r:id="rId1" />
*/
// Create a namespace manager, so you can search.
// Add a prefix (d) for the default namespace.
var nt = new NameTable();
var nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("d", worksheetSchema);
nsManager.AddNamespace("s", sharedStringSchema);
//If value for sheetName isn't found, take the first sheet
string searchString = string.Format("//d:sheet[#name='{0}']", sheetName);
XmlNode sheetNode = doc.SelectSingleNode(searchString, nsManager) ??
doc.SelectSingleNode("//d:sheet", nsManager);
/*
* 11/15/12 DS Added to avoid pulling the data each time
* Create a dictionary of the shared strings from the associated string file
*/
#region Shared String Dictionary
var sharedStrings = new Dictionary<int, string>();
foreach (System.IO.Packaging.PackageRelationship stringRelationship in documentPart.GetRelationshipsByType(sharedStringsRelationshipType))
{
// There should only be one shared string reference, so you exit this loop immediately.
Uri sharedStringsUri = PackUriHelper.ResolvePartUri(documentUri, stringRelationship.TargetUri);
PackagePart stringPart = xlPackage.GetPart(sharedStringsUri);
{
// Load the contents of the shared strings.
var stringDoc = new XmlDocument(nt);
stringDoc.Load(stringPart.GetStream());
nsManager.AddNamespace("s", sharedStringSchema);
const string strSearch = "//s:sst";
XmlNode stringNode = stringDoc.SelectSingleNode(strSearch, nsManager);
int keyInt = 0;
if (stringNode != null)
foreach (XmlElement nd in stringNode)
{
//string test = nd.InnerText;
sharedStrings.Add(keyInt, nd.InnerText);
keyInt = keyInt + 1;
}
}
}
#endregion
var hrowList = new List<string>();
var hrowArray = new string[] {};
if (sheetNode != null && sheetNode.Attributes != null)
{
// Get the relId attribute:
XmlAttribute relationAttribute = sheetNode.Attributes["r:id"];
if (relationAttribute != null)
{
string relId = relationAttribute.Value;
// First, get the relation between the document and the sheet.
PackageRelationship sheetRelation = documentPart.GetRelationship(relId);
Uri sheetUri = PackUriHelper.ResolvePartUri(documentUri, sheetRelation.TargetUri);
PackagePart sheetPart = xlPackage.GetPart(sheetUri);
// Load the contents of the workbook.
var sheetDoc = new XmlDocument(nt);
sheetDoc.Load(sheetPart.GetStream());
/*
* sheetDoc now contains the following important nodes:
* <dimension ref="A1:V81" /> range of sheet data
* <sheetData>
* <row r="1" spans="1:22"> <row> r = row number, spans = columns containing the data
* <c r="A1" t="s"><v>0</v></c> <c> r = Cell address (A1,B4,etc), t = data type ("s"=string,"b"=bool, null=decimal)
* <v> contents are the index num if t="s", or value of t=null
*/
XmlNode sheetDataNode = sheetDoc.SelectSingleNode("//d:sheetData", nsManager);
int roNum = 0;
if (sheetDataNode != null)
{
var isSkip = false;
foreach (XmlElement row in sheetDataNode)
{
var xrow = new XElement("Row");
foreach (XmlElement cell in row)
{
XmlAttribute typeAttr = cell.Attributes["t"];
string cellType = typeAttr != null ? typeAttr.Value : string.Empty;
XmlNode valueNode = cell.SelectSingleNode("d:v", nsManager);
cellValue = valueNode != null ? valueNode.InnerText : cellValue;
// Check the cell type. At this point, this code only checks for booleans and strings individually.
switch (cellType)
{
case "b":
cellValue = cellValue == "1" ? "TRUE" : "FALSE";
break;
case "s":
cellValue = sharedStrings[Convert.ToInt32(cellValue)];
break;
}
if (cellValue == null) continue;
cellValue = cellValue.Replace("\r", "");
cellValue = cellValue.Replace("\n", " ");
cellValue = cellValue.Trim();
if (roNum == 0)
{
hrowList.Add(cellValue);
}
else
{
//XmlAttribute rowAttr = cell.Attributes["r"];
//int intStart = rowAttr.Value.IndexOfAny("0123456789".ToCharArray());
//colLet = rowAttr.Value.Substring(0, intStart);
//int colNum = NumberFromExcelColumn(colLet);
int colNum = GetColNum(cell);
/* 05/29/13 DS force column names to UPPER to remove case sensitivity */
var xvar = new XElement(hrowArray[colNum - 1].ToUpper());
xvar.SetValue(cellValue);
xrow.Add(xvar);
}
/* 6/18/2013 DS You must clear the cellValue so it is carried into the next cell value if it is empty. */
cellValue = "";
}
if (roNum == 0) hrowArray = hrowList.ToArray();
else xroot.Add(xrow);
roNum = roNum + 1;
}
}
}
}
}
}
xsurvey.Add(xroot);
return xsurvey;
}
For the most part, it works very well. However, I have just noticed that if one of the cell values contains a number like 0.004 it becomes 4.0000000000000001E-3.
The resulting XML gets imported and that value is loaded as a string, but before the final transfer to the production tables, this particular field is converted to numeric. That format doesn't work with numeric.
How do I prevent that change on load? If I can't, is there a better method to prevent a system error, other than specifically scrubbing that field and changing it back as part of the transfer process?
UPDATE
It is only numbers less than .01 that have a problem. 1, 1.004, and .04 are fine, but .004 is not.
UPDATE 2
If I format the cells as text BEFORE populating the data, I do not have this issue. There is something about how ManEx stores the data that prevents a clean upload.
Read value as double with invariant culture, and then convert it to decimal
var cellValueDouble = Convert.ToDouble(cellValue,System.Globalization.CultureInfo.InvariantCulture);
var cellValueDecimal = Convert.ToDecimal(cellValueDouble);

Reading the XML values using LINQ

what is the best way of reading xml file using linq and the below code you will see that, I have three different loops and I feel like its not elegant or do I have options to retrofit the below code?
public static void readXMLOutput(Stream stream)
{
XDocument xml = new XDocument();
xml = LoadFromStream(stream);
var header = from p in xml.Elements("App").Elements("Application")
select p;
foreach (var record in header)
{
string noym = record.Element("nomy").Value;
string Description = record.Element("Description").Value;
string Name = record.Element("Name").Value;
string Code = record.Element("Code").Value;
}
var appRoles = from q in xml.Elements("App").Elements("Application").Elements("AppRoles").Elements("Role")
select q;
foreach (var record1 in appRoles)
{
string Name = record1.Element("Name").Value;
string modifiedName = record1.Element("ModifiedName").Value;
}
var memeber = from r in xml.Elements("App").Elements("Application").Elements("AppRoles").Elements("Role").Elements("Members")
select r;
foreach (var record2 in memeber)
{
string ExpirationDate = record2.Element("ExpirationDate").Value;
string FullName = record2.Element("FullName").Value;
}
}
UPDATED:
foreach (var record in headers)
{
..............
string Name1 = record.Attribute("Name").Value;
string UnmodifiedName = record.Attribute("UnmodifiedName").Value;
string ExpirationDate = record.Attribute("ExpirationDate").Value;
string FullName = record.Attribute("FullName").Value;
...............
}
Is that your actual code ? All those string variables you are assigning in the foreach loops only have a scope of one iteration of the loop. They are created and destroyed each time.
This may not work precisely in your case depending on the xml structure. Play around with it. Try it using LinqPad
var applications = from p in xml.Descendants("Application")
select new { Nomy = p.Element("nomy").Value
, Description = p.Element("Description").Value
, Name = p.Element("Name").Value
, Code = p.Element("Code").Value
};
var appRoles = from r in xml.Descendants("Role")
select new { Name = r.Element("Name").Value
, ModifiedName = r.Element("ModifiedName").Value
};
This answer is a hierarchical query.
var headers =
from header in xml.Elements("App").Elements("Application")
select new XElement("Header",
new XAttribute("noym", header.Element("nomy").Value),
new XAttribute("Description", header.Element("Description").Value),
new XAttribute("Name", header.Element("Name").Value),
new XAttribute("Code", header.Element("Code").Value),
from role in header.Elements("AppRoles").Elements("Role")
select new XElement("Role",
new XAttribute("Name", role.Element("Name").Value),
new XAttribute("ModifiedName", role.Element("ModifiedName").Value),
from member in role.Elements("Members")
select new XElement("Member",
new XAttribute("ExpirationDate", member.Element("ExpirationDate").Value),
new XAttribute("FullName", member.Element("FullName").Value)
)
)
);

Categories

Resources