Mixed node in nokogiri - nokogiri

I want to make a node that has both text content and an attribute with Nokogiri. E.g. I want to produce XML:
<root blah="value">text content</root>
I try to do this with:
Nokogiri::XML::Builder.new do
root(:blah=>"value") "text content"
end
But Ruby complains with:
create-config.rb:8: syntax error, unexpected tSTRING_BEG, expecting keyword_end
root(:blah => "value") "text content"
What am I doing wrong?

I found the solution. I had to use {} and text
Nokogiri::XML::Builder.new do
root(:blah => "value") {
text("text content")
}
end

Related

Please explain this ruby code (in rails)

Basically question is about ruby syntax
class Person < ActiveRecord::Base
validates :name, presence: true #no error
end
Code Source
My 2 Questions
1
To me this code validates :name, presence: true looks a like call to a method.
How can we call a method inside class body, outside any method? I think its not possible in oops.
2
Why I am getting error in these two variations
validates (:name , presence: true) #error
or
validates (:name , {presence: true}) #error
I have added parentheses to method call, as its allowed in ruby.
First parameter is symbol and 2nd parameter is hash.
In first case I have not added curly braces to hash, as I read that if last parameter is hash you can leave curly braces, In second code I have explicitly added curly braces but still got error.
Can anyone explain this syntax.
Thanks
Edit 1
Errors
In first I am getting
product.rb:8: syntax error, unexpected ',', expecting ')' validates (:name , presence: true) # error ^
In Second I am getting
product.rb:10: syntax error, unexpected ',', expecting ')' validates (:title , {presence: true}) # error ^
1: In ruby you can call a method when defining a class:
% irb
2.2.2 :001 > class Dummy
2.2.2 :002?> puts "Making a class..."
2.2.2 :003?> def hello
2.2.2 :004?> puts "Hello"
2.2.2 :005?> end
2.2.2 :006?> end
Making a class...
=> :hello
2.2.2 :007 > d = Dummy.new
=> #<Dummy:0x000000009ebbf0>
2.2.2 :008 > d.hello
Hello
=> nil
So that's exactly what's going on.
2: You get an error because you have a space between the method name and the argument list:
% irb
2.2.3 :001 > def func(*splat)
2.2.3 :002?> puts splat.inspect
2.2.3 :003?> end
=> :func
2.2.3 :004 > func(:test, :another => :test)
[:test, {:another=>:test}]
=> nil
2.2.3 :005 > func (:test)
[:test]
=> nil
2.2.3 :006 > func (:test, :another => :test)
SyntaxError: (irb):6: syntax error, unexpected ',', expecting ')'
func (:test, :another => :test)
^
from /home/haraldei/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
The second example above, where I'm passing just one arg works because you can enclose any valid expression in parenthesis. This is not the same as an argument list. So the expression:
(:test, :another => :test)
is not a valid expression, but the parser tries to pass it as one parenthesized argument to the method.
So to summarize, both your argument lists are correct, if you remove the space between them and the function name.
The answer to your first question: "Yes it is a method" and this is also somehow the answer to your second question.
The answer to your second question is "remove the space between validates and (". When having validates (...) it will throw
syntax error, unexpected ',', expecting ')' (SyntaxError)
validates (:name , presence: true)
validates is a method, and if using parentheses you mustn't use spaces.

REXML::Document.new take a simple string as good doc?

I would like to check if the xml is valid. So, here is my code
require 'rexml/document'
begin
def valid_xml?(xml)
REXML::Document.new(xml)
rescue REXML::ParseException
return nil
end
bad_xml_2=%{aasdasdasd}
if(valid_xml?(bad_xml_2) == nil)
puts("bad xml")
raise "bad xml"
end
puts("good_xml")
rescue Exception => e
puts("exception" + e.message)
end
and it returns good_xml as result. Did I do something wrong? It will return bad_xml if the string is
bad_xml = %{
<tasks>
<pending>
<entry>Grocery Shopping</entry>
<done>
<entry>Dry Cleaning</entry>
</tasks>}
Personally, I'd recommend using Nokogiri, as it's the defacto standard for XML/HTML parsing in Ruby. Using it to parse a malformed document:
require 'nokogiri'
doc = Nokogiri::XML('<xml><foo><bar></xml>')
doc.errors # => [#<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: bar line 1 and xml>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag foo line 1>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag xml line 1>]
If I parse a document that is well-formed:
doc = Nokogiri::XML('<xml><foo/><bar/></xml>')
doc.errors # => []
REXML treats a simple string as a valid XML with no root node:
xml = REXML::Document.new('aasdasdasd')
# => <UNDEFINED> ... </>
It does not however treat illegal XML (with mismatching tags, for example) as a valid XML, and throws an exception.
REXML::Document.new(bad_xml)
# REXML::ParseException: #<REXML::ParseException: Missing end tag for 'done' (got "tasks")
It is missing an end-tag to <done> - so it is not valid.

problems in building xml using Nokogiri in rails 4

