how to change the 14th line as changed value, And then save it as .plist file! i am trying to use XmlElement and then save it, but the problem is after i save that file, the doctype line will be ,I mean the "[]" has been added at the end of doctype line which will cause issue when iPhone use this file.in c#, how to edit it in right way?
i use below code to modify .plist file:
XmlDocument doc = new XmlDocument();
string plistPath = "app.plist";
doc.Load(plistPath);
foreach (var node in doc.SelectNodes("//string"))
{
if (node is XmlElement)
{
var elem = (XmlElement)node;
if (elem.InnerText == "software-package")
{
var versionElement = elem.NextSibling.NextSibling as XmlElement;
if (versionElement != null)
{
versionElement.InnerText = "PCDownload Url";
}
}
}
}
doc.Save(plistPath);
and the DOCTYPE line will changed to:< !DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"[]> in .plist file.
I think your issue has to do with the XmlDocument.Save() method. As you already know, XML and plist files are slightly different, but the Save() method is trying to apply XML properties to your plist when saving.
Here are some options:
1) Use regular expressions. Buffer the file contents into a byte[], make your changes using regular expressions, and then write that buffer to .plist.
2) Parse the document using the XML parser, but don't use the built in Save() method. This may still result in unwanted modifications in the plist file, but it's worth a shot.
My solution was to search and replace this string and remove it using another command. Not very efficient, but gets the job done:
...
doc.Save(plistPath);
(Get-Content -path $plistPath -Raw) -replace '"\[\]>', '' | Set-Content -Path $plistPath
Check out this link as well to do the same for android and iOS:
https://gist.github.com/campbellja/e5d735f048cab76adb16957fe4a7ad75
Related
I am trying to create a word document using a word template in my C# application using openXML. Here is my code so far:
DirectoryInfo tempDir = new DirectoryInfo(Server.MapPath("~\\Files\\WordTemplates\\"));
DirectoryInfo docsDir = new DirectoryInfo(Server.MapPath("~\\Files\\FinanceDocuments\\"));
string ype = "test Merge"; //if ype string contains spaces then I get this error
string sourceFile = tempDir + "\\PaymentOrderTemplate.dotx";
string destinationFile = docsDir + "\\" + "PaymentOrder.doc";
// Create a copy of the template file and open the copy
File.Copy(sourceFile, destinationFile, true);
// create key value pair, key represents words to be replace and
//values represent values in document in place of keys.
Dictionary<string, string> keyValues = new Dictionary<string, string>();
keyValues.Add("ype", ype);
SearchAndReplace(destinationFile, keyValues);
Process.Start(destinationFile);
And the SearchAndReplace funtion:
public static void SearchAndReplace(string document, Dictionary<string, string> dict)
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (KeyValuePair<string, string> item in dict)
{
Regex regexText = new Regex(item.Key);
docText = regexText.Replace(docText, item.Value);
}
using (StreamWriter sw = new StreamWriter(
wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
But when I try to open the exported file I get this error:
XML parsing error
Location: Part: /word/document.xml, line: 2, Column: 2142
Document.xml first lines:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14">
<w:body>
<w:tbl>
<w:tblPr>
<w:tblW w:w="10348" w:ttest Merge="dxa"/>
<w:tblInd w:w="108" w:ttest Merge="dxa"/>
<w:tblBorders>
Edit
I found out that the problem occured because I was using mergefields in the word template. If I use plain text it works. But in this case it will be slow because it has to check every single word in the template and if matches replace it. Is it possible to do it in another way?
Disclaimer: You seem to be using the OpenXML SDK, because your code looks virtually identical to that found here: https://msdn.microsoft.com/en-us/library/bb508261(v=office.12).aspx - I've never in my life used this SDK and I'm basing this answer on an educated guess at what's happening
It seems that the operation you're carrying out on this Word document is affecting parts of the document that you didn't intend.
I believe that calling document.MainDocumentPart.GetStream() just giving you more or less raw direct access to the XML of the document, and you're then treating it as a plain xml file, manipulating it as text, and carrying out a list of straight text replacements? I think it's thus likely the cause of the problem because you're intending to edit document text, but accidentally damaging xml node structure in the process
By way of an example, here is a simple HTML document:
<html>
<head><title>Damage report</title></head>
<body>
<p>The soldier was shot once in the body and twice in the head</p>
</body>
</html>
You decide to run a find/replace to make the places the soldier was shot, a bit more specific:
var html = File.ReadAllText(#"c:\my.html");
html = html.Replace("body", "chest");
html = html.Replace("head", "forehead");
File.WriteAllText(#"c:\my.html");
Only thing, your document is now ruined:
<html>
<forehead><title>Damage report</title></forehead>
<chest>
<p>The soldier was shot once in the chest and twice in the forehead</p>
</chest>
</html>
A browser can't parse it (well, it's still valid I suppose, but it's meaningless) any more because the replacement operation broke some things.
You're replacing "ype" with "test Merge" but this seems to be clobbering an occurrence of the word "type" - something that it seems pretty likely would appear in the XML attribute or element names - and turning it into "ttest Merge".
To correctly change the content of an XML document's node texts, it should be parsed from text to an XML document object model representation, the nodes iterated, the texts altered, and the whole thing re-serialized back to xml text. Office SDK does seem to provide ways to do this, because you can treat a document like a collection of class object instances, and say things like this code snippet (also from MSDN):
// Create a Wordprocessing document.
using (WordprocessingDocument myDoc = WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document))
{
// Add a new main document part.
MainDocumentPart mainPart = myDoc.AddMainDocumentPart();
//Create DOM tree for simple document.
mainPart.Document = new Document();
Body body = new Body();
Paragraph p = new Paragraph();
Run r = new Run();
Text t = new Text("Hello World!");
//Append elements appropriately.
r.Append(t);
p.Append(r);
body.Append(p);
mainPart.Document.Append(body);
// Save changes to the main document part.
mainPart.Document.Save();
}
You should be looking for another way, not using streams/direct low level xml access, to access the document elements. Something like these:
https://blogs.msdn.microsoft.com/brian_jones/2009/01/28/traversing-in-the-open-xml-dom/
https://www.gemboxsoftware.com/document/articles/find-replace-word-csharp
Or possibly starting with a related SO question like this: Search And Replace Text in OPENXML (Added file) (though the answer you need may be in the something linked inside this question)
I am using this code to write to a xml document. Issue is every time I call this code it overrides previously written Tags element.
However I want to append multiple Tag elements inside the Tags elements. How can I make such sets using XmlWriter?
using (XmlWriter writer = XmlWriter.Create(path))
{
writer.WriteStartElement("Tags");
writer.WriteElementString("Tag", tagName);
writer.WriteEndElement();
}
I found out over the net few solution involving LINQ, with which I am not very good at. So I am looking something without it?
This can be done via Linq Xml by:
public void AddTagToXml(string path, string tag)
{
XDocument doc;
// Load the existing file
if (File.Exists(path)) doc = XDocument.Load(path);
else
{
// Create a new file with the parent node
doc = new XDocument(new XElement("Tags"));
}
doc.Root.Add(new XElement("tag", tag));
doc.Save(path);
}
It's not terribly efficient as the file is opened and saved on each function call, but it covers your requirements.
Trying to write some simple code and see if I can get a hang of this XML business.
public static void Save() {
XDocument doc = XDocument.Load("Repository/Test.xml");
foreach (Produs p in produse) {
// Yes there are multiple elements ('p'), have checked
XElement root = new XElement("Produs");
root.Add(new XElement("Name", p.getName()));
root.Add(new XElement("Quantity", p.getQuant().ToString()));
doc.Element("Produse").Add(root); // This "Produse" here should be the root element of the XML file, right ?
//doc.Save("Repository/Test.xml");
}
doc.Save("Repository/Test.xml"); // moved here
}
No compile, or run time error, but nothing gets changed within the file. I do read from the file, so it does work.
Extra info on the .xml file (within visual studio):
Build action: Content
Copy to output directory: Copy always
I'm using the following xml file to read the contents of a file that I need to write to:
<properties>
<url>http://www.leagueoflegends.com/service-status</url>
<content>host=beta.lol.riotgames.com
xmpp_server_url=chat.na.lol.riotgames.com
lobbyLandingURL=http://www.leagueoflegends.com/pvpnet_landing
ladderURL=http://www.leagueoflegends.com/ladders
storyPageURL=http://www.leagueoflegends.com/story
lq_uri=https://lq.na.lol.riotgames.com/login-queue/rest/queue</content>
</properties>
I have intentionally made content element to have only the newlines and nothing else (instead of proper formatting).
However when I read the content element to a string it adds several newlines and tabulators on the beginning of the lines. The result I get by writing to a text file is the following text:
<imaginary newline here>
host=beta.lol.riotgames.com
xmpp_server_url=chat.na.lol.riotgames.com
lobbyLandingURL=http://www.leagueoflegends.com/pvpnet_landing
ladderURL=http://www.leagueoflegends.com/ladders
storyPageURL=http://www.leagueoflegends.com/story
lq_uri=https://lq.na.lol.riotgames.com/login-queue/rest/queue
<imaginary newline here><additional tab here>
The issue here is that I need that text to simply start from the first line, have no tabs, no spaces, just the newlines.
The C# code behind for reading the content tag is:
XDocument root = XDocument.Parse(File.ReadAllText(file), LoadOptions.PreserveWhitespace);
PropertyFile PF = new PropertyFile();
PF.Content = (from Content in root.Descendants("content")
select (string)Content.Value).Single();
file is the path to the file, as I am able to read everything else.
Any ideas would be much appreciated.
Thanks in advance
EDIT:
PropertyFile class code ahead (content is just a string holding data for one file of a filetype I'm reading):
class PropertyFile
{
public Uri URI { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string Content { get; set; }
}
Desired output of the file is:
host=beta.lol.riotgames.com
xmpp_server_url=chat.na.lol.riotgames.com
lobbyLandingURL=http://www.leagueoflegends.com/pvpnet_landing
ladderURL=http://www.leagueoflegends.com/ladders
storyPageURL=http://www.leagueoflegends.com/story
lq_uri=https://lq.na.lol.riotgames.com/login-queue/rest/queue
By default the serialization of a XDocument/XElement formats (i.e. indents) the xml fragment.
Try using:
root.Save("Root.xml", SaveOptions.DisableFormatting);
However any DOM operations won't be involved in insignificant spaces/tabs. What you write in an element, is what you get.
Try setting the LoadOptions to None:
XDocument root = XDocument.Parse(File.ReadAllText(file), LoadOptions.None);
According to MSDN, that will ignore all insignificant whitespace.
I tried it (with just a string for your XML - I didn't bother loading it from a file) and got the following:
host=beta.lol.riotgames.com
xmpp_server_url=chat.na.lol.riotgames.com
lobbyLandingURL=http://www.leagueoflegends.com/pvpnet_landing
ladderURL=http://www.leagueoflegends.com/ladders
storyPageURL=http://www.leagueoflegends.com/story
lq_uri=https://lq.na.lol.riotgames.com/login-queue/rest/queue
Is that what you're looking for?
Edited To Add Code I Used
string xml = #"<properties>
<url>http://www.leagueoflegends.com/service-status</url>
<content>host=beta.lol.riotgames.com
xmpp_server_url=chat.na.lol.riotgames.com
lobbyLandingURL=http://www.leagueoflegends.com/pvpnet_landing
ladderURL=http://www.leagueoflegends.com/ladders
storyPageURL=http://www.leagueoflegends.com/story
lq_uri=https://lq.na.lol.riotgames.com/login-queue/rest/queue
";
XDocument root = XDocument.Parse(xml, LoadOptions.None);
var content = (from Content in root.Descendants("content")
select (string)Content.Value).Single();
What do you get if you try ...?
using System.IO;
XDocument root = XDocument.Parse(File.ReadAllText(file),
LoadOptions.PreserveWhitespace);
string content = (from Content in root.Descendants("content")
select (string)Content.Value).Single();
File.WriteAllText("SomeTempFile.txt", content);
I suspect that this text file will be formatted as you expect. This would indicate a problem with PropertyFile.
i got file which contains simple XML structure, to operate on xml i use classes bulit in framework 3.5, for string not containing backslashes everything works fine, but in case strings i try to write contain backslashes final file isn't saved to disk, no exception or any kind of error at all. No matter if i write it as parrameter or as value of node, i even tried replace "\" with "\\" with no succes. What I'm doing wrong?
to create node i use following code
public XmlElement ToXml(XmlDocument docXml){
XmlElement answer = docXml.CreateElement("datafile");
answer.SetAttribute("name", dfName);
answer.SetAttribute("path", dfPath);
answer.SetAttribute("user", dfUser);
answer.SetAttribute("pass", dfPass);
answer.SetAttribute("defalut", isDefault.ToString().ToLower());
return answer;
}
Thanks in advance for any suggestions
Paul
I tried this myself and I have no trouble whatsoever:
class Program
{
static void Main(string[] args)
{
// get a list of files
string[] files = Directory.GetFiles(#"D:\backup");
// create new XML document
XmlDocument xdoc = new XmlDocument();
// add a "root" node
xdoc.AppendChild(xdoc.CreateElement("ListOfFiles"));
foreach (string file in files)
{
xdoc.DocumentElement.AppendChild(CreateXmlElement(xdoc, file));
}
// save file
xdoc.Save(#"D:\filelist.xml");
}
private static XmlElement CreateXmlElement(XmlDocument xmldoc, string filename)
{
XmlElement result = xmldoc.CreateElement("datafile");
result.SetAttribute("name", Path.GetFileName(filename));
result.SetAttribute("path", Path.GetDirectoryName(filename));
result.SetAttribute("fullname", filename);
return result;
}
}
Gives me a nice, clean XML file as a result:
<ListOfFiles>
<datafile name="mse-01-14.zip" path="D:\backup" fullname="D:\backup\mse-01-14.zip" />
<datafile name="Vor_09.iso" path="D:\backup" fullname="D:\backup\Vor_09.iso" />
</ListOfFiles>
Not a single problem at all.
Marc
I am assuming that you are trying to put backslash for the node named "path". You can't do that.
Use CDATA section to put characters that should be ignored by XML parser.
EDIT: It seems "\" is not a reserved character and I was able to edit an existing XML file & put it as below.
And the browser renders it as expected.
<Employees xmlns="http://Employees">
<Employee id="12615" title="Architect">
<!--This is a comment-->
<Name>
<First>Nancy</First>
<Middle>J.</Middle>
<Last>Davolio</Last>
</Name>
<Street>507 - 20th Ave. E. Apt. 2A</Street>
<City>Seattle</City>
<Zip>98122</Zip>
<Country>
<Name test="\abc">U.S.A.\\\\</Name>
</Country>
<Office>5/7682</Office>
<Phone>(206) 555-9857</Phone>
<Photo>Photo.jpg</Photo>
</Employee>
</Employees>
What is the content of the variable that has backslash in it?