Add items programmatically to repeatable items - asp.net

How can I add an item to a repeatable property programmatically in c#:
let's say I have a node (node id 1234) and in it companies list property, where each item has comapny name and image (media picker).
how do I add an item programmtically ?
Here's what I have so far:
XPathNodeIterator xpathIterator = umbraco.library.GetXmlNodeById(NodeId.ToString());
XElement node = XElement.Parse(xpathIterator.Current.OuterXml);
var list = node.Descendants(propertyAlias).FirstOrDefault();
// how do I add items here ? something like:
list.Descendants().Add(...)
thanks.
The package I'm referring to is:
Repeatable Custom Content
update:
I think the solution is to update the xml in umbraco.config.
I have the following xml in umbraco.config:
<Companies id="1176" parentID="1447" ...>
<umbracoNaviHide>0</umbracoNaviHide>
<companyList>
<item>
<data alias="title">Company1</data>
<data alias="image" />
<data alias="text" />
<data alias="date" />
</item>
<item>
<data alias="title">Company2</data>
<data alias="image">1943</data>
<data alias="text" />
<data alias="date" />
</item>
</items>
</companyList>
</Companies>
I am able to update umbraco.config programmatically, but the results are not updated in the backend, so that when I publish the companies node again, the changes are deleted. How can I update the umbraco.config and publish the node ?
Maybe I sh should update the database directly instead ?
My code:
Document companiesDoc = new Document(COMPANIESNODEID);
XmlDocument document = content.Instance.XmlContent;
XmlNode n = document.SelectSingleNode("//Companies[#id=" + COMPANIESNODEID.ToString() + "]").SelectSingleNode("//items");
XmlNode newItem = document.CreateNode(XmlNodeType.Element, "item", null);
XmlNode dName = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xn = document.CreateAttribute("alias");
xn.Value = "title";
dName.Attributes.Append(xn);
dName.InnerText = companyName;
XmlNode dImage = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xi = document.CreateAttribute("alias");
xi.Value = "image";
dImage.Attributes.Append(xi);
dImage.InnerText = companyImage;
XmlNode dText = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xt = document.CreateAttribute("alias");
xt.Value = "text";
dText.Attributes.Append(xt);
XmlNode dDate = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xd = document.CreateAttribute("alias");
xd.Value = "date";
dDate.Attributes.Append(xd);
newItem.AppendChild(dName);
newItem.AppendChild(dImage);
newItem.AppendChild(dText);
newItem.AppendChild(dDate);
n.AppendChild(newItem);

I am able to update umbraco.config programmatically, but the results
are not updated in the backend, so that when I publish the companies
node again, the changes are deleted. How can I update the
umbraco.config and publish the node ?
You are going about it the wrong way. The umbraco.config file is a read-only XML representation of the Umbraco database that is generated by Umbraco and then cached. It isn't intended to be written to or accessed directly. Every time you publish a page in Umbraco this file is regenerated, hence the reasons your updates are not persisted.
You also don't want to try and write to the Umbraco database directly, either. It is very complex and requires lots of relations. Again, it isn't intended to be written to.
To update nodes directly what you really need to do is use the Umbraco Document API. This allows you direct write access to nodes which you can the programatically publish. Simple example:
Document doc = new Document(1234);
doc.getProperty("bodyText").Value = "<p>Your body text</p>";
doc.getProperty("articleDate").Value = DateTime.Now;
User author = User.GetUser(0);
doc.Publish(author);
umbraco.library.UpdateDocumentCache(doc.Id);
I'd suggest posting on http://our.umbraco.org/forum if you need more help.

I managed to solve the problem using this code:
var doc = new Document(COMPANIESNODEID);
XDocument xdoc = XDocument.Parse(doc.getProperty("companyList").Value.ToString());
xdoc.Element("items").Add(new XElement("item",
new XElement("data", new XAttribute("alias", "title"), companyName),
new XElement("data", new XAttribute("alias", "image"), companyImage)));
doc.getProperty("companyList").Value = xdoc.ToString();
doc.Save();
doc.Publish(new User(0));
umbraco.library.UpdateDocumentCache(doc.Id);

Related

XmlDocument difficulties returning specific nodes/elements

first post. I hope it meets with the rules of asking questions.
I'm in a bit of bother with an xml document (its an API returned Xml). Now it uses a multitude of internet (http based) security measures which I have worked thru and I am now able to return the the top tier of nodes that are not nested.
however there are a few nodes which are nested under these and I need to return some of these values.
I'm set on using XMLDocument to do this, and I'm not interested in using XPath.
I should also note that I'm using the .Net 4.5 environment.
Example XML
<?xml version="1.0" encoding="utf-8"?>
<results>
<Info xmlns="http://xmlns.namespace">
<title>This Title</title>
<ref>
<SetId>317</SetId>
</ref>
<source>
<name>file.xxx</name>
<type>thisType</type>
<hash>cc7b99599c1bebfc4b8f12e47aba3f76</hash>
<pers>65.97602</pers>
<time>02:20:02.8527777</time>
</source>
....... Continuation which is same as above
Ok so above is the Xml that gets returned from the API, now, I can return title node no problem. What I would also like to return is any of the node values in the Element, for example the pers node value. But I only want to return one (as there are many in the existing xml further down)
Please note that there is an xmlns in the Info node which may not be allowing me to return the values.
So here is my code
using (var response = (HttpWebResponse) request.GetResponse())
{
//Get the response stream
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
var xDoc = new XmlDocument();
var nsm = new XmlNamespaceManager(xDoc.NameTable);
nsm.AddNamespace("ns", XmlNamespace);
//Read the response stream
using (XmlReader xmlReader = XmlReader.Create(stream))
{
// This is straight forward, we just need to read the XML document and return the bits we need.
xDoc.Load(xmlReader);
XmlElement root = xDoc.DocumentElement;
var cNodes = root.SelectNodes("/results/ns:Info", nsm);
//Create a new instance of Info so that we can store any data found in the Info Properties.
var info = new Info();
// Now we have a collection of Info objects
foreach (XmlNode node in cNodes)
{
// Do some parsing or other relevant filtering here
var title = node["title"];
if (title != null)
{
info.Title = title.InnerText;
_logger.Info("This is the title returned ############# {0}", info.Title);
}
//This is the bit that is killing me as i can't return the any values in the of the sub nodes
XmlNodeList sourceNodes = node.SelectNodes("source");
foreach (XmlNode sn in sourceNodes)
{
XmlNode source = sn.SelectSingleNode("source");
{
var pers = root["pers"];
if (pers != null) info.pers = pers.InnerText;
_logger.Info("############FPS = {0}", info.pers);
}
}
}
}
Thanks in advance for any help
So I finally figured it out.
Here is the code that gets the subnodes. Basically I wasn't using my namespace identifier or my namespace for returning subnodes within the "Source" node.
For anybody else in this situation,
When you declare your name space there are to parts to it, a namespace identifier which is anything you want it to be in my case I chose "ns" and then the actual namespace in the XML file which is prefixed by xmlns and will contain something like for example: "http://xmlns.mynamespace".
So when searching subnodes inside the top level you need to declare these namespaces for the main node of the subnode you want to get.
// get the <source> subnode using the namespace to returns all <source> values
var source = node.SelectSingleNode("ns:source", nsm);
if (source != null)
{
info.SourceType = source["type"].InnerText;
info.Pers = source["pers"].InnerText;
_logger.Info("This SourceNode is {0}", info.SourceType);
_logger.Info("This PersNode is {0}", info.FramesPerSecond);
}
I hope this helps somebody else that's chasing their tails as I have.
Thanks

Properties in PublishTransactionFilterData to narrow down the search using Tridion Core Services

I am using Tridion Core Service to get all the Components published from a publication on a specific target. The code is as below.Since there can be lot of components and the result obtained using this code contains all items, Is there any way to narrow down the results (like providing ItemType and recursive as false).
var filter = new PublishTransactionsFilterData
{
PublicationTarget = new LinkToPublicationTargetData { IdRef = targetId },
ForRepository = new LinkToRepositoryData { IdRef = GetPublication(publicationId)},
BaseColumns = ListBaseColumns.IdAndTitle,
};
XElement t= Instance.GetSystemWideListXml(filter);
var v = t.Elements().Where(k => k.Attribute("ItemType").Value == "16");
First of all your code will always return null, as because of ListBaseColumns.IdAndTitle there will be no ItemType attribute. The only way to narrow down the results are properties you can find on PublishTransactionsFilterData, which are:
EndDate, StartDate to search only inside this timestamp
Priority, if you know it
PublishedBy, if you know who published it
All the rest is post filtering, which is also ok. You can filter on everything you have in XML. Sample XML looks like this:
<tcm:Item ID="tcm:0-241-66560" Title="page" Allow="24576" Deny="67108864" Icon="T64L0P0" ItemType="64" ItemID="tcm:2-72-64" State="4" StateChangeDate="2013-03-11T14:53:55" Publication="Test" PublicationTarget="Local" ItemPath="\Test\New Structure Group" Action="0" ScheduleDate="" UserId="tcm:0-11-65552" User="domain\user" Priority="4" Managed="0" />
You can postfilter on any of the attributes

Extracting userid from Inbound headers

I have to read element from Inbound Header...
I am assigning inbound header using WCF.InboundHeaders to a string....
now my problem is my inbounde header is looking like this
InboundHeaders
<headers><s:userid xmlns:s="http://www.w3.org/2003/05/soap-envelope">testuser</s:userid>
<s:applicationid xmlns:s="http://www.w3.org/2003/05/soap-envelope">assistworkerweb</s:applicationid>
<a:Action s:mustUnderstand="1" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">http://Request</a:Action><a:To s:mustUnderstand="1" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
Now i need to extract user id from it ..how to extract user id from it..
You haven't mentioned where or how your string is stored (that is populated with your WCF.InboundHeaders), however I would use a simple fragment of XPath to extract the UserId. If you were extracting this using a C# helper, you could do something along the lines of (note, this is untested, however its pretty much there):
XmlDocument doc = new XmlDocument();
doc.Load([WCF.InboundHeaders Xml Fragment]);
// Create an XmlNamespaceManager to add 'soap-envelope' namespace
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
// Select the UserId
XmlNode userId = doc.SelectSingleNode("/headers/s:userid", nsmgr);
Console.WriteLine(userId.InnerXml);
You may also want to serialize the Xml fragment into a .Net object and retrieve the UserId in that manner.

How to ignore comments when parsing xml in asp.net

Seems like this should be easy, but I'm not finding a simple configuration setting. Basically I have a page that will be parsing xml files that may have some comment tags in them. I'm loading it as an xml doc and looping through a particular node of the document and I'm running into problems because it's counting the comment as a child node. Any way to tell asp.net not to look at comments other than writing my own check for <!-- ?
If you use XmlNode, then that has a NodeType property. Ignore the nodes where that has a value of "Comment".
An XNode has the same property.
Use XmlReaderSettings.IgnoreComments:
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreComments = true;
using (XmlReader reader = XmlReader.Create("input.xml", readerSettings))
{
XmlDocument myData = new XmlDocument();
myData.Load(reader);
// etc...
}

How to generate an XML file

I need to create an xml file here
bool result= false;
How to achieve this in ASP.NET with C# syntax. result is value that I need to add in the XML file.
I need to create an XML file under a folder with contents like this
<?xml version="1.0" encoding="utf-8" ?>
<user>
<Authenticated>yes</Authenticated>
</user>
thank you
XElement xml = new XElement("user",
new XElement("Authenticated","Yes"))
);
xml.Save(savePath);
It works for .net 3 and above, but
You can use XmlDocument for later versions
XmlDocument xmlDoc = new XmlDocument();
// Write down the XML declaration
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0","utf-8",null);
// Create the root element
XmlElement rootNode = xmlDoc.CreateElement("user");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
xmlDoc.AppendChild(rootNode);
// Create the required nodes
XmlElement mainNode = xmlDoc.CreateElement("Authenticated");
XmlText yesText= xmlDoc.CreateTextNode("Yes");
mainNode.AppendChild(yesText);
rootNode.AppendChild(mainNode);
xmlDoc.Save(savePath);
You can use XmlWriter too as suggests #marc_s or at least you can store xml to the file like sting
using(StreamWriter sw = new StreamWriter(savePath))
{
sw.Write(string.Format("<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<user><Authenticated>{0}</Authenticated></user>","Yes"));
}
How about this:
XmlTextWriter xtw = new XmlTextWriter(#"yourfilename.xml", Encoding.UTF8);
xtw.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
xtw.WriteStartElement("user");
xtw.WriteStartElement("Authenticated");
xtw.WriteValue(result);
xtw.WriteEndElement(); // Authenticated
xtw.WriteEndElement(); // user
xtw.Flush();
xtw.Close();
Or if you prefer to build up your XML file in memory, you can also use the XmlDocument class and its methods:
// Create XmlDocument and add processing instruction
XmlDocument xdoc = new XmlDocument();
xdoc.AppendChild(xdoc.CreateProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
// generate <user> element
XmlElement userElement = xdoc.CreateElement("user");
// create <Authenticated> subelement and set it's InnerText to the result value
XmlElement authElement = xdoc.CreateElement("Authenticated");
authElement.InnerText = result.ToString();
// add the <Authenticated> node as a child to the <user> node
userElement.AppendChild(authElement);
// add the <user> node to the XmlDocument
xdoc.AppendChild(userElement);
// save to file
xdoc.Save(#"C:\yourtargetfile.xml");
Should work on any version of the .NET framework, if you have a using System.Xml; clause at the top of your file.
Marc
If you want to generate the XML and then give the user a choice to save the XML in their workstation, check the post below. It explains that process in detail.
Generating XML in Memory Stream and download

Resources