I have an xml file as following:
<?xml version="1.0" encoding="utf-8"?>
<ABC version="1" xmlns="urn:Company">
</ABC>
I am releasing version 2 and the namespace changed to "NewCompany".
How do you update the namespace?
I tried
XmlDocument xmlDocument = new XmlDocument();
using (XmlReader xmlReader = XmlReader.Create("myfile.xml"))
{
xmlDocument.Load(xmlReader);
}
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("ABC");
if (nodeList.Count == 1)
{
XmlElement element = nodeList.Item(0) as XmlElement;
if (element != null)
{
element.SetAttribute("xmlns", "NewCompany");
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("myfile.xml", settings))
{
xmlDocument.WriteTo(writer);
}
}
}
But I get
"The prefix '' cannot be redefined from to within the same start element tag."
exception
I ran into this today and found a workaround. If you use XmlTextWriter instead of XmlWriter, the problem goes away. Your code sample would look something like this:
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("ABC");
if (nodeList.Count == 1)
{
XmlElement element = nodeList.Item(0) as XmlElement;
if (element != null)
{
element.SetAttribute("xmlns", "NewCompany");
using (XmlTextWriter writer = new XmlTextWriter("myfile.xml", Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
xmlDocument.WriteTo(writer);
}
}
}
I'd have imagined that XmlWriter.Create will simply return a XmlTextWriter, but that doesn't seem to be the case. From looking around in Reflector, XmlWriter.Create seems to return concrete types different from XmlTextWriter.
XmlTextWriter seems to support changing the namespace of the document element, while the writer returned by XmlWriter.Create doesn't.
I realize that this question is four years old, but perhaps my answer will help someone.
Related
My json file is mostly an array that contain objects but the list is incomplete, so I can't use the last entry. I would like to deserialize the rest of the file while discarding the last invalid entry
[ { "key" : "value1" }, { "key " : "value2"}, { "key
Please tell me if there is a way using Newtonsoft.Json library, or do I need some preprocessing.
Thank you!
Looks like on Json.NET 8.0.3 you can stream your string from a JsonTextReader to a JTokenWriter and get a partial result by catching and swallowing the JsonReaderException that gets thrown when parsing the truncated JSON:
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
Debug.WriteLine(ex);
}
root = jsonWriter.Token;
}
Console.WriteLine(root);
if (exceptionPath != null)
{
Console.WriteLine("Error occurred with token: ");
var badToken = root.SelectToken(exceptionPath);
Console.WriteLine(badToken);
}
This results in:
[
{
"key": "value1"
},
{
"key ": "value2"
},
{}
]
You could then finish deserializing the partial object with JToken.ToObject. You could also delete the incomplete array entry by using badToken.Remove().
It would be better practice not to generate invalid JSON in the first place though. I'm also not entirely sure this is documented functionality of Json.NET, and thus it might not work with future versions of Json.NET. (E.g. conceivably Newtonsoft could change their algorithm such that JTokenWriter.Token is only set when writing is successful.)
You can use the JsonReader class and try to parse as far as you get. Something like the code below will parse as many properties as it gets and then throw an exception. This is of course if you want to deserialize into a concrete class.
public Partial FromJson(JsonReader reader)
{
while (reader.Read())
{
// Break on EndObject
if (reader.TokenType == JsonToken.EndObject)
break;
// Only look for properties
if (reader.TokenType != JsonToken.PropertyName)
continue;
switch ((string) reader.Value)
{
case "Id":
reader.Read();
Id = Convert.ToInt16(reader.Value);
break;
case "Name":
reader.Read();
Name = Convert.ToString(reader.Value);
break;
}
}
return this;
}
Code taken from the CGbR JSON Target.
the second answer above is really good and simple, helped me out!
static string FixPartialJson(string badJson)
{
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
}
root = jsonWriter.Token;
}
return root.ToString();
}
I'm trying to read java generated JSON stream created by out.writeBytes with my Xpage. I can get data like getServerPort and others (listed in code below) but when I'm trying to read context with BufferedReader or ServletInputStream I'm reciving errors.
Any one knows simple way to read stream content like that on Xpage ? readLine method returned null.
var exCon = facesContext.getExternalContext()
var httpRequest:javax.faces.contex.ExternalContext =exCon.getRequest();
print("CallCenter getContext "+String(exCon.getContext()))
print("CallCenter ContentType "+String(httpRequest.getContentType()))
print("CallCenter ContentLength"+String(httpRequest.getContentLength()))
print("CallCenter RemoteAddr "+String(httpRequest.getRemoteAddr() ))
print("CallCenter ServerPort "+String(httpRequest.getServerPort()))
facesContext.responseComplete();
// ONE OF METHODS I've TRIED =============
var stringBuffer:java.lang.StringBuffer = new java.lang.StringBuffer(80);
var line = null;
var reader:java.io.BufferedReader = httpRequest.getReader();
while ((line = reader.readLine()) != null)
{
stringBuffer.append(line);
stringBuffer.append("\n");
}
print("Buffer "+stringBuffer.toString());
// ============================
} catch(e) {
_dump(e);
fdf
There can only be one: the stream or the reader. Instead of getReader() use new InputStreamReader(in); point in to the inputstream of the context
I hope anybody can help me.
My problem is that I get XML with html entities for special charakters like:
<person>
<firstname>Max</firstname>
<lastname>Müller</lastname>
</person>
<person>
<firstname>Bernd</firstname>
<lastname>Schäfer</lastname>
</person>
I find no way in QT to decode the "ü" to a normal "ü". In the QT-DomTree this entity will stand in a QDomEntityRefrence object wich has no getter or other output or parse functionality.
I use standard way to parse the XML tree
QDomDocument doc;
if (!doc.setContent(response, &errors))
return false;
QDomElement const & root = doc.firstChildElement("person");
for (QDomElement xmlPerson= root.firstChildElement("person"); !xmlPerson.isNull(); xmlPerson = xmlPerson.nextSiblingElement("person"))
{
QDomNodeList personCont = xmlPerson.childNodes();
PersonObj person;
for(int i = 0; i < personCont.count(); i++)
{
QDomNode itemNode = personCont.at(i);
if(itemNode.isElement()){
QDomElement item = itemNode.toElement();
if(item.tagName() == "firstname")
{
person.setFirstname(item.firstChild().text());
}
else if(item.tagName() == "lastname")
{
addressBook.setLastname(item.firstChild().text());
}
...
Result:
Max Mller
Bernd Schfer
Thanks for your greate awnsers
Use QTextDocument()
QTextDocument doc;
doc.setHtml("Schäfer");
qDebug()<<doc.toPlainText();
In your example
QTextDocument doc;
switch(item.tagName())
{
case "firstname":
doc.setHtml(item.firstChild().text());
person.setFirstname(doc.toPlainText());
break;
case "lastname":
doc.setHtml(item.firstChild().text());
addressBook.setLastname(doc.toPlainText());
break;
...
I'm using the HTML Agility Pack and Selenium to crawl a site, find particular tables, and then parse those tables. Everything works fine individually, but when I run the app, it sometimes drops huge chunks of HTML from within the table. When I track down the page on the site with the data, the HTML is there. For whatever reason, it isn't there when the crawler is running.
Here's the code. The rows[r].InnerHtml is NOT the HTML from page. Anyone have any thoughts on what might be happening here?
public IMyInterface CreateObjectFromHtmlRow(HtmlNode rowNode)
{
try
{
var columns = rowNode.SelectNodes("td");
MyClass obj = new MyClass()
{
OnlineId = columns[0].InnerText.Trim(),
FirstName = columns[1].InnerText.Trim(),
MiddleInitial = columns[2].InnerText.Trim(),
LastName = columns[3].InnerText.Trim(),
Residence = columns[4].InnerText.Trim(),
};
return obj;
}
catch (Exception exc)
{
_logger.LogFormat("Error trying to parse row: {0}", exc.Message);
return null;
}
}
IMyInterface obj = null;
obj = _repository.CreateObjectFromHtmlRow(rows[r]);
if (obj == null)
{
_logger.LogFormat("Unable to create object from this data: {0}", rows[r].InnerHtml);
}
else
{
// Do something useful
}
Thanks for your help.
WW
I would like to read a dynamic object from a json file and then use this in a stringTemplate.
The following code works.
dynamic data = new { bcName = "Lixam B.V", periodName = "July 2013" };
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013");
The following code fails
var json = "{bcName : 'Lixam B.V', periodName : 'July 2013'}";
dynamic data = JsonConvert.DeserializeObject(json);
string name = (data.bcName);
name.Should().Be("Lixam B.V"); // this passes
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013"); //fails
Is there another way to configure JsonConverter to be compatible with StringTemplate
You need to create an IModelAdaptor for whatever the compiled type representing dynamic is, and register it using TemplateGroup.RegisterModelAdaptor.
Inspired on Mr. Harwell's answer, I've implemented an IModelAdaptor that enable the usage of Newtonsoft.Json parsed objects.
Here it goes:
internal class JTokenModelAdaptor : Antlr4.StringTemplate.IModelAdaptor
{
public object GetProperty(
Antlr4.StringTemplate.Interpreter interpreter,
Antlr4.StringTemplate.TemplateFrame frame,
object obj,
object property,
string propertyName)
{
var token = (obj as JToken)?.SelectToken(propertyName);
if (token == null)
return null;
if (token is JValue)
{
var jval = token as JValue;
return jval.Value;
}
return token;
}
}
You just need to register the adaptor in your template group, like this:
template.Group.RegisterModelAdaptor(typeof(JToken), new JTokenModelAdaptor());