Commit bc1574af authored by R.W.Majeed's avatar R.W.Majeed

JAXB fact xml now namespace aware

parent aa194cef
......@@ -17,7 +17,8 @@
limitations under the License.
#L%
-->
<dwh-eav xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<eav-data xmlns="http://sekmi.de/histream/ns/eav-data"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- TODO namespace xmlns="http://sekmi.de/histream/dwh-eav..." -->
<!-- chronologisch impliziert, dass der zeitstempel eines nachfolgenden elementes gr��er als alle vorangehenden elemente sein muss. Der Zeitstempel kann vor dem Encounter-Start liegen -->
<meta>
......@@ -27,29 +28,31 @@
<!-- weitere metadaten n�tig? wertebereich, datentypen, ontologie, ...? -->
</meta>
<visit>
<patid>XX12345</patid>
<patient id="XX12345">
<surname>Dampf</surname>
<names>A</names>
<birthdate>2001-01-01</birthdate>
<deathdate>2020</deathdate>
<sex>F</sex>
<encounter start="2014-01-01T10:30:00" end="2014-01-05T10:30:00">XXE12345</encounter>
<location>Zuhause</location>
<!-- TODO inpatient/outpatient -->
<provider>xxxa</provider>
<facts>
<!-- test parsing of data types -->
<fact concept="source1"><value xsi:type="string">1</value></fact>
<fact concept="source1"><value xsi:type="string">2</value></fact>
<fact concept="source2"><value xsi:type="string">1</value></fact>
<fact concept="source3"><value xsi:type="string">1</value></fact>
<fact concept="source3"><value xsi:type="string">2</value></fact>
<fact concept="source3"><value xsi:type="string">99</value></fact>
<encounter id="XXE12345">
<start>2014-01-01T10:30:00</start>
<end>2014-01-05T10:30:00</end>
<location>Zuhause</location>
<!-- TODO inpatient/outpatient -->
<provider>xxxa</provider>
<facts>
<!-- test parsing of data types -->
<fact concept="source1"><value xsi:type="string">1</value></fact>
<fact concept="source1"><value xsi:type="string">2</value></fact>
<fact concept="source2"><value xsi:type="string">1</value></fact>
<fact concept="source3"><value xsi:type="string">1</value></fact>
<fact concept="source3"><value xsi:type="string">2</value></fact>
<fact concept="source3"><value xsi:type="string">99</value></fact>
</facts>
</visit>
</facts>
</encounter>
</patient>
<!-- weitere zeitstempel -->
</dwh-eav>
</eav-data>
......@@ -37,7 +37,7 @@
skos:notation "source1" ;
dwh:mapFact [
a dwh:MapRule ; # optional
dwh:condition "fact/value='1'"^^dwh:XPath ;
dwh:condition "f:fact/f:value='1'"^^dwh:XPath ;
dwh:target :t1 ;
dwh:modify dwh:removeValue
] .
......
......@@ -17,8 +17,8 @@
limitations under the License.
#L%
-->
<eav-data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<!-- TODO namespace xmlns="http://sekmi.de/histream/dwh-eav..." -->
<eav-data xmlns="http://sekmi.de/histream/ns/eav-data"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- chronologisch impliziert, dass der zeitstempel eines nachfolgenden elementes
größer als alle vorangehenden elemente sein muss. Der Zeitstempel kann vor dem
Encounter-Start liegen -->
......@@ -27,7 +27,7 @@
<etl strategy="replace-visit" />
<source timestamp="2015-04-21T08:58:00" id="test"/>
<!-- weitere metadaten ntig? wertebereich, datentypen, ontologie, ...? -->
<!-- weitere metadaten nötig? wertebereich, datentypen, ontologie, ...? -->
</meta>
<patient id="XX12345">
<surname>Dampf</surname>
......
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"
><!-- targetNamespace="http://sekmi.de/histream/ns/dwh" -->
targetNamespace="http://sekmi.de/histream/ns/eav-data"
xmlns="http://sekmi.de/histream/ns/eav-data">
<!-- value -->
<xs:complexType name="valueType">
<xs:simpleContent>
......
<?xml version="1.0" encoding="UTF-8"?>
<fact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="fact.xsd"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<fact xmlns="http://sekmi.de/histream/ns/eav-data"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://sekmi.de/histream/ns/eav-data fact.xsd"
patient="12345" encounter="23456" concept="T:testconcept1" start="2015-01-09T22:30" end="2015-01" location="L:ocation" provider="provider">
<value xsi:type="numeric" unit="mm" flag="A" operator="E">123</value>
<modifier code="M:test"><value xsi:type="string">123</value></modifier>
......
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:fact patient="12345" encounter="23456" concept="T:testconcept1" start="2015-01-09T22:30" end="2015-01" location="L:ocation" provider="provider"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns3="http://sekmi.de/histream/ns/eav-data">
<value xsi:type="ns3:numeric" unit="mm" flag="A" operator="E">123</value>
<modifier code="M:test"><value xsi:type="ns3:string">123</value></modifier>
</ns3:fact>
\ No newline at end of file
......@@ -34,6 +34,26 @@
</execution>
</executions>
</plugin>
<!--
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>schemagen</id>
<goals>
<goal>schemagen</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/java/de/sekmi/histream/impl</source>
</sources>
</configuration>
</plugin>
-->
</plugins>
</build>
<dependencies>
......
......@@ -26,11 +26,9 @@ import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
@XmlRootElement(name="value")
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name="numeric")
public class NumericValue extends AbstractValue {
......
......@@ -52,6 +52,7 @@ import de.sekmi.histream.Value;
@XmlType(propOrder={"abstractValue","modifierList"})
@XmlSeeAlso({StringValue.class,NumericValue.class})
public class ObservationImpl implements Observation{
public static final String XML_NAMESPACE="http://sekmi.de/histream/ns/eav-data";
@XmlTransient
protected ObservationFactoryImpl factory;
......
......@@ -25,11 +25,9 @@ import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
@XmlRootElement(name="value")
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name="string")
public class StringValue extends AbstractValue{
......
package de.sekmi.histream.impl;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
......@@ -14,6 +20,8 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import de.sekmi.histream.Observation;
......@@ -24,6 +32,8 @@ import de.sekmi.histream.eval.ScriptException;
* Evaluate XPath expressions for observations.
* <p>
* Each observations is converted to XML via JAXB with {@link ObservationImpl}.
* In XPath 1.0, null namespace means no namespace. Therefore all namespace information is removed from the DOM.
*
* The XML looks like:
* <pre>{@code
* <fact patient="XX12345" encounter="XXE12345" concept="T:group:1" start="2014-01-01T010:30:00" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
......@@ -42,16 +52,58 @@ import de.sekmi.histream.eval.ScriptException;
*/
public class XPathEvaluator implements Engine{
private XPathFactory factory;
private XPath xpath;
XPath xpath;
private JAXBContext jaxb;
private Marshaller marshaller;
private static final NamespaceContext namespaceContext = new NamespaceContext() {
@Override
public Iterator<?> getPrefixes(String namespaceURI) {
String prefix = getPrefix(namespaceURI);
if( prefix == null )return Arrays.asList().iterator();
else if( namespaceURI.equals(ObservationImpl.XML_NAMESPACE) ){
return Arrays.asList(prefix,"f").iterator();
}else return Arrays.asList(prefix).iterator();
}
@Override
public String getPrefix(String namespaceURI) {
switch( namespaceURI ){
case ObservationImpl.XML_NAMESPACE:
return XMLConstants.DEFAULT_NS_PREFIX;
case XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI:
return "xsi";
case XMLConstants.XML_NS_URI:
return XMLConstants.XML_NS_PREFIX;
case XMLConstants.XMLNS_ATTRIBUTE_NS_URI:
return XMLConstants.XMLNS_ATTRIBUTE;
}
return null;
}
@Override
public String getNamespaceURI(String prefix) {
switch( prefix ){
case XMLConstants.DEFAULT_NS_PREFIX:
case "f":
return ObservationImpl.XML_NAMESPACE;
case "xsi":
return XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
case XMLConstants.XML_NS_PREFIX:
return XMLConstants.XML_NS_URI;
case XMLConstants.XMLNS_ATTRIBUTE:
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
}
return XMLConstants.NULL_NS_URI;
}
};
public XPathEvaluator() throws JAXBException{
this.factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
this.xpath.setNamespaceContext(namespaceContext);
this.jaxb = JAXBContext.newInstance(ObservationImpl.class);
this.marshaller = jaxb.createMarshaller();
//this.marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE);
//this.marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
}
public static final String toXMLString(Observation fact){
......@@ -69,8 +121,19 @@ public class XPathEvaluator implements Engine{
private Node getObservationNode(Observation fact) throws ScriptException{
DOMResult dom = new DOMResult();
try {
/*DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setNamespaceAware(false);
Document d = f.newDocumentBuilder().newDocument();
DOMConfiguration dc = d.getDomConfig();
dc.setParameter("namespace-declarations", false);
dc.setParameter("namespaces", false);
dom = new DOMResult(d);
marshaller.marshal(fact, d.getDocumentElement());
System.out.println("XX:"+dom.getNode().getOwnerDocument().getDomConfig().getParameter("namespaces"));
TODO: find a way to produce a DOM without namespaces, then remove namespaces from XPaths in XPathEvaluatorTest and test-mapping.ttl
*/
marshaller.marshal(fact, dom);
//marshaller.marshal(fact, System.out);
marshaller.marshal(fact, System.out);
} catch (JAXBException e) {
throw new ScriptException(e);
}
......
......@@ -5,9 +5,12 @@
*
*/
@XmlSchema(
@XmlSchema(namespace=ObservationImpl.XML_NAMESPACE,
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns = {
@XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
@XmlNs(prefix = "xsi", namespaceURI = javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
//"http://www.w3.org/2001/XMLSchema-instance"
}
)
package de.sekmi.histream.impl;
......
......@@ -37,7 +37,8 @@ import de.sekmi.histream.Value;
public class ObservationImplJAXBTest {
public static final File EXAMPLE_FACT_XSD = new File("examples/fact.xsd");
public static final File[] EXAMPLE_FACT_FILES = new File[]{
new File("examples/fact1.xml")
new File("examples/fact1.xml"),
// new File("examples/fact2.xml"),
};
JAXBContext jaxb;
......@@ -84,7 +85,7 @@ public class ObservationImplJAXBTest {
DOMResult dom = new DOMResult();
ObservationImpl o = createObservation(i);
JAXB.marshal(o, dom);
JAXB.marshal(o, System.out);
}
}
@Test
......@@ -98,7 +99,9 @@ public class ObservationImplJAXBTest {
Object o2;
try{
m.marshal(o1, s);
System.out.println("Marshal+Unmarshal["+i+"]: "+s.toString());
o2 = u.unmarshal(new StringReader(s.toString()));
}catch( Throwable e ){
throw new Exception("Error for observation "+i, e);
}
......@@ -106,7 +109,7 @@ public class ObservationImplJAXBTest {
Assert.assertEquals(ObservationImpl.class, o2.getClass());
// verify values
Assert.assertEquals(o1.getValue(), ((ObservationImpl)o2).getValue());
System.out.println("Value:"+((ObservationImpl)o2).getValue());
ObservationImpl ou = (ObservationImpl)o2;
switch( i ){
case 0:
......
package de.sekmi.histream.impl;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBException;
import org.junit.Assert;
......@@ -19,6 +20,11 @@ public class XPathEvaluatorTest {
eval = new XPathEvaluator();
}
@Test
public void testDefaultNamespace(){
Assert.assertEquals(ObservationImpl.XML_NAMESPACE, eval.xpath.getNamespaceContext().getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
}
@Test
public void testExpressions() throws Exception{
FileObservationProviderTest t = new FileObservationProviderTest();
......@@ -27,7 +33,7 @@ public class XPathEvaluatorTest {
Observation o = s.get();
//System.out.println("XXX:"+eval.evaluateToString("translate(fact/@start,'-:T','')", o));
//System.out.println(XPathEvaluator.toXMLString(o));
String[] trueExpressions = new String[]{"fact/@patient", "fact/@concept", "fact/@start", "number(translate(fact/@start,'-:T',''))=201409070104003"};
String[] trueExpressions = new String[]{"f:fact/@patient", "f:fact/@concept", "f:fact/@start", "number(translate(f:fact/@start,'-:T',''))=201409070104003"};
for( String expr : trueExpressions ){
Assert.assertEquals(expr, true, eval.test(expr, o));
}
......@@ -37,21 +43,21 @@ public class XPathEvaluatorTest {
}
// compare string value
Assert.assertEquals(true, eval.test("fact/value='abc123'", o));
Assert.assertEquals(true, eval.test("f:fact/f:value='abc123'", o));
// compare numeric value
o = s.get();
Assert.assertEquals(true, eval.test("fact/value > 122 and fact/value < 124", o));
Assert.assertEquals(true, eval.test("f:fact/f:value > 122 and f:fact/f:value < 124", o));
// compare value with unit
// XXX flag not supported yet
o = s.get();
o = s.get();
Assert.assertEquals(true, eval.test("fact/value/@unit = 'mm' and fact/value > 123", o));
Assert.assertEquals(true, eval.test("f:fact/f:value/@unit = 'mm' and f:fact/f:value > 123", o));
// compare modifier values
o = s.get();
Assert.assertEquals(true, eval.test("fact/modifier[@code='T:mod:3']/value = 78.9 and fact/modifier[@code='T:mod:1']", o));
Assert.assertEquals(true, eval.test("f:fact/f:modifier[@code='T:mod:3']/f:value = 78.9 and f:fact/f:modifier[@code='T:mod:1']", o));
s.close();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment