I have the following XML structure:
<Order>
<Mats>
<mat>
<item>
<imgsrc>img_0</imgsrc>
<cid>cid_0</cid>
</item>
</mat>
<mat>
<item>
<imgsrc>img_1</imgsrc>
<cid>cid_1</cid>
</item>
</mat>
</Mats>
</Order>
In Flex, I am trying to get the first imgsrc and first cid. This is what I have so far:
public function globals_get_default_matte():void
{
var defaults_matte_loader:XMLLoader = new XMLLoader();
defaults_matte_loader.url = Globals.defaultMatteXMLURL;
defaults_matte_loader.loadXML();
defaults_matte_loader.addEventListener("dataWritten",globals_get_default_matte_result_handler);
}
public function globals_get_default_matte_result_handler(e:Event):void
{
var _xml:XML = new XML(e.currentTarget.data);
if (_xml)
{
var mattes_list:XMLList = _xml.elements("Mats");
var matte0:XML = mattes_list[0][0][0] as XML;
trace(mattes_list);
trace(matte0);
trace(matte0.childNodes);
}
}
In the Expressions tab, matte0.childNodes gives:
errors during evaluation
This is not doing what you want:
var mattes_list:XMLList = _xml.elements("Mats");
var matte0:XML = mattes_list[0][0][0] as XML;
mattes_list lists the <Mats> node, then matte0 does nothing more than select the first (and only) <Mats> node. Meanwhile, childNodes is not a property of XML, but the legacy XMLNode object, which you aren't using.
You should familiarize yourself with e4x in AS3. It's more like a query selector syntax.
To list the <mat> nodes and retrieve the first <cid> node, you can do this:
var mattes_list:XMLList = _xml.Mats.mat;
var matte0_cid:XML = mattes_list[0].item.cid[0];
Related
Trying to convert a json string to key value pairs using Newtonsoft but no luck so far.
Response from the API:
var response = #"{'result':{'0199 - B344EE33':
{
'6400_00260100':{'1':[{'val':336688}]},
'6400_00462500':{'1':[{'val':null}]},
'6800_00832A00':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_008AA200':{'1':[{'low':0,'high':null,'val':0}]}
}}}";
Result I want is a new object of key value pairs:
{
"6400_00260100" : 336688,
"6400_00462500" : null,
"6800_00832A00" : 3000,
"6800_008AA200" : 0
}
In the response the result will always be the first and only prop. In the next level the code 0199 - B344EE33 can change but there will be only one prop in this level so we can always take the first one. Then in the last level we always need the val property.
What I have is the following but for getting the key value pairs in a clean way I got stuck:
var json = JObject.Parse(response);
var result = json["result"].First;
var path = result.Path;
UPDATE
var jObjectResult = new JObject();
var response = #"{'result':{'0199 - B344EE33':
{
'6800_10821E00':{'1':[{'val':'SMA Sunny Boy'}]},
'6800_00A21E00':{'1':[{'val':'3.0.0.2222'}]},
'6800_00823400':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_08822B00':{'1':[{'val':'SMA'}]},
'6800_08822000':{'1':[{'val':'Sunny Boy 3.0'}]}
}}}";
var json = JObject.Parse(response);
var json_serial = json["result"].First.Children<JObject>().ToList()[0];
foreach(var token in json_serial)
{
var tokenKey = token.Key;
var tokenVal = token.Value.SelectToken("$.1[0].val");
jObjectResult.Add(tokenKey, tokenVal);
}
You could use SelectTokens with the recursive descent operator .. to find all the val properties, then walk up the chain using .Parent repeatedly to get the corresponding key. Create new JProperties from this information and put them into a new JObject to get your result. Here is a "one-liner":
var result = new JObject(
JObject.Parse(response)
.SelectTokens("$..val")
.Select(jt => new JProperty(
((JProperty)jt.Parent.Parent.Parent.Parent.Parent.Parent).Name,
jt
))
);
Fiddle: https://dotnetfiddle.net/TbZ7LS
At the end with some pointers form #Brian Rogers I came with the following solution:
// Arrange
var response = #"{'result':{'0199 - B344EE33':
{
'6800_10821E00':{'1':[{'val':'SMA Sunny Boy'}]},
'6800_00A21E00':{'1':[{'val':'3.0.0.2222'}]},
'6800_00823400':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_08822B00':{'1':[{'val':'SMA'}]},
'6800_08822000':{'1':[{'val':'Sunny Boy 3.0'}]}
}}}";
// Act
var json = JObject.Parse(response);
var json_serial = (JProperty)json["result"].First();
var jObjectResult = new JObject(
json_serial.Value.Select(p =>
{
return new JProperty(
((JProperty)p).Name,
p.First.SelectToken("$.1[0].val")
);
}));
Is there a simpler way to do this? I am sincerely concerned that this LinqPad doodle might be too verbose:
var xml = #"
<root attr1=""attribute one"" attr2=""attribute two"">
<title>this is the root</title>
<xhtml>
<div id=""wrapper"">
<p style=""first""><em>hello</em> world!</p>
</div>
</xhtml>
</root>
";
var xDoc = XDocument.Parse(xml);
Func<XNode, string> getXhtml = node =>
{
var s = string.Empty;
StringWriter wr = null;
try
{
wr = new StringWriter();
using(var jsonWriter = new JsonTextWriter(wr))
{
jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
new JsonSerializer().Serialize(jsonWriter, node.ToString());
}
s = wr.ToString();
}
finally
{
if(wr != null) wr.Dispose();
}
return s;
};
var escaped_xhtml = getXhtml(xDoc.Root.Element("xhtml").Element("div"));
escaped_xhtml.Dump("escaped xhtml");
var placeholder = "#rx-xhtml";
xDoc.Root.Element("xhtml").Value = placeholder;
var json = JsonConvert.SerializeXNode(xDoc.Root, Newtonsoft.Json.Formatting.Indented);
var json_final =json
.Replace(string.Format(#"""{0}""",placeholder), escaped_xhtml);
json_final.Dump("json with escaped xhtml");
var jDoc = JObject.Parse(json_final);
escaped_xhtml = (string)jDoc["root"]["xhtml"];
escaped_xhtml.Dump("decoded xhtml");
It may be reasonable to assume that JSON.NET already has, say, the equivalent of my getXhtml() routine. JSON.NET has so many great features I am concerned that I might be missing out.
Is this what you want? It produces the same result for json_final:
// Parse the XML
var xDoc = XDocument.Parse(xml);
// Extract the "div" element.
var div = xDoc.Root.Element("xhtml").Element("div");
div.Remove();
// Convert the remainder to a JObject.
var jDoc = JObject.FromObject(xDoc.Root, JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = new[] { new XmlNodeConverter() } }));
// Store the Div element as a string literal.
jDoc["root"]["xhtml"] = div.ToString();
// Stringify the JSON using StringEscapeHandling = StringEscapeHandling.EscapeHtml
var json_final = JsonConvert.SerializeObject(jDoc, new JsonSerializerSettings { Formatting = Formatting.Indented, StringEscapeHandling = StringEscapeHandling.EscapeHtml });
It eliminates the string replacement and the getXhtml delegate. Note that StringEscapeHandling applies during the final conversion to string, not to intermediate conversions to Joken (where string literals are not escaped).
Even simpler still, replace the <Div> element with a corresponding XML string literal before converting to JSON:
// Parse the XML
var xDoc = XDocument.Parse(xml);
// Replace the DIV element with its XML string literal value
var div = xDoc.Root.Element("xhtml").Element("div");
div.Remove();
xDoc.Root.Element("xhtml").Value = div.ToString();
// Convert to JSON using StringEscapeHandling = StringEscapeHandling.EscapeHtml
var json_final = JsonConvert.SerializeObject(xDoc, new JsonSerializerSettings { Converters = new[] { new XmlNodeConverter() }, Formatting = Formatting.Indented, StringEscapeHandling = StringEscapeHandling.EscapeHtml });
So, I have this HTML-form that I want to fill in with the names of the US states. I have all of 50 of them (Alabama to Wyoming) stored in the following format:
<?xml version="1.0"?>
<states xml:lang="EN">
<item>
<label>Alabama</label>
<value>AL</value>
</item>
<item>
<label>Alaska</label>
<value>AK</value>
</item>
...
When the user starts typing "Ne", the script would list in a pop-box the suggestions Nebraska, Nevada, New Hampshire, New Jersey, etc. As the user continues typing: "New", the list of suggestions would narrow down to New Hampshire, New Jersey, New Mexico, New York, until there is only one state left. What AJAX should I use to get this thing working?
function ajaxFunction(str) {
if (str.length==0) {
document.getElementById("search").innerHTML="";
document.getElementById("search").style.border="0px";
return;
}
var input=document.getElementById('text1').value;
var ajaxRequest = new XMLHttpRequest();
ajaxRequest.onreadystatechange = function() {
if (ajaxRequest.readyState==4 && ajaxRequest.status==200) {
var res=ajaxRequest.responseXML;
var states=res.getElementsByTagName("states");
var elem=states[0];
var items=res.getElementsByTagName("item");
document.getElementById("search").innerHTML="";
for(var i=0;i<items.length;i++){
var item=items[i].getElementsByTagName("label");
var state=item[0].innerHTML;
var len=str.length;
var match=state.substr(0,len);
if(match.toUpperCase()==input.toUpperCase()){
var val=items[i].getElementsByTagName("value");
var value=val[0].innerHTML;
var e = document.createElement('span');
e.innerHTML = state+"("+value+") ";
document.getElementById("search").appendChild(e.firstChild);
}
}
document.getElementById("search").style.border="1px solid #A5ACB2";
}
}
ajaxRequest.open("GET","USA_States.xml",true);
ajaxRequest.send();
}
I have that code:
private function handleFlashVarsXmlLoaded(event:Event) : void
{
var secondsplit:String = null;
var item:Array = null;
var string:* = XML(String(event.target.data));
var notsplited:* = string.vars_CDATA; //what is .vars_CDATA?
var splitted:* = notsplitted.split("&");
var datacontainer:Object = {};
var index:Number = 0;
item = secondsplit.split("=");
datacontainer[item[0]] = item[1];
this.parseFlashVars(datacontainer); // go next
return;
}
That function is loaded when URLLoader is loaded.
I think that this function parse a XML file to string(fe. param1=arg1¶m2=arg2), then split it by "&" and then by "=" and add data to datacontainer by
datacontainer["param1"] = "arg1"
But how should the XML file look like and what is string.vars_CDATA
I think, vars_CDATA is just a name of XML field, becourse variable named "string" is contains whole XML. So var "notsplited" contains a String-typed data of this field (I think so, becourse of the line "var splitted:* = notsplitted.split("&");", which splits String to Array).
I'm trying to load a txt file of variables into my AS3 project. The problem I have though seems to be down to the fact that the txt file (which is pre formatted and cannot be changed) is formatted using double amphersands... e.g.
&name=mark&
&address=here&
&tel=12345&
I'm using the following code to load the txt file
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
trace(myLoader.data);
}
Using URLLoaderDataFormat.VARIABLES generates the following error:
Error: Error #2101: The String passed to URLVariables.decode() must be a URL-encoded query string containing name/value pairs.
If I use URLLoaderDataFormat.TEXT I can load the data successfully but I'm not able (or don't know how to) access the variables.
Would anyone have any ideas or work arounds to this please.
Thanks,
Mark
I had that kind of problem some time ago.
I suggest you to load first as a text, remove those line breaks, the extra amphersands and parse manually:
var textVariables:String;
var objectVariables:Object = new Object();
...
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.TEXT;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
textVariables = myLoader.data;
textVariables = textVariables.split("\n").join("").split("\r").join(""); // removing line breaks
textVariables = textVariables.split("&&").join("&"); // removing extra amphersands
var params:Array = textVariables.split('&');
for(var i:int=0, index=-1; i < params.length; i++)
{
var keyValuePair:String = params[i];
if((index = keyValuePair.indexOf("=")) > 0)
{
var key:String = keyValuePair.substring(0,index);
var value:String = keyValuePair.substring(index+1);
objectVariables[key] = value;
trace("[", key ,"] = ", value);
}
}
}
I wrote that code directly here, I don't have any AS3 editor here, so, maybe you'll find errors.
If you have data in String and it has a structure just like you wrote, you can do a workaround:
dataInString = dataInString.split("\n").join("").split("\r").join(""); // removing EOL
dataInString = dataInString.slice(0,-1); // removing last "&"
dataInString = dataInString.slice(0,1); // removing first "&"
var array:Array = dataInString.split("&&");
var myVariables:Object = new Object();
for each(var item:String in array) {
var pair:Array = item.split("=");
myVariables[pair[0]] = pair[1];
}
That should make you an object with proper variables.