change xml format of JMSSerializer - jms-serializer

I have an array like this:
$a = array("test" =>
array("foo" => "bar")
);
By serilizing it as xml, I expected to get something like:
<test>
<foo>bar</foo>
</test>
But I get:
<result>
<entry>
<entry><![CDATA[bar]]></entry>
</entry>
</result>
How is possible to get the xml the way I described above with JMSSerializer?
I know this is possible with Annotation, but I need to do it with php, so which methods should I call to setup xmlRoot and xmlValue et.c?

Related

how can I get some attributes when using Nokogiri

Here is my xml string, I want to get the English result "B"
<body>
<attributes>
<attr name="Math" namespace="">A</attr>
<attr name="English" namespace="" parentName="">B</attr>
</attributes>
</body>
Here is how I parse the xml string
result = Nokogiri::XML(xml)
res = Hash.from_xml(result.to_s)
But when I use res["body"]["attributes"], I only get the result set
=> {"attr"=>["A", "B"]}
Because the order of attr is not regular,
So how can I judge what the English result really is ?
Thanks!
You can use css selector:
result.css("attr[name='English']").children.to_s
will give you "B"

xpath expression to select an item whose ENTIRE text contents contains a specific string

Can i have an xpath expression to select an item whose ENTIRE text contents (including its descendants') contains a specific string?
My xml is like this:
<item>
<sentence>Good morning. Today is fine.</sentence>
<entry>
<keywords>
<keyword>fooA</keyword>
<keyword>fooB</keyword>
</keywords>
</entry>
<entry>
<keywords>
<keyword>fooC</keyword>
<keyword>fooD</keyword>
</keywords>
</entry>
</item>
<item>
<sentence>It's raining, we'd better get a raincoat.</sentence>
<entry>
<keywords>
<keyword>barA</keyword>
<keyword>barB</keyword>
</keywords>
</entry>
<entry>
<keywords>
<keyword>barC</keyword>
<keyword>barD</keyword>
</keywords>
</entry>
</item>
What I want to get is. If I look up any word or words in:
"Good morning. Today is fine. fooA fooB fooC fooD"
like "morning", "fooC", or "fine fooB", I will get the first item.
and if I look up any word or words in:
"It's raining, we'd better get a raincoat.. barA barB barC barD"
like "raining", "better", "better barD", "get barB barA", i get the second item.
I'm trying to use contain() and concat(), but seemed I couldn't concatenate within the xpath expression all descendants in different levels.
contains(concat(sentence/text(),entry/keywords/keyword/text()),"barC")
not working. concat() only turns the first text node to string.
Thanks in advance!!
This seems to work just fine
//item[contains(string(), 'barC')]
Demo here - http://www.xpathtester.com/xpath/da560511673f56c89386aecfc15a4a63
If you only want to use specific child nodes, try this
//item[(sentence|entry)[contains(string(), 'barC')]]
Demo - http://www.xpathtester.com/xpath/8236042dbcceea163665b015aa4da180

Nokogiri (Ruby): Extract tag contents for a specific attribute inside each node

I have a XML with the following structure
<Root>
<Batch name="value">
<Document id="ID1">
<Tags>
<Tag id="ID11" name="name11">Contents</Tag>
<Tag id="ID12" name="name12">Contents</Tag>
</Tags>
</Document>
<Document id="ID2">
<Tags>
<Tag id="ID21" name="name21">Contents</Tag>
<Tag id="ID22" name="name22">Contents</Tag>
</Tags>
</Document>
</Batch>
</Root>
I want to extract the contents of specific tags for each Document node, using something like this:
xml.xpath('//Document/Tags').each do |node|
puts xml.xpath('//Root/Batch/Document/Tags/Tag[#id="ID11"]').text
end
Which is expected to extract the contents of the tag with id = "ID11" for each 2 nodes, but retrieves nothing. Any ideas?
You have a minor error in the xpath, you are using /Documents/Document while the XML you pasted is a bit different.
This should work:
//Root/Batch/Document/Tags/Tag[#id="ID11"]
My favorite way to do this is by using the #css method like this:
xml.css('Tag[#id="ID11"]').each do |node|
puts node.text
end
It seemed that xpath used was wrong.
'//Root/Batch/Documents/Document/Tags/Tag[#id="ID11"]'
shoud be
'//Root/Batch/Document/Tags/Tag[#id="ID11"]'
I managed to get it working with the following code:
xml.xpath('//Document/Tags').each do |node|
node.xpath("Tag[#id='ID11']").text
end

How can I concatenate two XML tags using Ruby/Nokogiri?

I am using Ruby to retrieve an XML document with the following format:
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
I want to know how to produce the following result, with the tags concatenated:
<project>
<users>
<person>
<name>LUIS JOHN</name>
</person>
</users>
</project>
Here is the code I am using:
file = File.new( "proyectos.xml" )
doc3 = Nokogiri::XML(file)
a=0
#participa = doc3.search("person")
#participa.each do |i|
#par = #participa.search("name").map { |node| node.children.text }
#par.each do |i|
puts #par[a]
puts '--'
a = a + 1
end
end
Rather than supply code, here's how to fish:
To parse your XML into Nokogiri, which I recommend highly:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
EOT
That gives you a doc variable which is the DOM as a Nokogiri::XML::Document. From that you can search, either for matching nodes or a particular node. search allows you to pass an XPath or CSS accessor to locate what you are looking for. I recommend CSS for most things because it is more readable, but XPath has some great tools to dig into the structure of your XML, so often I end up with both in my code.
So, doc.at('users') is the CSS accessor to find the first users node. doc.search('person') will return all nodes matching the person tag as a NodeSet, which is basically an array which you can enumerate or loop over.
Nokogiri has a text method for a node that lets you get the text content of that node, including all the carriage-returns between nodes that would normally be considered formatting in the XML as it flows down the document. When you have the text of the node, you can apply the normal Ruby string processing commands, such as strip, squish, chomp, etc., to massage the text into a more usable format.
Nokogiri also has a children= method which lets you redefine the child nodes of a node. You can pass in a node you've created, a NodeSet, or even the text you want rendered into the XML at that point.
In a quick experiment, I have code that does what you want in basically four lines. But, I want to see your work before I share what I wrote.
Finally, puts doc.to_xml will let you easily see if your changes to the document were successful.
Here's how I'd do it:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
EOT
The XML is parsed into a DOM now. Search for the users tags, then locate the embedded name tags and extract the text from them. Join the results into a single space-delimited string. Then replace the children of the users tag with the desired results:
doc.search('users').each do |users|
user_names = users.search('name').map(&:text).join(' ')
users.children = "<person><name>#{ user_names }</name></person>"
end
If you output the resulting XML you'll get:
puts doc.to_xml
<?xml version="1.0"?>
<project>
<users><person><name>LUIS JOHN</name></person></users>
</project>

XQuery return text node if it contains given keyword

A test sample of my xml file is shown below:
test.xml
<feed>
<entry>
<title>Link ISBN</title>
<libx:libapp xmlns:libx="http://libx.org/xml/libx2" />
</entry>
<entry>
<title>Link Something</title>
<libx:module xmlns:libx="http://libx.org/xml/libx2" />
</entry>
</feed>
Now, I want to write an xquery which will find all <entry> elements which have <libx:libapp> as a child. Then, for all such entries return the title if the title contains a given keyword (such as Link). So, in my example xml document the xquery should return "Link ISBN".
My sample xquery is shown below:
samplequery.xq (here doc_name is the xml file shown above and libapp_matchkey is a keyword such as 'Link')
declare namespace libx='http://libx.org/xml/libx2';
declare variable $doc_name as xs:string external;
declare variable $libpp_matchkey as xs:string external;
let $feeds_doc := doc($doc_name)
for $entry in $feeds_doc/feed/entry
(: test whether entry has libx:libapp child and has "Link" in its title child :)
where ($entry/libx:libapp and $entry/title/text()[contains(.,$libapp_matchkey)])
return $entry/title/text()
This xquery is returning null instead of the expected result 'Link ISBN'. Why is that?
I want to write an xquery which will
find all elements which have
as a child. Then, for
all such entries return the title if
the title contains a given keyword
(such as Link).
Just use:
/*/entry[libx:libapp]/title[contains(.,'Link')]/text()
Wrapping this XPath expression in XQuery we get:
declare namespace libx='http://libx.org/xml/libx2';
/*/entry[libx:libapp]/title[contains(.,'Link')]/text()
when applied on the provided XML document:
<feed>
<entry>
<title>Link ISBN</title>
<libx:libapp xmlns:libx="http://libx.org/xml/libx2" />
</entry>
<entry>
<title>Link Something</title>
<libx:module xmlns:libx="http://libx.org/xml/libx2" />
</entry>
</feed>
the wanted, correct result is produced:
Link ISBN

Resources