how to iterate xml nodes with groovy - groovy

I'm trying to iterate through an xml file with groovy to get some values.
I found many people with the same problem, but the solution they used doesn't work for me, or it's too complicated.
I'm not a groovy dev, so I need a bullet proof solution which I can implement.
Basically I have an xml response file that looks like this: ( it looks bad but that's what I get)
<Body>
<head>
<Details>
<items>
<item>
<AttrName>City</AttrName>
<AttrValue>Rome</AttrValue>
</item>
<item>
<AttrName>Street</AttrName>
<AttrValue>Via_del_Corso</AttrValue>
</item>
<item>
<AttrName>Number</AttrName>
<AttrValue>34</AttrValue>
</item>
</items>
</Details>
</head>
</Body>
I've already tried this solution I found here on StackOverflow to print the values:
def envelope = new XmlSlurper().parseText("the xml above")
envelope.Body.head.Details.items.item.each(item -> println( "${tag.name}") item.children().each {tag -> println( " ${tag.name()}: ${tag.text()}")} }
the best I get is
ConsoleScript11$_run_closure1$_closure2#2bfec433
ConsoleScript11$_run_closure1$_closure2#70eb8de3
ConsoleScript11$_run_closure1$_closure2#7c0da10
Result: CityRomeStreetVia_del_CorsoNumber34
I can also remove everything after the first println, and anything inside it, the result is the same
My main goal here is not to print the values but to extrapolate those values from the xml and save them as string variables...
I know that using strings is not the best practice but I just need to understand now.

Your code as is had 2 flaws:
with envelope.Body you would NOT find anything
if you fix No. 1, you would run into multiple compile errors for each(item -> println( "${tag.name}"). Here the ( is used instead of { and you use an undefined tag variable here.
The working code would look like:
import groovy.xml.*
def xmlBody = new XmlSlurper().parseText '''\
<Body>
 <head>
  <Details>
<items>
<item>
<AttrName>City</AttrName>
<AttrValue>Rome</AttrValue>
</item>
<item>
<AttrName>Street</AttrName>
<AttrValue>Via_del_Corso</AttrValue>
</item>
<item>
<AttrName>Number</AttrName>
<AttrValue>34</AttrValue>
</item>
</items>
 
  </Details>
 </head>
</Body>'''
xmlBody.head.Details.items.item.children().each {tag ->
println( "  ${tag.name()}: ${tag.text()}")
}
and print:
AttrName: City
AttrValue: Rome
AttrName: Street
AttrValue: Via_del_Corso
AttrName: Number
AttrValue: 34

Related

parsing the text in python of the given format

I want to parse a file which looks like this:
<item> <one-of> <item> deepa vats </item> <item> deepa <ruleref uri="#Dg-e_n_t41"/> </item> </one-of> <tag> out = "u-dvats"; </tag> </item>
<item> <one-of> <item> maitha al owais </item> <item> doctor maitha </item> <item> maitha <ruleref uri="#Dg-clinical_nutrition24"/> </item> </one-of> <tag> out = "u-mal_owais"; </tag> </item>
The result should be username:out for example:
deepa vats : u-dvats and maitha al owais : u-mal_owais
to extract the username i tried
print ([j for i,j in re.findall(r"(<item>)\s*(.*?)\s*(?!\1)(?:</item>)",line)])
if len(list1) != 0:
print(list1[0].split("<item>")[-1])
You can parse the xml with objectify from lxml.
To parse an XML string you could use objectify.fromstring(). Then you can use dot notation or square bracket notation to navigate through the element and use the text property to get the text inside the element. Like so:
item = objectify.fromstring(item_str)
item_text = item.itemchild['anotherchild'].otherchild.text
From there you can manipulate the string and format it.
In this case I can see that you want the text inside item >> one-of >> item and the text inside item >> tag. In order to get it we could do something like this:
>>> from lxml import objectify
>>> item_str = '<item> <one-of> <item> maitha al owais </item> <item> doctor maitha </item> <item> maitha <ruleref uri="#Dg-clinical_nutrition24"/> </item> </one-of> <tag> out = "u-mal_owais"; </tag> </item>'
>>> item = objectify.fromstring(item_str)
>>> item_text = item['one-of'].item.text
>>> tag_text = item['tag'].text
>>> item_text
' maitha al owais '
>>> tag_text
' out = "u-mal_owais"; '
Since python doesn't allow hyphens in variable names and since tag is a property of the objectify object you have to use bracket notation instead of dot notation in this case.
I suggest using BeautifulSoup:
import bs4
soup = bs4.BeautifulSoup(your_text, "lxml")
' '.join(x.strip() for x in soup.strings if x.strip())
#'deepa vats deepa out = "u-dvats"; maitha al owais doctor maitha maitha out = "u-mal_owais";'

Counting an XML attribute in Groovy

So I'm making a script in Groovy that parses a really large XML file, appends some stuff and slightly changes each element every time it appends. Each of these elements has an ID number associated with it and I want to make it so that every time an element is appended, the ID number will = the highest ID number in the file +1. I'll show a little piece of code to that will help understand:
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="xyxy" version="1.1">
<file original="zzz.js" source-language="en" target-language="en" datatype="javascript">
<body>
<trans-unit id="20" resname="foo">
<source>foofoo</source>
<target>foofoo</target>
</trans-unit>
<trans-unit id="21" resname="blah">
<source>blahblah</source>
<target>blahblah</target>
</trans-unit>
</body>
</file>
</xliff>
In this case, if I added an element (trans-unit) to the list, the ID would need to be 22. I have an algorithm that parses and appends, but I'm not sure how to increment the ID each time. Again, I'm using Groovy to do this. Does anyone have an idea? Thanks in advance!!
Assuming you have parsed that XML with xmlslurper or xmlparser, you should be able to get the next id with the help of max:
def xml = '''<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="xyxy" version="1.1">
<file original="zzz.js" source-language="en" target-language="en" datatype="javascript">
<body>
<trans-unit id="20" resname="foo">
<source>foofoo</source>
<target>foofoo</target>
</trans-unit>
<trans-unit id="21" resname="blah">
<source>blahblah</source>
<target>blahblah</target>
</trans-unit>
</body>
</file>
</xliff>'''
def x = new XmlSlurper().parseText(xml)
def next = 1 + x.file.body.'trans-unit'*.#id*.text().collect { it as Integer }.max()
assert next == 22
To use XmlParser, you need to change the line to:
def next = 1 + x.file.body.'trans-unit'*.#id.collect { it as Integer }.max()

How to get the attribute value of an xml code using linq

<Shape ID="1" NameU="Start/End" Name="Start/End" Type="Shape" Master="2">
....</Shape>
<Shape ID="2" NameU="Start/End" Name="Start/End" Type="Shape" Master="5">
....</Shape>
I have to return the Master value for every ID value.
How can i achieve it by using LINQ to XMl.
You didn't really present how your XML document looks like, so I assumed it's as follow:
<Shapes>
<Shape ID="1" NameU="Start/End" Name="Start/End" Type="Shape" Master="2">
</Shape>
<Shape ID="2" NameU="Start/End" Name="Start/End" Type="Shape" Master="5">
</Shape>
</Shapes>
You can simply get Master attribute value for all different ID like that:
var xDoc = XDocument.Load("Input.xml");
var masters = xDoc.Root
.Elements("Shape")
.ToDictionary(
x => (int)x.Attribute("ID"),
x => (int)x.Attribute("Master")
);
masters will be Dictionary<int, int> where key is your ID and value is corresponding Master attribute value.

JavaFX & FXML: how do I set the default selected item in a ChoiceBox in FXML?

I have the following FXML:
<ChoiceBox>
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="2 minutes" />
<String fx:value="5 minutes" />
<String fx:value="15 minutes" />
</FXCollections>
</items>
</ChoiceBox>
But in the GUI it just shows a ChoiceBox with a default of nothing. I would like the first element in the list to be the default, and for a choice of "null" or nothing to be prohibited.
How do I accomplish this?
I added the value attribute to the ChoiceBox tag, and that worked.
<ChoiceBox value="2 minutes">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="2 minutes" />
<String fx:value="5 minutes" />
<String fx:value="15 minutes" />
</FXCollections>
</items>
</ChoiceBox>
First, you should import your needed value model, like Crowell answer, you should import like this in your fxml header:
<?import javafx.collections.*?>
Second, if you want's import your own model, import it first and then like this:
<?import com.zzg.mybatis.generator.model.*?>
....
<ChoiceBox layoutX="24.0" layoutY="14.0" prefWidth="150.0">
<items>
<FXCollections fx:factory="observableArrayList">
<DatabaseDTO name="MySQL" value="1"></DatabaseDTO>
<DatabaseDTO name="Oracle" value="2"></DatabaseDTO>
</FXCollections>
</items>
</ChoiceBox>
#Groostav: In case we programmatically "know" the value that should appear as selected (for example, we landed in an edit form), we can do the following:
1) Add a new item with index 0 (that is, the element we need to show as selected):
myChoiceBox.getItems().add(0, ItemObtainedProgrammatically);
2) Show the item as selected (since we already know it's at position 0):
myChoiceBox.getSelectionModel().select(0);
Probably this qualifies as a dirty hack, but it works. The con: You have the same item twice in your choicebox

How to Amending XElement using LINQ C#

how do I amaned an existing xemement type object in memory ?
I have something like below XElement in my memory , I want to modify the same before proceeding to next iteration in loop. Want to add to group all nodes. Using xElement.Add didnt worked - so wondering whats the best possible approach?
<Root>
<deals>
<deal>
<dealid> D1 </dealid>
<Trade> T1</Trade>
<Details> dt1 </Details>
<Details> dt2 </Details>
<Trade> T2</Trade>
<Details> dt1 </Details>
<Details> dt2 </Details>
<Group> g1 </Group>
<Group> g2 </group>
</deal>
</deals>
<Root>
This has been done by using two different XElement objects and merging both just after each iteration - thanks for lookint into this.
Regards,

Resources