How do I use JAXB's #XmlSchema annotation on a Scala package object? - scala

This question is following on from Blaise's excellent answer here.
My question is, how do I use the JAXB #XmlSchema annotation from within Scala?
This is what I've come up with so far:
// File src/main/scala/co/orderly/prestasac/representations/wrappers.scala
package co.orderly.prestasac.representations
// JAXB
import javax.xml.bind.annotation._
#XmlSchema(xmlns = Array(#XmlNs(prefix = "xlink", namespaceURI = "http://www.w3.org/1999/xlink")))
package object wrappers {
}
Unfortunately this throws an error:
/home/alex/Development/Orderly/prestashop-scala-client/src/main/scala/co/orderly/prestasac/representations/wrappers/wrappers.scala:18: illegal start of simple expression
[error] #XmlSchema(xmlns=Array(#XmlNs(prefix = "xlink", namespaceURI = "http://www.w3.org/1999/xlink")))
[error] ^
In case there's a workaround which doesn't require #XmlSchema, I'll explain what I'm trying to do - basically I'm trying to unmarshall an XML representation which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<products>
<product id="11" xlink:href="http://www.myshop.com/api/products/11"/>
<product id="12" xlink:href="http://www.myshop.com/api/products/12"/>
...
</products>
</prestashop>
I believe I need to use #XmlSchema to define the "xlink"-prefixed namespace for the href links...

Related

How to suppress root element in BeanIO XML generation?

When generating a XML file with BeanIO, the StreamBuilder name is used as root element. How to suppress this root element?
Example:
StreamBuilder builder = new StreamBuilder("builder_name")
.format("xml")
.parser(new XmlParserBuilder()).addRecord(Test.class);
The Test class:
#Record
public class Test {
#Field(at=0)
private String field1 = "ABC";
// Getters and Setters ...
}
The generated XML file:
<builder_name>
<Test>
<field1>ABC</field1>
</Test>
</builder_name>
I don't want builder_name to be showed as root element. I want Test element to be the root. How can I achieve that?
You need to set the xmlType property/attribute to XmlType.NONE on your stream configuration.
The answer is in Appendix A - XML Mapping file reference of the documentation.
xmlType - The XML node type mapped to the stream. If not specified or set to element, the stream is mapped to the root element of the XML document being marshalled or unmarshalled. If set to none, the XML input stream will be fully read and mapped to a child group or record.
The trick is now to translate that piece of information into the StreamBuilder API, which is:
xmlType(XmlType.NONE)
Your example then becomes:
StreamBuilder builder = new StreamBuilder("builder_name")
.format("xml")
.xmlType(XmlType.NONE)
.parser(new XmlParserBuilder())
.addRecord(Test.class);
Which produces this unformatted/unindented output:
<?xml version="1.0" encoding="utf-8"?><test><field1>ABC</field1></test>
To have the xml formatted (pretty print)/indented use:
StreamBuilder builder = new StreamBuilder("builder_name")
.format("xml")
.xmlType(XmlType.NONE)
.parser(new XmlParserBuilder()
.indent()
)
.addRecord(Test.class);
Note the change to the XmlParserBuilder, to produce this output:
<?xml version="1.0" encoding="utf-8"?>
<test>
<field1>ABC</field1>
</test>

How to call Groovy script from Scala?

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<facts>
<fact id="ItemPrice" displayName="Item Price">
<defaultValue>0</defaultValue>
<script><![CDATA[
Double Value_Sales= 500;
Double Unit_Sales= 10;
Double res=Value_Sales/Unit_Sales;
return res;
]]></script>
</fact>
</facts>
Above is the sample groovy script written in xml file for finding item price.
Java code for processing Groovy:
List<Fact> factList = NREUtils.readXml("/SampleDictionary.xml") //cutome API
GroovyShell shell = new GroovyShell();
String scriptStr = factList.get(0).getScript();
Script groovyScript = shell.parse(scriptStr); // return "ItemPrice" script
Binding binding = new Binding();
groovyScript.setBinding(binding);
Object val = groovyScript.run(); // **Result will be 50**
I would like the corresponding Scala code for the same.
Without further information on your problem, and being both languages (scala and groovy) executed over the JVM, I would suggest you just to compile your groovy code and include the jar in the classpath of the JVM running your scala code.
Here you have some ideas about how to turn groovy code into usable bytecode: http://docs.groovy-lang.org/latest/html/documentation/tools-groovyc.html
Then do just do as you would with any java library that you would like to call from scala: Using Java libraries in Scala