I need to build the following xml data
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:description7a.services.chrome.com">
<soapenv:Header/>
<soapenv:Body>
<urn:VehicleDescriptionRequest>
<urn:accountInfo number="test" secret="test" country="US" language="en" behalfOf="test"/>
<!--You have a CHOICE of the next 3 items at this level-->
<!--Optional:-->
<urn:styleId>test</urn:styleId>
<urn:switch>ShowAvailableEquipment</urn:switch>
<urn:includeMediaGallery>Both</urn:includeMediaGallery>
</urn:VehicleDescriptionRequest>
</soapenv:Body>
</soapenv:Envelope>
I am using the following code to build it
def self.xml_build(style_id,number,secret,behalfOf)
builder = Nokogiri::XML::Builder.new do |xml|
xml.send("soapenv:Envelope"){
xml.send("soapenv:Header")
xml.send("soapenv:Body") {
xml.send("urn:VehicleDescriptionRequest"){
xml.send("urn:accountInfo")("number"=>"#{number}" "secret"=>"#{secret}" "country"=>"US" "language"=>"en" "behalfOf"=>"#{behalfOf}")
xml.send("urn:styleId"){xml.text "#{style_id}"}
xml.send("urn:switch"){xml.text "ShowAvailableEquipment"}
xml.send("urn:includeMediaGallery"){xml.text "Both"}
}
}
}
end
file_test=File.new("dummy_file", 'w')
file_test.puts builder.to_xml
builder.to_xml
end
I am getting the following error
SyntaxError: /home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected '(', expecting '}'
... xml.send("urn:accountInfo")("number"=>"#{number}" "secret...
... ^
/home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected =>, expecting '}'
...d("urn:accountInfo")("number"=>"#{number}" "secret"=>"#{secr...
... ^
/home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected =>, expecting '}'
...number"=>"#{number}" "secret"=>"#{secret}" "country"=>"US" "...
... ^
/home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected =>, expecting '}'
...ecret"=>"#{secret}" "country"=>"US" "language"=>"en" "behalf...
... ^
/home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected =>, expecting '}'
...}" "country"=>"US" "language"=>"en" "behalfOf"=>"#{behalfOf}...
... ^
/home/aravind/Documents/dev/nthat/app/models/carinfo.rb:27: syntax error, unexpected =>, expecting '}'
..." "language"=>"en" "behalfOf"=>"#{behalfOf}")
Also I am not sure how to build this part of the xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:description7a.services.chrome.com">
The following will generate your xml:
require 'nokogiri'
def self.xml_build(style_id,number,secret,behalfOf)
builder = Nokogiri::XML::Builder.new do |xml|
xml.send("soapenv:Envelope", 'xmlns:soapenv' => "http://schemas.xmlsoap.org/soap/envelope/", 'xmlns:urn' => "urn:description7a.services.chrome.com"){
xml.send("soapenv:Header")
xml.send("soapenv:Body") {
xml.send("urn:VehicleDescriptionRequest"){
xml.send("urn:accountInfo", "number"=>"#{number}", "secret"=>"#{secret}", "country"=>"US", "language"=>"en", "behalfOf"=>"#{behalfOf}")
xml.comment('You have a CHOICE of the next 3 items at this level')
xml.comment('Optional:')
xml.send("urn:styleId"){xml.text "#{style_id}"}
xml.send("urn:switch"){xml.text "ShowAvailableEquipment"}
xml.send("urn:includeMediaGallery"){xml.text "Both"}
}
}
}
end
end
puts xml_build('test', 'test', 'test', 'test').to_xml
#=> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:description7a.services.chrome.com">
#=> <soapenv:Header/>
#=> <soapenv:Body>
#=> <urn:VehicleDescriptionRequest>
#=> <urn:accountInfo number="test" secret="test" country="US" language="en" behalfOf="test"/>
#=> <!--You have a CHOICE of the next 3 items at this level-->
#=> <!--Optional:-->
#=> <urn:styleId>test</urn:styleId>
#=> <urn:switch>ShowAvailableEquipment</urn:switch>
#=> <urn:includeMediaGallery>Both</urn:includeMediaGallery>
#=> </urn:VehicleDescriptionRequest>
#=> </soapenv:Body>
#=> </soapenv:Envelope>
The exception you were seeing was due to how you were trying to create the attributes of the accountInfo node. Note that the attributes should be passed as arguments to the send method:
xml.send("urn:accountInfo", "number"=>"#{number}", "secret"=>"#{secret}", "country"=>"US", "language"=>"en", "behalfOf"=>"#{behalfOf}")
The same can be done to get the attributes on the Envelope node:
xml.send("soapenv:Envelope", 'xmlns:soapenv' => "http://schemas.xmlsoap.org/soap/envelope/", 'xmlns:urn' => "urn:description7a.services.chrome.com")
Finally, to get the comments, use the comment method:
xml.comment('You have a CHOICE of the next 3 items at this level')
xml.comment('Optional:')

syntax error, unexpected ',', expecting tCOLON2 or '[' or '.' when assigning a class to erb

In my profile.html.erb file I get a syntax error anytime I try to assign a class or id to erb. Below is an example:
<p>"<%= current_user.current_program.name, :id => 'progress' %>" Progress</p>
This gives me the following error:
SyntaxError in Users#profile
Showing /.../app/views/users/profile.html.erb where line #13 raised:
/Users/.../app/views/users/profile.html.erb:13: syntax error, unexpected tASSOC, expecting tCOLON2 or '[' or '.'
...er.current_program.name, :id => 'progress' );#output_buffer....
... ^
I can't figure out what the syntax error is. I'm totally stumped.
We can reproduce and simplify your problem in a standalone Ruby like so:
require 'erb'
ERB.new("<p><%= name, :a => 'b' %></p>").run
Producing the error:
SyntaxError: (erb):1: syntax error, unexpected tASSOC, expecting tCOLON2 or '[' or '.'
..."; _erbout.concat(( name, :a => 'b' ).to_s); _erbout.concat ...
... ^
from /Users/phrogz/.../ruby/1.9.1/erb.rb:838:in `eval'
from /Users/phrogz/.../ruby/1.9.1/erb.rb:838:in `result'
from /Users/phrogz/.../ruby/1.9.1/erb.rb:820:in `run'
from (irb):2
from /Users/phrogz/.../bin/irb:16:in `<main>'
Even more simply, taking ERB out of the mix:
a, :b=>'c'
#=> SyntaxError: (irb):3: syntax error, unexpected tASSOC, expecting tCOLON2 or '[' or '.'
What you have just isn't valid Ruby code. What were you trying to do there? Pass the :id => 'progress' hash as a parameter to the .name method? If so, then drop the comma, and (optionally) include parentheses for clarity:
<p>"<%= current_user.current_program.name( :id=>'progress' ) %>" Progress</p>
And if you're using Ruby 1.9+, you can use the simpler Hash-with-symbol-keys syntax:
<p>"<%= current_user.current_program.name( id:'progress' ) %>" Progress</p>
However, it seems unlikely to me that the name method takes such a hash, so I ask again: what are you really trying to accomplish? What does the name method return, and what HTML output do you want?
Taking a guess, maybe you wanted the text returned by .name to be wrapped in <span id="progress">? If so, you must do so like:
<p>"<span id="progress"><%= current_user.current_program.name%></span>" Progress</p>
Or perhaps using content_tag:
<p><%= content_tag("span", current_user.current_program.name, id:'progress') %> Progress</p>
In Haml this would be:
%p
%span#progress= current_user.current_program.name
Progress
maybe if you remove the comma it will work (is current_user.current_program.name a method that takes a hash as a parameter?)

