Say I have two variables (value1 and value2) and either could be nil, how can I create an element using XmlMarkup and only add the attributes that are not nil?
If I do this
xm = Builder::XmlMarkup.new
xm.item(:attribute1=>value1, :attribute2=>value2)
and both value1 and value2 are nil, I still get
<item attribute1="", attribute2=""/>
I have also tried to add the attributes after creating the element but had no success and I cannot figure out if this is even supported.
If it is not already apparent, I am a complete ruby beginner so any input would be appreciated.
I think something like this could work:
xm = Builder::XmlMarkup.new
attributes = {}
attributes[:attribute1] = value1 if value1
attributes[:attribute2] = value2 if value2
xm.item(attributes)
If you have more than a couple of attributes I can show you a way to minimize duplication with a similar method too.
Related
I have the following XML payload:
<fizz>
<buzz class="foo">
<whatever/>
</buzz>
</fizz>
The value of the /fizz/buzz[#class]/#class attribute can be foo, bar or whistlefeather. I'm trying to write an efficient XPath expression that covers all three scenarios. The best I have is:
/fizz/buzz[#class]/#class = 'foo' |
/fizz/buzz[#class]/#class = 'bar' |
/fizz/buzz[#class]/#class = 'whistlefeather'
Is there some "shorthand" way to make this more condense/efficient (less verbose)?
Using this (all xpath version) :
/fizz/buzz[#class='foo' or #class='bar' or #class='whistlefeather']
Using xpath >=2 :
/fizz/buzz[#class=("foo", "bar", "whistlefeather")]
Correcting the answer from #GillesQuenot:
Using any XPath version:
/fizz/buzz[#class='foo' or #class='bar' or #class='whistlefeather']
Using XPath 2.0 or later:
/fizz/buzz[#class=("foo", "bar", "whistlefeather")]
(Note, this returns the selected buzz elements. It's unclear what you actually want the expression to return.)
I have a string which looks like the following:
string = " <SET-TOPIC>INITIATE</SET-TOPIC>
<SETPROFILE>
<PROFILE-KEY>predicates_live</PROFILE-KEY>
<PROFILE-VALUE>yes</PROFILE-VALUE>
</SETPROFILE>
<think>
<set><name>first_time_initiate</name>yes</set>
</think>
<SETPROFILE>
<PROFILE-KEY>first_time_initiate</PROFILE-KEY>
<PROFILE-VALUE>YES</PROFILE-VALUE>
</SETPROFILE>"
My objective is to be able to read out each top level that is in caps with the parse. I use a case statement to evaluate what is the top level key, such as <SETPROFILE> but there can be lots of different values, and then run a method that does different things with the contnts of the tag.
What this means is I need to be able to know very easily:
top_level_keys = ['SET-TOPIC', 'SET-PROFILE', 'SET-PROFILE']
when I pass in the key know the full value
parsed[0].value = {:PROFILE-KEY => predicates_live, :PROFILE-VALUE => yes}
parsed[0].key = ['SET-TOPIC']
I currently parse the whole string as follows:
doc = Nokogiri::XML::DocumentFragment.parse(string)
parsed = doc.search('*').each_with_object({}){ |n, h|
h[n.name] = n.text
}
As a result, I only parse and know of the second tag. The values from the first tag do not show up in the parsed variable.
I have control over what the tags are, if that helps.
But I need to be able to parse and know the contents of both tag as a result of the parse because I need to apply a method for each instance of the node.
Note: the string also contains just regular text, both before, in between, and after the XML-like tags.
It depends on what you are going to achieve. The problem is that you are overriding hash keys by new values. The easiest way to collect values is to store them in array:
parsed = doc.search('*').each_with_object({}) do |n, h|
# h[n.name] = n.text :: removed because it overrides values
(h[n.name] ||= []) << n.text
end
I have the following code that's repeated:
var ccaNumber = (from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber
Ideally, I want to create the above as an expression then add my clause to the end of it.
So, I created the expression as follows:
Expression currExp = from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber;
I now want to combine them:
var ccaNumber = (currExp select r.Element("CreditCardAuthorityNumber").Value).FirstOrDefault();
However I now get the following error:
Invalid expression term ')'
Any suggestions?
ta,
yogi
I think you are mixing things up here.
What you can do is:
var items = from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber
select r;
This declares items as a Enumerable of elements that match your Where-Condition.
And then you can use those defined items like this:
var ccaNumber = items.Select(item=>item.Element("CreditCardAuthorityNumber").Value).FirstOrDefault();
However, this is all utilising lazy evaluation and you need to take care of multiple enumerations here. Here is a pretty indepth explanaition that is way better than my sh*tty english.
When adding to an existing expression, you need to use the lambda syntax, not the Linq syntax:.
Try:
var ccaNumber = (currExp
.Select(r=>r.Element("CreditCardAuthorityNumber").Value))
.FirstOrDefault();
I'm working on a configuration file parser and I need help parsing key: value pairs into a hash.
I have data in the form of: key: value key2: value2 another_key: another_value.
So far I have code in form of
line = line.strip!.split(':\s+')
which returns an array in the form of
["key:value"]["key2: value2"]["another_key: another_value"]
How can I turn these arrays into a single hash in the form of
{key=>value, key2=>value2, another_key=>another_value}
I'm not sure if the key:value pairs need to be in the form of a string or not. Whatever is easiest to work with.
Thanks for your help!
This is the solution I found:
line = line.strip.split(':')
hash = Hash[*line]
which results in the output{"key"=>"value"}, {"key2"=>"value2"}
Very very close to Cary's solution:
Hash[*line.delete(':').split]
Even simpler:
Hash[*line.gsub(':',' ').split]
# => {"key"=>"value", "key2"=>"value2", "another_key"=>"another_value"}
Assuming the key and value are single words, I'd probably do something like this:
Hash[line.scan(/(\w+):\s?(\w+)/)]
You can change the regex if it's not quite what you are looking for.
I have been using kivy but need help with a problem. I try to run this
def go(self, value, value2):
self.value2.source = 'Graphics\\Tiles\\' + value + '.png'
But every time it tells me value2 is not a property for newgame(my class). It works if I give the image name but I need to make it identify value2 as an argument. How do I do this?
If you are sending value2 as parameter you shouldn't use self, like this:
def go(self, value, value2):
value2.source = 'Graphics\\Tiles\\' + value + '.png'
The error you are getting is because value2 is not defined anywhere else on your class.