REXML && Output of Specific Attr Values

A

aidy

Hi,

Using REXML, I am listing all the values of specific attributes from an
XML file

<SNIP>

require 'rexml/document'
include REXML # so ! pre-fixing everything with REXML


class Test_XML

def parse_file

doc = Document.new File.new('C:\Ruby_Files\TESTLOG.xml')
doc.elements.each("SAFS_LOG/LOG_MESSAGE") { |element| puts
element.attributes["type"] }

end
end

foo = Test_XML.new;foo.parse_file()

</SNIP>


output


START DATATABLE
GENERIC
START TESTCASE


Is it possible to only put those attributes with a specific value?

i.e.

puts if element.attributes["type"] == 'START TESTCASE '

Thanks

Aidy
 
C

ChrisH

You have the answer:
....
puts element.attributes["type"] if element.attributes["type"] = 'START
TESTCASE '
 
A

aidy

Hi,

Thanks for the answer and I apologise for posting again.

This is my code

<snip>
require 'rexml/document'
include REXML # so ! pre-fixing everything with REXML


class Test_XML

def parse_file

doc = Document.new File.new('C:\Ruby_Files\TESTLOG.xml')
doc.elements.each("SAFS_LOG/LOG_MESSAGE") { |element|
if element.attributes["type"] == 'START TESTCASE'
puts element.attributes["type"]
puts element.children()
end
}

end
end

foo = Test_XML.new;foo.parse_file()

</snip>

AND OUTPUT

<snip>

START TESTCASE

<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>

<MESSAGE_DETAILS><![CDATA[Checks to see if all the correct defaults are
there]]></MESSAGE_DETAILS>

START TESTCASE

<MESSAGE_TEXT><![CDATA[ST_LTD_2]]></MESSAGE_TEXT>

<MESSAGE_DETAILS><![CDATA[Don't change any values and click on
Search]]></MESSAGE_DETAILS>

</snip>

I am trying to get to the child element '<MESSAGE_TEXT>' and retrieve
the text within CDATA.

Obj.children() (as you would expect) is returning all child elements,
and I am not getting any child output with next_sibling_node() .


Cheers

Aidy
 
C

ChrisH

I haven't doen any REXML, but looking at the docs it seems the
REXML::Element.cdatas() might do the trick?
 
R

Robert Klemme

aidy said:
Hi,

Thanks for the answer and I apologise for posting again.

This is my code

<snip>
require 'rexml/document'
include REXML # so ! pre-fixing everything with REXML


class Test_XML

def parse_file

doc = Document.new File.new('C:\Ruby_Files\TESTLOG.xml')
doc.elements.each("SAFS_LOG/LOG_MESSAGE") { |element|
if element.attributes["type"] == 'START TESTCASE'
puts element.attributes["type"]
puts element.children()
end
}

end
end

foo = Test_XML.new;foo.parse_file()

</snip>

AND OUTPUT

<snip>

START TESTCASE

<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>

<MESSAGE_DETAILS><![CDATA[Checks to see if all the correct defaults are
there]]></MESSAGE_DETAILS>

START TESTCASE

<MESSAGE_TEXT><![CDATA[ST_LTD_2]]></MESSAGE_TEXT>

<MESSAGE_DETAILS><![CDATA[Don't change any values and click on
Search]]></MESSAGE_DETAILS>

</snip>

I am trying to get to the child element '<MESSAGE_TEXT>' and retrieve
the text within CDATA.

Obj.children() (as you would expect) is returning all child elements,
and I am not getting any child output with next_sibling_node() .


Cheers

Aidy
If you want only the leaf elements I'm almost 100% certain there is an
XPath expression you can use that selects exactly those nodes. Even if
you do it in two steps like now you probably could do another XPath
query inside the block - but IMHO the proper way to do it is to craft
the right XPath expression in the first place.

If you provide the XML (or a short sample) we might be able to help a
bit better.

Btw, you're not closing the file handle properly. Rather do this:

doc = File.open('C:\Ruby_Files\TESTLOG.xml') {|io| Document.new(io)}

Kind regards

robert
 
A

aidy

Hi,
If you provide the XML (or a short sample) we might be able to help a
bit better.