Why does the JSON returned from my Sinatra App give a syntax error?

I'm developing a Sinatra app, which returns JSON, e.g.
get '/clients' do
# do stuff
response = {
"success" => "true",
"msg" => "Clients successfully retrieved",
"data" => {"clients" => #current_user.clients}
}
return response.to_json
end
The returned JSON looks something like this:
{"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}
When I copy and paste it into a JSON parser, it works fine.
http://json.parser.online.fr/
But when I fire up irb and try to use it, I get a bunch of errors:
1.9.3-p286 :001 > a = {"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}
SyntaxError: (irb):1: syntax error, unexpected ':', expecting tASSOC
a = {"success":"true","msg":"Clients success...
^
(irb):1: syntax error, unexpected ',', expecting $end
a = {"success":"true","msg":"Clients successfully r...
^
from /home/[me]/.rvm/rubies/ruby-1.9.3-p286/bin/irb:13:in `<main>'
1.9.3-p286 :002 >
Anyone able to offer any insight? Am I doing something wrong?
Thanks alot
Problem
JSON doesn't constitute a valid Ruby hash. It's a String that you need to parse with JSON#parse.
Solution
Parse JSON as a String by enclosing it in single quotes or a Ruby quote literal. For example:
JSON.parse %q/{"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}/
=> {"success"=>"true",
"msg"=>"Clients successfully retrieved",
"data"=>
{"clients"=>
[{"client"=>
{"created_at"=>"2013-03-31T22:50:18Z",
"email"=>"test#test.com",
"first_name"=>"Marge",
"gender"=>"F",
"hairdresser_id"=>2,
"id"=>1,
"surname"=>"Simpson",
"updated_at"=>"2013-03-31T22:50:18Z"}}]}}
Your hash has key value pair denoted as { key : value } but ruby uses '=>' symbol to map key to a value.
Try replacing ':' to '=>' and it works fine.
eg) a = {"success" => "true"}
If you want to parse this Json to ruby has then use this snippet:
require 'json'
value = "{\"val\":\"test\",\"val1\":\"test1\",\"val2\":\"test2\"}"
puts JSON.parse(value) # => {"val"=>"test","val1"=>"test1","val2"=>"test2"}

Resources