Xtext and EMF modeling - Opposite relations parsing

I'm currently playing around with XText and EMF and I've come to a dead end.
I have an ecore model that I created using the diagram editor. I don't provide the XML representation; it should be clear from the example. Some of the relations are opposite to each other (like the parent-children relation).
This binding works perfectly fine when I create the instances programatically. Below, I show a test case that is successfully passed.
However, when I parse the model using XText, these opposite relations are not set. I can't find a way to fix this. The relations are strictly one-directional as they appear in the input file. Is there any way to force Xtext to set these? or am I supposed to resolve these manually?
Passing test
WordsFactory factory = WordsFactory.eINSTANCE;
// Prepare a simple dictionary hierarchy
Dictionary d = factory.createDictionary();
Synset s = factory.createAdjectiveSynset();
s.setDescription("A brief statement");
s.setExample("He didn't say a word.");
WordSense ws = factory.createAdjectiveWordSense();
Word w = factory.createWord();
w.setName("word");
ws.setWord(w);
s.getWordSenses().add(ws);
d.getWords().add(w);
d.getSynsets().add(s);
// Now check the bidirectional links
Assert.assertTrue(ws.getSynset() == s);
Assert.assertTrue(w.getSenses().get(0) == ws);
XMI representation of this example
<?xml version="1.0" encoding="ASCII"?>
<words:Dictionary xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:words="http://www.example.com/dstahr">
<words senses="//#synsets.0/#wordSenses.0" name="word"/>
<synsets xsi:type="words:AdjectiveSynset" description="A brief statement" example="He didn't say a word.">
<wordSenses xsi:type="words:AdjectiveWordSense" word="//#words.0"/>
</synsets>
</words:Dictionary>
Grammar definition (some unimportant rules removed)
grammar ocs_assignment.dsl.DSL with org.eclipse.xtext.common.Terminals
import "platform:/resource/ocs_assignment.model/model/words.ecore"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
Dictionary returns Dictionary:
{Dictionary}
'dict' name=EString
('add words' '[' words+=Word* ( "," words+=Word)* ']')?
synsets+=Synset*
;
Synset returns Synset:
AdjectiveSynset | NounSynset | VerbSynset;
WordSense returns WordSense:
AdjectiveWordSense | NounWordSense | VerbWordSense;
Word returns Word:
name=EString;
EString returns ecore::EString:
STRING | ID;
NounWordSense returns NounWordSense:
word=[Word|EString];
NounSynset returns NounSynset:
{NounSynset}
'(N)' name=EString
'{'
'content' '[' (wordSenses+=NounWordSense ( "," wordSenses+=NounWordSense)*)? ']'
'description' description=EString
'example' example=EString
('hyponym' hyponym=[Synset|EString])?
('hypernym' hypernym=[Synset|EString])?
('similarTo' '(' similarTo+=[Synset|EString] ( "," similarTo+=[Synset|EString])* ')' )?
'}';
Parsed file
dict dict
add words test1 test2 test3
(N) test1
{
content [ test1 test2 ]
description "test1"
example "test1"
}
(N) test2
{
content [ test3 ]
description "test2"
example "test2"
hypernym test1
}
XMI representation of the parsed file (missing references for Words)
<?xml version="1.0" encoding="ASCII"?>
<words:Dictionary xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:words="http://www.example.com/dstahr">
<words name="test1"/>
<words name="test2"/>
<words name="test3"/>
<synsets xsi:type="words:NounSynset" description="test1" example="test1" name="test1">
<wordSenses xsi:type="words:NounWordSense">
<word href="importedFile1.wdsl#xtextLink_::0.1.0.2.0::1::/0"/>
</wordSenses>
</synsets>
<synsets xsi:type="words:NounSynset" description="test2" example="test2" name="test2">
<hypernym xsi:type="words:AdjectiveSynset" href="importedFile1.wdsl#xtextLink_::0.1.1::1::/21"/>
<wordSenses xsi:type="words:NounWordSense">
<word href="importedFile1.wdsl#xtextLink_::0.1.1.2.0::1::/0"/>
</wordSenses>
</synsets>
</words:Dictionary>
Xtext does not support inverse relations built-in. If you generate the metamodel from your grammar, you would see that the inverse is not set for the corresponding relations. However, if your Ecore model has the inverse relation property is set, Xtext will maintain that.
There are two ways to use such a metamodel:
Create your own Ecore model and reference it.
You could define an IXtext2EcorePostProcessor instance that can update your generated metamodel before it is serialized. For details, see the corresponding blog post of Christian Dietrich.
The first solution is quite easy, but you would lose the auto-generated EMF models. In the second case, you have to write code that updates the Ecore (meta)model before it is serialized that can be really tricky to achieve. We have done the second approach for EMF-IncQuery (for another kind of customization), as at that point the autogeneration was really important, however the customizer became really hard to understand since.

