Is there a way to create DOM elements using string in AngleSharp? For example:
var result = document.Create...("<div id='div1'>hi<p>world</p></div>");
This is possible using a document fragment.
There are multiple possibilities how to use a document fragment, one way would be to use fragment parsing for generating a node list in the right context:
var context = BrowsingContext.New(Configuration.Default);
var document = await context.OpenAsync(r => r.Content("<div id=app><div>Some already available content...</div></div>"));
var app = document.QuerySelector("#app");
var parser = context.GetService<IHtmlParser>();
var nodes = parser.ParseFragment("<div id='div1'>hi<p>world</p></div>", app);
app.Append(nodes.ToArray());
The example shows how nodes can be created in the context of a certain element (#app in this case) and that the behavior is different than, e.g., using InnerHtml, which would remove existing nodes.
Hope this helps!
Related
I'm new to mongo in c#
I found tow ways to find documents based on search critiria:
the first using filter:
var collection = _database.GetCollection<BsonDocument>("restaurants");
var filter = Builders<BsonDocument>.Filter.Eq("address.zipcode", "10075");
var result = await collection.Find(filter).ToListAsync();
The second using query:
MongoCollection<BsonDocument> books;
var query = Query.EQ("author", "Kurt Vonnegut");
foreach (BsonDocument book in books.Find(query)) {
// do something with book
}
What's the best way to find documents based to what MongoDB recommendation?
As far I know query builders (like your second example using Query.EQ) belong to old versions of C# drivers (1.X) (see Query class). Also I suggest you to see Builder section in this link that confirm query builders is the old way to consult data.
After the release of the 2.0 version of the .NET driver, a lot of changes were made, including the way of consult the data (you can read more about that in this link). If you are using the last C# driver version you should use your first approach.
The first way you mentioned is quite fine. You might want to incorporate using a mongo cursor as well to allow you to iterate through results
var collection = _database.GetCollection<BsonDocument>("restaurants");
var filter = Builders<BsonDocument>.Filter.Eq("address.zipcode", "10075");
using(var _cursor = await collection.Find(filter).ToCursorAsync())
{
while(await _cursor.MoveNextAsync())
{
foreach(var _document in _cursor.Current) //gets current document
{
//you can do things like get the _id of the document
var _id = _document["_id"];
}
}
}
I have a sample xml file in following format:-
Also, I have a Control class shown below:
class Control
{
private string id;
public string Id
{
get { return id; }
set { id = value; }
}
private string controlType;
public string ControlType
{
get { return controlType; }
set { controlType = value; }
}
private string searchProperties;
public string SearchProperties
{
get { return searchProperties; }
set { searchProperties = value; }
}
public List<Control> ChildrenControl = new List<Control>();
}
I need to read the XML file mentioned above and populate the code. I am not sure how to recursively do that. I was thinking to use Linq to XML, but not sure how to use it recursively in this case in which parent and child elements are of the same type. Can someone please help me with this problem?
Thanks,
Harit
Update:
Try the following. It uses Linq to XML and a recursive function to parse the controls from out of the XML document. It assumes the existence of your XML data in a file called "Controls.xml", and obviously your Control class. Its not the greatest of code, but it should get you started.
private void ParseControlsData()
{
var doc = XDocument.Load("Controls.xml");
var controls = from control in doc.Element("controls").Elements("control")
select CreateFromXElement(control);
var controlsList = controls.ToList();
Console.ReadLine();
}
private Control CreateFromXElement(XElement element)
{
var control = new Control()
{
Id = (string)element.Attribute("id"),
ControlType = (string)element.Attribute("controlType"),
SearchProperties = (string)element.Attribute("searchProperties")
};
var childrenElements = element.Element("childControls");
if (childrenElements != null)
{
var children = from child in childrenElements.Elements("control")
select CreateFromXElement(child);
control.ChildrenControl = children.ToList();
}
return control;
}
Notes:
In the ParseControlsData function, it uses query expression syntax to select the first element in the document called "controls" (your root), and then selects all sub-elements named "control". A very similar expression occurs inside the CreateFromXElement function, except it needs to find an element called "childControls".
There's no real error checking. You'll definitely need some.
Update:
Don't do this, it doesn't work for your example because you have values stored in attributes, and by default the DataContractSerializer + DataContractAttributes combination does not support that (without a whole bunch of extra work). Other options are Linq to XML (as you suggested) and using the XmlSerializer (which is similar to the DataContractSerializer, but uses its own set of attributes). I'll look into it further.
Previous Answer:
One way to turn an XML document into an Object Graph is to mark the classes you want to create from the XML with DataContract attributes, and to use the DataContractSerializer. All you need to do is make sure that the DataContract(Name = "X") and DataMember(Name = "Y") match the names of the elements inside your XML.
Have a look at my answer on XML Element Selection, which is performing the operation you want (taking existing XML and turning it into an Object Graph). You probably wont need to worry about the CDATA stuff that that user ran into, so your solution will probably be a bit simpler.
Also, have a look at my answer on How to catch/send XML doc with various sub arrays?, which is performing the reverse operation (that user wanted to create XML from an Object Graph).
If you can't tell, I'm a fan of the DataContractSerializer :)
You can use recursion using Func<> delegate, but you have to declare it before specifying the actual delegate logic:
var xDoc = XDocument.Load("Input.xml");
Func<XElement, List<Control>> childControlsQuery = null;
childControlsQuery =
x => (from c in x.Elements("control")
select new Control
{
Id = (string)c.Attribute("id"),
ControlType = (string)c.Attribute("controltype"),
SearchProperties = (string)c.Attribute("searchproperties"),
ChildrenControl = childControlsQuery(c.Element("childControls") ?? new XElement("childControls"))
}).ToList();
var controls = childControlsQuery(xDoc.Root);
You can remove ?? new XElement("childControls") if you're sure there is always childControls element, even when given control does not have any childs.
And if you're sure there is always only one main control, you can get it as:
var mainControl = controls.First();
I am using Roslyn library.
I want to add the statements after matching line: Here is the requirement.
first I want to find the below line:
_container.RegisterInstance(NavigationService);
And then I want to add below statements after the above line:
_container.RegisterInstance<ISessionStateService>(SessionStateService);
_container.RegisterInstance<IFlyoutService>(FlyoutService);
Any help would be greatly appreciated.
EDIT:(I have created the expressions but now how to add those two experssions to my targetExpression?
string strContent = File.ReadAllText(strPath);
SyntaxTree tree = SyntaxTree.ParseText(strContent);
var targetExpression = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>()
.FirstOrDefault(
x => x.Expression.ToString().Contains("_container.RegisterInstance") && x.ArgumentList.ToString().Contains("NavigationService"));
InvocationExpressionSyntax replacementNode1 =
Syntax.InvocationExpression(Syntax.ParseExpression(#"_container.RegisterInstance<ISessionStateService>(SessionStateService);"));
InvocationExpressionSyntax replacementNode2 =
Syntax.InvocationExpression(Syntax.ParseExpression(#"_container.RegisterInstance<IFlyoutService>(FlyoutService);"));
MethodDeclarationSyntax targetMethod = (MethodDeclarationSyntax)targetExpression.Parent.Parent.Parent;
List<InvocationExpressionSyntax> list = targetMethod.DescendantNodes().OfType<InvocationExpressionSyntax>().ToList();
int index = list.IndexOf(targetExpression);
list.Insert(index + 1, replacementNode1);
list.Insert(index + 1, replacementNode2);
now the issue is how to get my updated tree?? Means how to update my list and get the tree with these changes.
Edit: Now I am able to generate add the nodes but only issue is formatting.. the spacing is not correct. here is the code:
string strContent = File.ReadAllText(strPath);
SyntaxTree tree = SyntaxTree.ParseText(strContent);
ExpressionStatementSyntax expressionStatementSyntax =
Syntax.ExpressionStatement(Syntax.ParseExpression("_container.RegisterInstance(NavigationService);"));
var targetBlock =
tree.GetRoot()
.DescendantNodes()
.OfType<BlockSyntax>()
.FirstOrDefault(x => x.Statements.Any(y => y.ToString().Contains("_container.RegisterInstance")));
StatementSyntax syn1 =
Syntax.ParseStatement(#"_container.RegisterInstance<ISessionStateService>(SessionStateService);");
StatementSyntax syn2 = Syntax.ParseStatement(#"_container.RegisterInstance<ISessionStateService>(SessionStateService2);");
List<StatementSyntax> newSynList = new List<StatementSyntax> { syn1, syn2 };
SyntaxList<StatementSyntax> blockWithNewStatements = targetBlock.Statements;
foreach (var syn in newSynList)
{
blockWithNewStatements = blockWithNewStatements.Insert(1, syn);
}
BlockSyntax newBlock = Syntax.Block(blockWithNewStatements);
var newRoot = tree.GetRoot().ReplaceNode(targetBlock, newBlock);
it generates the output with all the lines left aligned.. any suggestions?
After your edit, it looks like the main remaining question is about dealing with the line formatting. In both cases, once you've got your final root, you can invoke a formatter to clean it up. You have two options:
You can call the NormalizeWhitespace() extension on your nodes once you're done, which very rudely reformats all the nodes into something remotely "reasonable". If you don't care about preserving any formatting you had, and just want the output to not look terrible, this is the simple option.
You can reference the Roslyn.Services assembly, and then add "using Roslyn.Services" on the top if you don't already. From there, there's a Format() method which is a much fancier formatter that attempts to keep indenting as it is, respects what the user already had, etc, etc. If you stick a syntax annotation on the nodes you created, you can then pass that annotation to this formatter so it knows to leave the rest of the file untouched.
I have this string of XML elements in a document
<dmc><avee><modelic></modelic><sdc></sdc><chapnum></chapnum><section></section>
<subsect></subsect><subject></subject><discode></discode><discodev></discodev>
<incode></incode><incodev></incodev><itemloc></itemloc></avee></dmc>
What I need to do is now populate those elements with user inputted variables using Linq. I currently have:
XDocument doc = XDocument.Load(sgmlReader);
doc.Element("modelic").Add(MI);
doc.Element("sdc").Add(sd);
doc.Element("chapnum").Add(sys);
doc.Element("section").Add(subsys);
doc.Element("subsect").Add(subsubsys);
doc.Element("subject").Add(unit);
doc.Element("discode").Add(dc);
doc.Element("discodev").Add(dcv);
doc.Element("incode").Add(infcode);
doc.Element("incodev").Add(infCV);
doc.Element("itemloc").Add(loc);
(yes I'm using sgmlReader but this works fine in my program in other areas) I'm clearly missing something fundamental as it's giving me a NullReferenceException was unhandled - Object reference not set to an instance of an object.
Any ideas/suggestions please?
The Element() method only matches the immediate children of the container.
You can either chain Descendants() into First():
doc.Descendants("modelic").First().Add(MI);
Or navigate to the immediate parents of the elements you want to modify:
doc.Root.Element("avee").Element("modelic").Add(MI);
This should work:
var avee = dmc.Root.Element("avee");
avee.Element("modelic").Value = MI;
avee.Element("sdc").Value = sd;
Just repeat the last line for each of your remaining elements (chapnum, section...).
The problem was that first you have to retrieve root element (dmc), then avee, and then you can set values for child elements of avee.
I want to get all visible columns (Hidden == false) for specific list in sharePoint site, I tried to look through the SharePointWebService.Lists.GetList(listName), but couldn't find anything useful, also checked the methods provided by the Lists WebService and also nothing new,
Please advice.
You can use the GetListAndView method of the Lists web service to get the schemas for the list and a view.
From the documentation, if you leave the viewName parameter empty, the default view will be returned. Then, you can read the <ViewFields></ViewFields> node for the list of fields.
*Edit*
Turns out using XPath to query the returned XML was tougher than I thought... here is what I came up with:
XmlNode result = webService.GetListAndView("My Pictures", string.Empty);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(result.OwnerDocument.NameTable);
nsmgr.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/soap/");
string xpathQuery = "sp:View/sp:ViewFields/sp:FieldRef";
XmlNodeList nodes = result.SelectNodes(xpathQuery, nsmgr);
for (int i = 0; i < nodes.Count; i++)
{
Console.WriteLine(nodes[i].Attributes["Name"].Value);
}
Looks like you have to have a XmlNamespaceManager otherwise your query always returns no values. Something about specifying the namespace... Here is a good reference.
The GetList() method returns a CAML fragment that includes the list's field (column) definitions. You might want to try an XPath expression:
XmlNode list = yourListService.GetList("yourListName");
XmlNodeList visibleColumns
= list.SelectNodes("Fields/Field[not(#Hidden) or #Hidden='FALSE']");
I used the above code but, after a long search I found the solution to get all or custom columns from the sharepoint list. The code for that is shared on ..
Custom Columns or ALL Columns
Solution is quite simple. Using GetList() or similar functions is the wrong way to go.
Instead use GetListContentTypesAsync() to get Content ID and then get the specific ContentType using GetListContentTypeAsync(), it returns XML which includes all visible columns in sharepoint list:
var Contents = await soapListClient.GetListContentTypesAsync(list.Title, "0x01"); // 0x01 is kind of a root element for sharepoint.
String ContentID = Contents.Body.GetListContentTypesResult.Descendants().FirstOrDefault().Attribute("ID").Value.ToString();
var ContentType = await soapListClient.GetListContentTypeAsync(list.Title, ContentID);
XElement xmll = XElement.Parse(ContentType.Body.GetListContentTypeResult.ToString());