How to write Nokogiri xml output to rails database? - ruby-on-rails

I want to write a db/seeds.rb file which uses an xml file for the source data.
The xml looks like this:
<?xml version="1.0"?>
<Collies xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://api.syntra-limburg.be">
<Colli>
<colliid>7b524488-c847-4271-a5ee-ca53c0aeb0cd</colliid>
<collinaam>Summer School: Taalbad Professioneel Nederlands</collinaam>
<aantalsessies>0</aantalsessies>
<aantaluren />
</Colli>
<Colli>
<colliid>89ecb4b5-3393-4109-9ea2-b1b1f3126128</colliid>
<collinaam>Summer School: BA4- BA5 gewaarschuwd en vakbekwaam persoon</collinaam>
<aantalsessies>0</aantalsessies>
<aantaluren />
</Colli>
</Collies>
My code seeds.rb file looks like this:
...
doc = Nokogiri::XML(f)
Colli.delete_all
doc.css("Colli").each do |colli|
Colli.create!(name: colli["colllinaam"], session: colli["aantalsessies"])
end
f.close
Within my database alle the name and session fields have "nil" in them. I tried doing colli.css("collinaam") but that does not seem to work either.
How should I tackle this problem? Can somebody point me in the right direction?

I fixed it myself.
I had an "L" too much in the collinaam. no need for the bracket stuff just basic nokogiri.
doc.css("Colli").each do |item|
Colli.create!(
name: item.css("collinaam").text,
teaser: item.css("teaser").text)
end

Related

Nokogiri Tag with id and a normal field

I am trying to create a line in an xml file that looks like this <Type id="Standard">Economy 3-5 Business Days</Type>. So far I have only been able to make it look like <Type id="Standard" value="Economy 3-5 Business Days"/>.
Maybe I missed it in the nokogiri docs, but I couldn't find anyway to get the line to show up like the first example.
My like currently looks like xml.Type(id: 'Standard', value:'Economy 3-5 Business Days')
Try xml.Type('Economy 3-5 Business Days', id: 'Standard')
I don't know the whole story about what do you expect to build in your software, but this could help you:
require 'nokogiri'
builder = Nokogiri::XML::Builder.new do |xml|
xml.Type.Standard! "Economy 3-5 Business Days"
end
puts builder.to_xml
Which outputs:
#> <?xml version="1.0"?>
#> <Type id="Standard">Economy 3-5 Business Days</Type>
Here is some documentation you should read in case you would like to build more complex documents: http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Builder

UniVerse XDOM Trouble with Default Namespaces

I'm trying to use the XDOM functions of UniVerse to parse an XML file, but I can't get it to correctly parse XML that uses a default namespace. It can correctly handle XML without namespaces, or with named namespaces, but if there is a default namespace, all xPaths will fail to locate the nodes they are supposed to match.
To give a simple example, I'm, trying to parse this XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore xmlns="http://www.example.com">
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
With this code:
PROGRAM XDOM.TEST
$INCLUDE SYSCOM XML.H
OPEN "XML" TO F.XML ELSE STOP "OPEN FAILED"
READ XML FROM F.XML, 'TEST.xml' ELSE STOP "READ FAILED"
EXIT.PROG = #FALSE
CONVERT #FM TO CHAR(10) IN XML
IF NOT(EXIT.PROG) AND XDOMOpen(XML, XML.FROM.STRING, XDOM) # XML.SUCCESS THEN GOSUB XML.ERR
IF NOT(EXIT.PROG) AND XDOMLocate(XDOM, '/bookstore/book[#category="CHILDREN"]', 'xmlns=http://www.example.com', XNODE) # XML.SUCCESS THEN GOSUB XML.ERR
IF NOT(EXIT.PROG) AND XDOMEvaluate(XNODE, './author', 'xmlns=http://www.example.com', AUTHOR) # XML.SUCCESS THEN GOSUB XML.ERR
IF NOT(EXIT.PROG) then PRINT AUTHOR
STOP
XML.ERR:
XML.CODE = ''
XML.ERR = ''
EXIT.PROG = #TRUE
IF XMLGetError(XML.CODE, XML.ERR) = XML.SUCCESS THEN
PRINT XML.CODE
PRINT XML.ERR
END
RETURN
END
When I run this code as is, I get the output:
10
The location path '/bookstore/book[#category="CHILDREN"]' was not found.
However, if I remove the "xmlns=http://www.example.com" namespace, it works fine.
After searching on my own, I found out that this is actually a bug UniVerse's XDOM parser itself. Someone has kindly documented a work-around here. You can "fool" the parser into working by giving a name to the default namespace. They also note that you can't use double-quotes in the namespace map either.
Personally, I prefer the simpler solution of just manually stripping out the offending namespace before parsing it. Adding this line to the above program fixes the issue, albeit in a very hacky way:
XML = CHANGE(XML, ' xmlns="http://www.example.com"', '')
This way you don't have to put unnecessary prefixes on all your xPath nodes. This may not always be an option though, depending on how you are getting the XDOM handle.

Nokogiri parsing Rackspace return using XPath in Rails