Omit empty attributes with groovy DOMBuilder

Groovy's MarkupBuilder has an omitNullAttributes and an omitEmptyAttributes. But DOMBuilder doesn't. This is the code I have
>>> def xml = DOMBuilder.newInstance()
>>> def maybeEmpty = null
>>> println xml.foo(bar: maybeEmpty)
<foo bar=""/>
I want bar to be omitted if empty. I found a workaround in an answer to Groovy AntBuilder, omit conditional attributes... to findAll empty attributes and remove them. Since I have a complex DOM to be generated, I'm looking for other options.
I believe there is no built-in option for that, but if you need a DOMBuilder, you could subclass it and filter the attributes...
#groovy.transform.InheritConstructors
class DOMBuilderSubclass extends groovy.xml.DOMBuilder {
#Override
protected Object createNode(Object name, Map attributes) {
super.createNode name, attributes.findAll{it.value != null}
}
}
You might want to tune the construction as in standard DOMBuilder, this is just an example.
def factory = groovy.xml.FactorySupport.createDocumentBuilderFactory().newDocumentBuilder()
def builder = new DOMBuilderSubclass(factory)
println builder.foo(bar: null, baz: 1)
//<?xml version="1.0" encoding="UTF-8"?>
//<foo baz="1"/>
standard output as you said was...
println groovy.xml.DOMBuilder.newInstance().foo(bar: null, baz: 1)
//<?xml version="1.0" encoding="UTF-8"?>
//<foo bar="" baz="1"/>

Control XML Serialization from DataSet -- Attributes on "TableName element"

Hope I chose the correct forum.
I have a dataset object with one table that comes to me from a common custom component's GetDS method. I need to pass XML to another process (chunked as byte array). I have it all working but the XML is missing some attributes that the consuming process expects.
I create a dataset object and can control the name of the TableName (root element) and the row like this:
da.Fill(ds, "Foo")
ds.DataSetName = "FooUpload"
I use the GetXML method to serialize to XML that looks like the following:
<?xml version="1.0" standalone="yes" ?>
<FooUpload>
<Foo>
<FooMasterID>483</FooMasterID>
<Country>27</Country>
<PaymentCode>ANN</PaymentCode>
<Amount>132</Amount>
<PaidDate>2012-12-31 00:00:00</PaidDate>
<PaidBy>FooServices</PaidBy>
</Foo>
</FooUpload>
The calling process expects
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<FooUpload **ClientCode="FOOO" RecordCount="1" CreateDate="2008-12-09T15:02:18.920" CreateUser="valli"**>
<Foo>
<FooMasterID>483</FooMasterID>
<Country>27</Country>
<PaymentCode>ANN</PaymentCode>
<Amount>132</Amount>
<PaidDate>2012-12-31 00:00:00</PaidDate>
<PaidBy>FooServices</PaidBy>
</Foo>
</FooUpload>
Note the attributes on the FooUpload element. This node is the name of the DataTable in the DataSet.
I have searched for how to control the XMLSerializer and find lots of examples for custom objects. I even found examples of setting the column mapping to be MappingType.Attribute which is close but I need to do this with the root element which is actually the TableName for the dataset.
I feel that I am close and if I do not find a more elegant solution I will have to create a hack like looping and spitting out changed string plus rest of the XML.
You can feed the output of GetXML into a XmlDocument and add the attributes afterwards. For example:
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(ds.GetXml());
XmlAttribute attr=xdoc.CreateAttribute("ClientCode");
attr.Value = "FOOOO";
xdoc.DocumentElement.Attributes.Append(attr);
Then you can save the xdoc into a file, or put it into a string, for example:
XmlTextWriter xw = new XmlTextWriter(new MemoryStream(),Encoding.UTF8);
xdoc.Save(xw);
xw.BaseStream.Position = 0;
StreamReader sr = new StreamReader(xw.BaseStream);
string result = sr.ReadToEnd();
This looks pretty much as what you are looking for.