2121
2222import org .w3c .dom .Node ;
2323
24+ import javax .xml .xpath .XPath ;
25+ import javax .xml .xpath .XPathConstants ;
26+ import javax .xml .xpath .XPathException ;
27+ import javax .xml .xpath .XPathFactory ;
28+
2429import static uk .co .real_logic .sbe .xml .Presence .CONSTANT ;
2530import static uk .co .real_logic .sbe .xml .XmlSchemaParser .handleError ;
2631import static uk .co .real_logic .sbe .xml .XmlSchemaParser .handleWarning ;
@@ -41,6 +46,7 @@ public class EncodedDataType extends Type
4146 private final PrimitiveValue maxValue ;
4247 private final PrimitiveValue nullValue ;
4348 private final String characterEncoding ;
49+ private final String valueRef ;
4450 private boolean varLen ;
4551
4652 /**
@@ -68,6 +74,20 @@ public EncodedDataType(final Node node, final String givenName, final String ref
6874 final String lengthAttr = getAttributeValueOrNull (node , "length" );
6975 length = Integer .parseInt (null == lengthAttr ? "1" : lengthAttr );
7076 varLen = Boolean .parseBoolean (getAttributeValue (node , "variableLength" , "false" ));
77+ valueRef = getAttributeValueOrNull (node , "valueRef" );
78+
79+ if (null != valueRef )
80+ {
81+ if (valueRef .indexOf ('.' ) == -1 )
82+ {
83+ handleError (node , "valueRef format not valid (enum-name.valid-value-name): " + valueRef );
84+ }
85+
86+ if (presence () != CONSTANT )
87+ {
88+ handleError (node , "present must be constant when valueRef is set: " + valueRef );
89+ }
90+ }
7191
7292 if (PrimitiveType .CHAR == primitiveType )
7393 {
@@ -81,23 +101,30 @@ public EncodedDataType(final Node node, final String givenName, final String ref
81101
82102 if (presence () == CONSTANT )
83103 {
84- if (node .getFirstChild () == null )
85- {
86- handleError (node , "type has declared presence as \" constant\" but XML node has no data" );
87- constValue = null ;
88- }
89- else
104+ if (null == valueRef )
90105 {
91- final String nodeValue = node .getFirstChild ().getNodeValue ();
92- if (PrimitiveType .CHAR == primitiveType )
106+ if (node .getFirstChild () == null )
93107 {
94- constValue = processConstantChar (node , lengthAttr , nodeValue );
108+ handleError (node , "type has declared presence as \" constant\" but XML node has no data" );
109+ constValue = null ;
95110 }
96111 else
97112 {
98- constValue = PrimitiveValue .parse (nodeValue , primitiveType );
113+ final String nodeValue = node .getFirstChild ().getNodeValue ();
114+ if (PrimitiveType .CHAR == primitiveType )
115+ {
116+ constValue = processConstantChar (node , lengthAttr , nodeValue );
117+ }
118+ else
119+ {
120+ constValue = PrimitiveValue .parse (nodeValue , primitiveType );
121+ }
99122 }
100123 }
124+ else
125+ {
126+ constValue = lookupValueRef (node );
127+ }
101128 }
102129 else
103130 {
@@ -126,6 +153,47 @@ public EncodedDataType(final Node node, final String givenName, final String ref
126153 }
127154 }
128155
156+ private PrimitiveValue lookupValueRef (final Node node )
157+ {
158+ try
159+ {
160+ final int periodIndex = valueRef .indexOf ('.' );
161+ final String valueRefType = valueRef .substring (0 , periodIndex );
162+
163+ final XPath xPath = XPathFactory .newInstance ().newXPath ();
164+ final Node valueRefNode = (Node )xPath .compile ("/messageSchema/types/enum[@name='" + valueRefType + "']" )
165+ .evaluate (node .getOwnerDocument (), XPathConstants .NODE );
166+
167+ if (valueRefNode == null )
168+ {
169+ XmlSchemaParser .handleError (node , "valueRef not found: " + valueRefType );
170+ return null ;
171+ }
172+
173+ final EnumType enumType = new EnumType (valueRefNode );
174+ if (enumType .encodingType () != primitiveType )
175+ {
176+ handleError (node , "valueRef does not match this type: " + valueRef );
177+ return null ;
178+ }
179+
180+ final String validValueName = valueRef .substring (periodIndex + 1 );
181+ final EnumType .ValidValue validValue = enumType .getValidValue (validValueName );
182+
183+ if (null == validValue )
184+ {
185+ handleError (node , "valueRef for validValue name not found: " + validValueName );
186+ return null ;
187+ }
188+
189+ return validValue .primitiveValue ();
190+ }
191+ catch (final XPathException ex )
192+ {
193+ throw new RuntimeException (ex );
194+ }
195+ }
196+
129197 /**
130198 * Construct a new EncodedDataType with direct values. Does not handle constant values.
131199 *
@@ -156,6 +224,7 @@ public EncodedDataType(
156224 this .maxValue = null ;
157225 this .nullValue = null ;
158226 characterEncoding = null ;
227+ valueRef = null ;
159228 }
160229
161230 /**
@@ -269,6 +338,16 @@ public String characterEncoding()
269338 return characterEncoding ;
270339 }
271340
341+ /**
342+ * Get the value of the valueRef attribute.
343+ *
344+ * @return the value of the valueRef attribute.
345+ */
346+ public String valueRef ()
347+ {
348+ return valueRef ;
349+ }
350+
272351 private PrimitiveValue processConstantChar (final Node node , final String lengthAttr , final String nodeValue )
273352 {
274353 final int valueLength = nodeValue .length ();
0 commit comments