How can I get the value of specific nodes in Java from XML.
I have structure like what you see bellow and I want to get the values of userFileds(2,N.A. for the first one and 1 for the last one(it is part of real xml data. the number of elements are more):
<element class="AufOrgKombination" hash="AOK_1414931143186_52">
<field name="layer">4</field><field name="name">Function </field>
<field name="description">des</field>
<userField hash="USERFIELD_1415779871581_0">2.0</userField>
<userField hash="USERFIELD_1415386348389_3">N.A.</userField>
</element>
<element class="AufOrgKombination" hash="AOK_1414931143186_23">
<field name="layer">4</field><field name="name">Function 2 </field>
<field name="description">des</field>
<userField hash="USERFIELD_1415779871581_0">1</userField>
</element>
You should consider not to use the XPath API, but a library that handles it for you (Disclosure: I'm affiliated with that project). You probably want to reflect the XML structure somehow to your object structure. There are some difficulties to overcome (Namespaces, default namespaces, type conversion, mapping to Java objects, ...).
One possible solution using the suggested library:
public class Demo {
public interface Projection {
interface Element {
#XBRead("./userField")
List<String> getUserFieldValues();
}
#XBRead("//element")
List<Projection.Element> getElements();
}
public static void main(final String[] args) throws IOException {
Projection projection = new XBProjector().io().url("resource://data.xml").read(Projection.class);
for (Projection.Element element : projection.getElements()) {
for (String userField : element.getUserFieldValues()) {
System.out.println(userField);
}
}
}
}
This program prints out:
2.0
N.A.
1
You can use the query language XPath. It was designed exactly for that purpose.
Java 7 comes with a bunch of classes for working with XPath. See documentation and examples here.
Note that your xml is not well formed because it does not have exactly one root element.
For the modified and well formed version of your xml document
<root>
<element class="AufOrgKombination" hash="AOK_1414931143186_52">
<field name="layer">4</field><field name="name">Function </field>
<field name="description">des</field>
<userField hash="USERFIELD_1415779871581_0">2.0</userField>
<userField hash="USERFIELD_1415386348389_3">N.A.</userField>
</element>
<element class="AufOrgKombination" hash="AOK_1414931143186_23">
<field name="layer">4</field><field name="name">Function 2 </field>
<field name="description">des</field>
<userField hash="USERFIELD_1415779871581_0">1</userField>
</element>
</root>
your XPath query would look like
/root/element/userField/text()
The result for the query (Testet with www.freeformatter.com/xpath-tester.html) looks like this:
Text='2.0'
Text='N.A.'
Text='1'
You can use the Java classes mentioned above to make that kind of queries.
Related
I have introduced two new fields inside Alfresco using Model manager, those fields are List of values. After I run the application, and try to edit a file that contains those fields I get this:
The reason is not familiar to me, because this is not my first time that I create new fields, and before everything was ok.
If I add some values to be saved, then it is ok. I suppose that there is a connection with a database, but I am not sure.
This is the code:
<field id="adadoc:regions" set='regionsAndCountries'>
<control template="/org/alfresco/components/form/controls/select-many-regions.ftl">
<control-param name="mode">and</control-param>
<control-param name="style">width:325px</control-param>
</control>
</field>
<field id="adadoc:countries" set='regionsAndCountries' >
<control template="/org/alfresco/components/form/controls/select-many-countries.ftl">
<control-param name="mode">and</control-param>
<control-param name="style">width:325px</control-param>
</control>
</field>
What could be the problem?
In my java(/spring/hibernate) web app, I am contending with XML like this (I've simplified it down a lot for example purposes - I cannot modify the XML as I'm receiving it from a third party - I only control the client code, and client domain objects - there is no XSD or WSDL to represent this XML either):
<?xml version="1.0" encoding="utf-16"?>
<Records count="22321">
<Metadata>
<FieldDefinitions>
<FieldDefinition id="4444" name="name" />
<FieldDefinition id="5555" name="hair_color" />
<FieldDefinition id="6666" name="shoe_size" />
<FieldDefinition id="7777" name="last_comment"/>
<!-- around 100 more of these -->
</FieldDefinitions>
</Metadata>
<!-- Several complex object we don't care about here -->
<Record contentId="88484848475" >
<Field id="4444" type="9">
<Reference id="56765">Joe Bloggs</Reference>
</Field>
<Field id="5555" type="4">
<ListValues>
<ListValue id="290711" displayName="Red">Red</ListValue>
</ListValues>
</Field>
<Field id="6666" type="4">
<ListValues>
<ListValue id="24325" displayName="10">10</ListValue>
</ListValues>
</Field>
<Field id="7777" type="1">
<P>long form text here with escaped XML here too
don't need to process or derefernce the xml here,
just need to get it as string in my pojo<P>
</Field>
</Record>
<Record><!-- another record obj here with same fields --> </Record>
<Record><!-- another record obj here with same fields--> </Record>
<!-- thousands more records in the sameish format -->
</Records>
The XML contains a 'records' element, which contains some metadata, then lots of 'record' elements. Each record element contains lots of 'field' entries.
My goal would be to use JAXB to unmarshall this XML into a large collection of 'record' objects. So I could do something like this:
List<Record> unmarhsalledRecords = this.getRecordsFromXML(stringOfXmlShownAbove)
where each record would look like this:
public class Record {
private String name;
private String hairColor;
private String shoeSize;
private String lastComment;
//lots more fields
//getters and setters for these fields
}
However, I've never needed to dereference field names in jaxb - is that even possible with jaxb - or do I need to write some messy/hard to maintain code with a stax parser?
None of the examples I can find online touch on anything like this - any help would be greatly appreciated.
Thank you!
I don't think jaxb supports complex mapping logic like. A couple of options that I can think of.
Transform the xml using freemarker or xslt (I hate xslt) to an xml format that matches your desired model before parsing with jaxb
Eg
<Records>
<Record>
<Name>Joe Bloggs</Name>
<HairColour>Red</HairColour>
...
</Record>
</Records>
Parse the xml as is and write an adapter wrapper in the java layer which adapts from the inbound jaxb objects to your more "user friendly" model. The adapter layer could call into the jaxb objects under the hood so you could later serialize back to xml after changes
I have the following xml doc:
<database>
<order>
<data>
<field name="time" value="10:10:10" />
</data>
<data>
<field name="product" value="product_type_1">
<field name="attributeA" value="Foo" />
<field name="attributeB" value="Bar" />
</field>
<field name="attributeC" value="Jeam" />
<field name="attributeD" value="Beam" />
<field name="attributeE" value="Deam" />
</data>
</order>
<order>
<data>
<field name="time" value="10:10:11" />
</data>
<data>
<field name="product" value="product_type_2">
<field name="attributeF" value="Bravo" />
<field name="attributeG" value="Echo" />
</field>
<field name="attributeC" value="Jeam2" />
<field name="attributeD" value="Beam2" />
<field name="attributeJ" value="Charlie" />
<field name="attributeK" value="Tango" />
<field name="attributeL" value="Zulu" />
</data>
</order>
It is a set of "order" elements but the "field" (both on quantity and type) depend on the value of the element whose name is "product". I am interested in extracting info depending on the value of the product. More specifically, I would end up with something like this table:
Time Product AttributeA AttributeB AttributeC AttributeD
10:10:10 product_type_1 Foo Bar Jeam Beam
10:10:11 product_type_2 Jeam2 Beam2
In other words I am trying to "cut" unesessary info depending on the value of child element of "order". I am trying to achive this by using xpath (in java) but I am stuck. It is impossible for me to emulate the "if" condition described above.
I am thinking of using and xpath query to retrieve one order element at a time, then query for the product type and then choose the apropriate xpath to retieve the coresponding attributes, but that sounds really inneficient and slow.
Is it possible to do it more efficiently? Is xpath not the right answer here?
Thanks in advance.
P.S: The alignment and organization of the data you see above doesn't really matter as long as I retrieve the correct data then I am sure I'll be able to print them somehow.
If you want to use XPath, you will need at least XPath 3.0 or XQuery (this code is valid in both of them). Have a look at XQuery engines if you want to use this in Java, for example Saxon, BaseX, eXist DB, ...
for $order in /database/order
return string-join((
$order//field[#name='time']/#value,
$order//field[#name='product']/#value,
($order//field[#name='attributeA']/#value, '')[1],
($order//field[#name='attributeB']/#value, '')[1],
($order//field[#name='attributeC']/#value, '')[1],
($order//field[#name='attributeD']/#value, '')[1]),
' ')
The pattern used for the attributes makes sure that empty values do not break the table layout (so for the second product type, attributes C and D do not get attributes A and B). is the tab character.
If you want to use Java for further processing the output, I'd go with this: Fetch all orders (/database/order) and loop over them. Then, for each order, use DOM (or XPath again) to fetch the nodes you need. Yet it seems that the question you asked is not your actual problem, it might be that using XQuery could lead to a cleaner solution.
I am in the process of writing a code generation XSL and have a sticky issue with which I need some expert help.
The XML defines a messaging object and its members. Below is a small sample of one of the message objects which would need to get translated into a Java object suitable for serialization:
<message name="MyObject">
<comment>Some comment</comment>
<field name="a" type="byte"/>
<field name="b" type="Int32"/>
<field name="c" type="string"/>
<field name="foo1" type="byte" numberOfBits="3"/>
<field name="foo2" type="bool" numberOfBits="1" />
<field name="foo3" type="bool" numberOfBits="1" />
<field name="foo4" type="bool" numberOfBits="1" />
<field name="foo5" type="bool" numberOfBits="1" />
<field name="foo6" type="bool" numberOfBits="1"/>
<field name="d" type="Int32"/>
<field name="e" type="Int32"/>
<field name="f" type="Int16"/>
<field name="bar1" type="byte" numberOfBits="4"/>
<field name="bar2" type="empty" numberOfBits="3"/>
<field name="bar3" type="bool" numberOfBits="1"/>
</message>
I am struggling with how to generate the necessary bit operations for the foo and bar members above. Each set of these "numberOfBits" members will always be groups of 8 bits and will always fit within a byte. In particular I am having trouble keeping track of the number of bits into the current byte and when to start the next byte.
For example, the foo members above would look something like below if I was writing from scratch:
byte bitset1;
byte getFoo1() { return (biteset1 & 0x07); }
boolean getFoo2() { return (biteset1 & 0x08) == 0x08; }
boolean getFoo3() { return (biteset1 & 0x10) == 0x10; }
boolean getFoo4() { return (biteset1 & 0x20) == 0x20; }
boolean getFoo5() { return (biteset1 & 0x40) == 0x40; }
boolean getFoo6() { return (biteset1 & 0x80) == 0x80; }
Any pointers to get me going in the right direction would be greatly appreciated.
Mike
I'd suggest to try xsl:param and/or xsl:variable and a nested template.
Top templates matches first foo and calls nested template for next-sibling, passing the accumulated bit offset to it as xsl:param.
Nested template calls itself for next-sibling.
The nesting ends when no more foo is found.
I think it should work.
I've been using Castor these past couple of days to try to get a little serialization going between my Java program and XML in a readable way. Though it has a few faults, Castor's automatic xml generation via reflection is actually very functional. Unfortunately, one thing that seems to be fairly well left out of the examples is dealing with generics. It seems the reflection API does a wonderful job as it is, but as it is inadvertently grabbing a lot of redundant data just because methods start with get___(), I wanted to write my own mapping file to stave this off.
Firstly, it seems altogether fair that in the attributes to a "field" element, one should define "type". However, it does not specify what should be done if this type is abstract or simply an interface. What should I put as the type then?
Secondly, most "collection" type objects specified in Castor (List, Vector, Collection, Set, etc) only require 1 generic type, so specifying "type" as what's inside and "collection="true"" are enough. However, it does not specify what I should do in the case of a collection like a Map, where 2 types are necessary. How can I specify both the key type and value type?
Any help at all would be greatly appreciated!
For the second of my questions:
When specifying something with a Map or a Table, you need to redefine org.exolab.castor.mapping.MapItem within the bind-xml element within your field element. Example taken from here
<class name="some.example.Clazz">
<field name="a-map" get-method="getAMap" set-method="setAMap">
<bind-xml ...>
<class name="org.exolab.castor.mapping.MapItem">
<field name="key" type="java.lang.String">
<bind-xml name="id"/>
</field>
<field name="value" type="com.acme.Foo"/>
</class>
</bind-xml>
</field>
</class>
Also, omit the type attribute from the parent field element.
For my first question, the trick is to NOT specify the type in the field element and allow Castor to infer it by itself. If you have definitions for the classes that could appear there, then it will automatically use those. For example:
<class name="some.example.Clazz">
<!-- can contain condition1 or condition2 elements -->
<field name="condition" collection="arraylist" required="true">
<bind-xml name="condition" node="element" />
</field>
</class>
<class name="some.example.condition1">
<field name="oneField" >
<xml-bind name="fieldOne" />
</field>
</class>
<class name="some.example.condition2">
<field name="anotherField />
<xml-bind name="fieldTwo" />
</field>
</class>
The output of into XML by Castor would use condition1 and condition2 style XML into the "condition" field of Clazz while still referring to its proper instantiation type.