Interesting Java code generation issue using XSLT - java

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.

Related

How to solve Invalid property value in Alfresco

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?

Solr, how to define Nested Documents in the schema.xml

I have a document with a nested document and I want to define the schema to Solr. I have been reading the documentation but I don't know how to define the schema.xml with nested documents.
When I try to index a document with addBean I get an error because I don't have in the schema the field obj1 and I don't know how to define it.
I'm using java object with #Field annotations.
public class ObjToIndex {
#Field
String id;
#Field
String name;
#Field
ObjToIndex2 obj1;
public class ObjToIndex2 {
#Field
String id;
#Field
String lastName;
I don't know how to define in the schema a field obj1 with type "object" or something similar.
I don't know how to define in the schema a field obj1 with type
"object" or something similar.
You can't (at least not in the way you think it)
Solr is not designed in that way: the unit of information is a document that is composed by fields; fields may be of different types, but, in short, they are only primitive types (strings, numbers, booleans), fields cannot be complex objects. Take a look at How Solr Sees the World in the documentation.
Does it mean you can't manage nested documents? No. You can manage them with some caveats
How to define the schema
First of all you need to define the internal _root_ field like this:
<field name="_root_" type="string" indexed="true" stored="false" docValues="false" />
Then you need to merge all "primitive" fields of your parent and children objects in a single list of fields. This has some counterparts that are also mentioned in the solr documentation:
you have to define an id field that must exist for both parent and children objects and you have to guarantee it is globally unique
only fields that exists in both parent and children objects can be declared as "required"
For example let's see a slightly more complex case where you can nest multiple comments to blog posts:
public class BlogPost {
#Field
String id;
#Field
String title;
#Field(child = true)
List<Comment> comments;
}
public class Comment {
#Field
String id;
#Field
String content;
}
Then you need a schema like this:
<?xml version="1.0" encoding="UTF-8" ?>
<schema name="${solr.core.name}" version="1.5">
<types>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="long" class="solr.LongPointField" positionIncrementGap="0"/>
<fields>
<field name="_version_" type="long" indexed="true" stored="true" />
<field name="_root_" type="string" indexed="true" stored="false" docValues="false" />
<field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true" />
<field name="title" type="string" indexed="true" stored="true" multiValued="false" required="false" />
<field name="content" type="string" indexed="true" stored="true" multiValued="false" required="false" />
</fields>
<uniqueKey>id</uniqueKey>
</schema>
How to index documents
Using solrj it is pretty straightforward: simply create your nested objects in Java and the library will take care of creating the correct request when adding them
final BlogPost myPost = new BlogPost();
myPost.id = "P1";
myPost.title = "My post";
final Comment comment1 = new Comment();
comment1.id = "P1.C1";
comment1.content = "My first comment";
final Comment comment2 = new Comment();
comment2.id = "P1.C2";
comment2.content = "My second comment";
myPost.comments = List.of(comment1, comment2);
...
solrClient.addBean("my_core", myPost);
How to retrieve documents
This is a little bit tricky: to rebuild the original object and its children you have to use the child doc transformer in your request (query.addField("[child]")):
final SolrQuery query = new SolrQuery("*:*");
query.addField("*");
query.addField("[child]");
try {
final QueryResponse response = solrClient.query("my_core", query);
final List<BlogPost> documents = response.getBeans(BlogPost.class);
in order to have nested object, please use the #Field(child = true)
public class SolrBeanWithNested{
#Field
private String id;
#Field(child = true)
private MyNestedOject nested;
}
Available since solr 5.1
See ticket : solr child
I believe this is correct:
How to write nested schema.xml in solr?
Some of the logic of "why" is described here but the basic concept is that "child" documents are actually more "related" or "linked" documents within the same schema. They may include different fields, but effectively, they're just adding to the superset of fields in the overall schema.

finding node values DOM with in Java

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.

Retrieving attribute values depending on the value of another attribute using xpath

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.

Castor XML Mapping and java.util.Map

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.

Categories