This is a sample of the XML.

<SNIP>


<SAFS_LOG>

<LOG_MESSAGE type="START TESTCASE" date="04-05-2006" time="16:43:42" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="FAILED" date="04-05-2006" time="16:44:08" >
<MESSAGE_TEXT><![CDATA[TerritoryListTable:innerText did not
contain substring]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="STOP TESTCASE" date="04-05-2006" time="16:44:05" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>


...... many more sections like this

</SAFS_LOG>


</SNIP>

The XML that I am dealing with is not well structured. I tried to XSLT
it, but I started pulling my hair out.
So I thought using REXML to parse and builder to create a new XML file,
then XSLT it.

So what I am trying to do is this (pseudo code)

if type_attribute = "START TESTCASE"
puts gettext() # i.e. ST_LTD_1
end
if type_attribute = "FAILED"
@fail = 'FAILED'
puts 'FAIL!"
end
if attribute = "STOP TESTCASE" && @fail != 'FAILED'
puts 'PASS'
end

Btw, you're not closing the file handle properly. Rather do this:
oc = File.open('C:\Ruby_Files\TESTLOG.xml') {|io| Document.new(io)}

I was under the impression that if a file had an adjacent block, Ruby
automatically closes it.

I am not so sure where this block would go '{|io| Document.new(io)}'?

Thanks for the Help

Aidy
 
R

Robert Klemme

aidy said:
Hi,
If you provide the XML (or a short sample) we might be able to help a
bit better.


This is a sample of the XML.

<SNIP>


<SAFS_LOG>

<LOG_MESSAGE type="START TESTCASE" date="04-05-2006" time="16:43:42" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="FAILED" date="04-05-2006" time="16:44:08" >
<MESSAGE_TEXT><![CDATA[TerritoryListTable:innerText did not
contain substring]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="STOP TESTCASE" date="04-05-2006" time="16:44:05" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>


..... many more sections like this

</SAFS_LOG>


</SNIP>

The XML that I am dealing with is not well structured. I tried to XSLT
it, but I started pulling my hair out.
So I thought using REXML to parse and builder to create a new XML file,
then XSLT it.

So what I am trying to do is this (pseudo code)

if type_attribute = "START TESTCASE"
puts gettext() # i.e. ST_LTD_1
end
if type_attribute = "FAILED"
@fail = 'FAILED'
puts 'FAIL!"
end
if attribute = "STOP TESTCASE" && @fail != 'FAILED'
puts 'PASS'
end

Btw, you're not closing the file handle properly. Rather do this:
oc = File.open('C:\Ruby_Files\TESTLOG.xml') {|io| Document.new(io)}

I was under the impression that if a file had an adjacent block, Ruby
automatically closes it.

I am not so sure where this block would go '{|io| Document.new(io)}'?

Thanks for the Help

I have a solution but I'm not sure whether this can be done better with
XPath - I doubt it. Does this help?

Kind regards

robert


#!/bin/env ruby

require 'rexml/document'

doc = REXML::Document.new(DATA)

fail = false

doc.each_element('*/LOG_MESSAGE') do |elem|
case elem.attribute:)type).value
when "START TESTCASE" then
elem.each_element('MESSAGE_TEXT') {|mt| print mt.text}
puts
fail = false
when "FAILED" then
fail = true
puts "FAIL"
when "STOP TESTCASE" then
puts "PASS" unless fail
else
STDERR.puts "Unknown type: #{elem.attribute:)type).value}"
end
end

__END__
<SAFS_LOG>

<LOG_MESSAGE type="START TESTCASE" date="04-05-2006" time="16:43:42" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="FAILED" date="04-05-2006" time="16:44:08" >
<MESSAGE_TEXT><![CDATA[TerritoryListTable:innerText did not
contain substring]]></MESSAGE_TEXT>
</LOG_MESSAGE>
<LOG_MESSAGE type="STOP TESTCASE" date="04-05-2006" time="16:44:05" >
<MESSAGE_TEXT><![CDATA[ST_LTD_1]]></MESSAGE_TEXT>
</LOG_MESSAGE>


</SAFS_LOG>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top