I'm using Nokogiri to parse a return from the Rackspace API
so I'm using their sample code to
response = server.get '/customers/'+#user.customer_id.to_s+'/domains/', server.xml_format
doc = Nokogiri::XML::parse response.body
puts "xpath values"
doc.xpath("//name").each do |node|
puts
node.text
end
As my code to use Nokogiri to return the nodelist of nodes of the element
for some reason I seem to have missed something obvious and I just for the life of me cannot get it to parse the list of nodes and return them to me, is there something simple I can do to fix to have it return the list of nodes?
Here's an example of the XML I'm trying to parse:
<domainList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:xml:domainList">
<offset>0</offset>
<size>50</size>
<total>4</total>
<domains>
<domain>
<name>domain1.com</name>
<accountNumber>xxxxxxx</accountNumber>
<serviceType>exchange</serviceType>
</domain>
<domain>
<name>domain2.com</name>
<accountNumber>xxxxxxx</accountNumber>
<serviceType>exchange</serviceType>
</domain>
<domain>
<name>domain3.com</name>
<accountNumber>xxxxxxx</accountNumber>
<serviceType>exchange</serviceType>
</domain>
</domains>
</domainList>
Cheers
The issue seems to be that you have to tell Nokogiri about their namespace.
If you remove xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:xml:domainList" from your domainLists tag you'd see your query work.
Otherwise you need to tell Nokogiri about that namespace.
doc.xpath("//blarg:name", {'blarg' => 'urn:xml:domainList'}).each do |name|
puts name.text
end
Nokogiri xpath takes a second argument which is a hash of namespaces. The xml you have defines a general namespace but doesn't give it a tag. I don't know if there is a way for nokogiri to just find this, so instead on your searches just give your search an arbitrary tag and associate the namespace path with that tag. You can put whatever text you want instead of blarg, it was just for the example.

Is it possible to generate plain-old XML using Haml?

I've been working on a piece of software where I need to generate a custom XML file to send back to a client application. The current solutions on Ruby/Rails world for generating XML files are slow, at best. Using builder or event Nokogiri, while have a nice syntax and are maintainable solutions, they consume too much time and processing.
I definetly could go to ERB, which provides a good speed at the expense of building the whole XML by hand.
HAML is a great tool, have a nice and straight-forward syntax and is fairly fast. But I'm struggling to build pure XML files using it. Which makes me wonder, is it possible at all?
Does any one have some pointers to some code or docs showing how to do this, build a full, valid XML from HAML?
Doing XML in HAML is easy, just start off your template with:
!!! XML
which produces
<?xml version='1.0' encoding='utf-8' ?>
Then as #beanish said earlier, you "make up your own tags":
%test
%test2 hello
%item{:name => "blah"}
to get
<test>
<test2>hello</test2>
<item name='blah'></item>
</test>
More:
http://haml.info/docs/yardoc/file.REFERENCE.html#doctype_
%test
%test2 hello
%item{:name => "blah"}
run it through haml
haml hamltest.haml test.xml
open the file in a browser
<test>
<test2>hello</test2>
<item name='blah'></item>
</test>
The HAML reference talks about html tags and gives some examples.
HAML reference
This demonstrates some things that could use useful for xml documents:
!!! XML
%root{'xmlns:foo' => 'http://myns'}
-# Note: :dashed-attr is invalid syntax
%dashed-tag{'dashed-attr' => 'value'} Text
%underscore_tag Text
- ['apple', 'orange', 'pear'].each do |fruit|
- haml_tag(fruit, "Yummy #{fruit.capitalize}!", 'fruit-code' => fruit.upcase)
%foo:nstag{'foo:nsattr' => 'value'}
Output:
<?xml version='1.0' encoding='utf-8' ?>
<root xmlns:foo='http://myns'>
<dashed-tag dashed-attr='value'>Text</dashed-tag>
<underscore_tag>Text</underscore_tag>
<apple fruit-code='APPLE'>Yummy Apple!</apple>
<orange fruit-code='ORANGE'>Yummy Orange!</orange>
<pear fruit-code='PEAR'>Yummy Pear!</pear>
<foo:nstag foo:nsattr='value'></foo:nstag>
</root>
Look at the Haml::Helpers link on the haml reference for more methods like haml_tag.
If you want to use double-quotes for attributes,
See: https://stackoverflow.com/a/967065/498594
Or outside of rails use:
>> Haml::Engine.new("%tag{:name => 'value'}", :attr_wrapper => '"').to_html
=> "<tag name=\"value\"></tag>\n"
Haml can produce XML just as easily as HTML (I've used it for FBML and XHTML). What problems are you having?
I've not used HAML, but if you can't make it work another option is Builder.
what about creating the xml header, e.g. <?xml version="1.0" encoding="UTF-8"?>
?
It should be possible. After all you can create plain old XML with Notepad.

Create xml-stylesheet PI with Rails XMLBuilder

I want to attach an xslt stylesheet to an XML document that I build with XMLBuilder. This is done with a Processing Instruction that looks like
<?xml-stylesheet type='text/xsl' href='/stylesheets/style.xslt' ?>
Normally, I'd use the instruct! method, but :xml-stylesheet is not a valid Ruby symbol.
XMLBuilder has a solution for this case for elements using tag! method, but I don't see the equivalent for Processing Instructions.
Any ideas?
You do it like this:
xm.instruct! 'xml-stylesheet', {:href=>'/stylesheets/style.xslt', :type=>'text/xsl'}
Just add that line right after
xm.instruct! :xml, {:encoding=>"your_encoding_type"}
and before the rest of your document output code and you should be good to go.
I'm not sure this will solve your problem since I don't know the instruct! method of that object, but :'xml-stylesheet' is a valid ruby symbol.
If using the atom_feed helper, you can pass this in the instruct option:
atom_feed(instruct: {
'xml-stylesheet' => {type: 'text/xsl', href: 'styles.xml'}
}) do |feed|
feed.title "My Atom Feed"
# entries...
end
Which results in (showing only first 3 lines):
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="styles.xml"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">

Resources