Index: src/main/java/org/exolab/castor/xml/UnmarshalHandler.java =================================================================== --- src/main/java/org/exolab/castor/xml/UnmarshalHandler.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/UnmarshalHandler.java (Arbeitskopie) @@ -58,6 +58,8 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; import java.util.Stack; import java.util.StringTokenizer; @@ -764,7 +766,7 @@ state.buffer.setLength(0); } - if (type == String.class) { + if (type == String.class && !((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { if (str != null) state.object = str; else if (state.nil) { @@ -780,7 +782,10 @@ state.object = new byte[0]; else { //-- Base64/HexBinary decoding - if (HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { + if ((descriptor.isMultivalued() + && HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) + || HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { +// if (HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) { state.object = HexDecoder.decode(str); } else { state.object = Base64Decoder.decode(str); @@ -790,6 +795,19 @@ else if (state.args != null) { state.object = createInstance(state.type, state.args); } + // TODO: !!! need to make this more explicit !!! + else if (descriptor.isMultivalued() + && descriptor.getSchemaType() != null + && descriptor.getSchemaType().equals("list") + && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { + StringTokenizer attrValueTokenizer = new StringTokenizer(str); + List primitives = new ArrayList(); + while (attrValueTokenizer.hasMoreTokens()) { + String tokenValue = attrValueTokenizer.nextToken(); + primitives.add(toPrimitiveObject(type, tokenValue, state.fieldDesc)); + } + state.object = primitives; + } else state.object = toPrimitiveObject(type,str,state.fieldDesc); } else if (ArrayHandler.class.isAssignableFrom(state.type)) { @@ -812,7 +830,9 @@ //-- handle base64/hexBinary if (valueType.isArray() && (valueType.getComponentType() == Byte.TYPE)) { - if (HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { + if ((descriptor.isMultivalued() + && HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) + || HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { value = HexDecoder.decode((String) value); } else { value = Base64Decoder.decode((String) value); @@ -1030,16 +1050,34 @@ if (firstOccurance && _clearCollections) { handler.resetValue(state.object); } + + if (descriptor.isMultivalued() + && descriptor.getSchemaType() != null + && descriptor.getSchemaType().equals("list") + && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { + List values = (List) val; + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + //-- finally set the value!! + Object value = iterator.next(); + handler.setValue(state.object, value); + + // If there is a parent for this object, pass along + // a notification that we've finished adding a child + if ( _unmarshalListener != null ) { + _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); + } + } + } else { - //-- finally set the value!! - handler.setValue(state.object, val); - - // If there is a parent for this object, pass along - // a notification that we've finished adding a child - if ( _unmarshalListener != null ) { - _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); - } + //-- finally set the value!! + handler.setValue(state.object, val); + // If there is a parent for this object, pass along + // a notification that we've finished adding a child + if ( _unmarshalListener != null ) { + _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); + } + } } } @@ -3010,53 +3048,70 @@ //-- if this is an multi-value attribute - StringTokenizer attrValueTokenizer = null; - if (descriptor.isMultivalued()) - { - attrValueTokenizer = new StringTokenizer(attValue); - if(attrValueTokenizer.hasMoreTokens()) - attValue = attrValueTokenizer.nextToken(); + if (descriptor.isMultivalued()) { + StringTokenizer attrValueTokenizer = new StringTokenizer(attValue); + while (attrValueTokenizer.hasMoreTokens()) { + attValue = attrValueTokenizer.nextToken(); + setAttributeValueOnObject(attValue, descriptor, parent, handler, + type, isPrimative, isQName, isByteArray); + } + } else { + setAttributeValueOnObject(attValue, descriptor, parent, handler, + type, isPrimative, isQName, isByteArray); } + + } //-- processAttribute + + /** + * Sets the value of an attribute on the target object, using the {@link FieldHandler} + * provided. + * @param attValue The attribute value. + * @param descriptor Corresponding {@link XMLFieldDescriptor} instance for the attribute processed. + * @param parent Parent object into which attribute value needs to be 'injected'. + * @param handler {@link FieldHandler} used for 'value injection'. + * @param type {@link Class} type. + * @param isPrimitive Indicates whether the attribute value represents a primitive value. + * @param isQName Indicates whether the attribute value represents a QName value. + * @param isByteArray Indicates whether the attribute value represents a byte array. + * @throws SAXException If there's a problem 'injecting' the attribute value into the target field. + */ + private void setAttributeValueOnObject(final String attValue, + final XMLFieldDescriptor descriptor, + final Object parent, + final FieldHandler handler, + final Class type, + final boolean isPrimitive, + final boolean isQName, + final boolean isByteArray) throws SAXException { + //-- value to set + Object value = attValue; + //-- special type conversion for primitives + if (isPrimitive) { + value = toPrimitiveObject(type, attValue, descriptor); + } - while(true) - { - //-- value to set - Object value = attValue; - //-- check for proper type and do type conversion - if (isPrimative) - value = toPrimitiveObject(type, attValue, descriptor); - - // special treatment for byte[]s - if (isByteArray) { - if (attValue == null) - value = new byte[0]; - else { - //-- Base64/hexbinary decoding - if (HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { - value = HexDecoder.decode(attValue); - } else { - value = Base64Decoder.decode(attValue); - } + //-- special byte[]s provessing, if required + if (isByteArray) { + if (attValue == null) { + value = new byte[0]; + } else { + //-- Base64/hexbinary decoding + if (HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) { + value = HexDecoder.decode(attValue); + } else { + value = Base64Decoder.decode(attValue); } } - - //-- check if the value is a QName that needs to - //-- be resolved (ns:value -> {URI}value) - if(isQName) - value = resolveNamespace(value); - //-- set value - handler.setValue(parent, value); - //-- more values? - if(attrValueTokenizer==null) - break; - if(!attrValueTokenizer.hasMoreTokens()) - break; - //-- next value - attValue = attrValueTokenizer.nextToken(); } + + //-- QName resolution (ns:value -> {URI}value), if required + if(isQName) { + value = resolveNamespace(value); + } + //-- set value + handler.setValue(parent, value); + } - } //-- processAttribute - /** * Processes the given attribute set, and creates the * constructor arguments Index: src/main/java/org/exolab/castor/xml/XMLFieldDescriptor.java =================================================================== --- src/main/java/org/exolab/castor/xml/XMLFieldDescriptor.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/XMLFieldDescriptor.java (Arbeitskopie) @@ -18,6 +18,7 @@ import java.util.List; import org.exolab.castor.mapping.FieldDescriptor; +import org.exolab.castor.xml.util.XMLFieldDescriptorImpl; /** * XML field descriptor. Wraps {@link FieldDescriptor} and adds @@ -241,12 +242,31 @@ * Returns the possible substitution groups for this class. * @return the possible substitution groups for this class. */ - public List getSubstitutes(); + List getSubstitutes(); /** * Sets the possible substitution groups for this class. * @param substitutes Possible substitution groups for this class. */ - public void setSubstitutes(List substitutes); + void setSubstitutes(List substitutes); + /** + * Sets whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + * @param derivedFromXSList A boolean value, true or false. + */ + void setDerivedFromXSList(boolean derivedFromXSList); + + /** + * Indicates whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + * @param derivedFromXSList Trueif the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. +. + */ + boolean isDerivedFromXSList(); + + String getComponentType(); + + } Index: src/main/java/org/exolab/castor/xml/schema/XMLType.java =================================================================== --- src/main/java/org/exolab/castor/xml/schema/XMLType.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/schema/XMLType.java (Arbeitskopie) @@ -164,7 +164,8 @@ **/ public final boolean isSimpleType() { return ((getStructureType() == Structure.SIMPLE_TYPE) || - (getStructureType() == Structure.UNION)); + (getStructureType() == Structure.UNION) || + (getStructureType() == Structure.LIST)); } //-- isSimpleType Index: src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java =================================================================== --- src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java (Arbeitskopie) @@ -120,7 +120,7 @@ * @return the type of this Schema Structure */ public short getStructureType() { - return Structure.SIMPLE_TYPE; //-- should be changed to LIST + return Structure.LIST; } //-- getStructureType /** Index: src/main/java/org/exolab/castor/xml/Marshaller.java =================================================================== --- src/main/java/org/exolab/castor/xml/Marshaller.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/Marshaller.java (Arbeitskopie) @@ -1688,8 +1688,10 @@ else if (byteArray) { //-- Base64Encoding / HexBinary String schemaType = descriptor.getSchemaType(); + String componentType = descriptor.getComponentType(); char[] chars = new char[0]; - if (HexDecoder.DATA_TYPE.equals(schemaType)) { + if ((descriptor.isMultivalued() && HexDecoder.DATA_TYPE.equals(componentType)) || + HexDecoder.DATA_TYPE.equals(schemaType)) { chars = new String(HexDecoder.encode((byte[]) object)).toCharArray(); } else { chars = Base64Encoder.encode((byte[]) object); @@ -1868,6 +1870,22 @@ //-- handle byte arrays if (type.isArray() && (type.getComponentType() == Byte.TYPE)) { marshal(obj, elemDescriptor, handler, myState); + } else if (type.isArray() && elemDescriptor.isDerivedFromXSList()) { + Object buffer = processXSListType(obj, elemDescriptor); + String elemName = elemDescriptor.getXMLName(); + String elemQName = elemName; + if ((nsPrefix != null) && (nsPrefix.length() > 0)) { + elemQName = nsPrefix + ':' + elemName; + } + char[] chars = buffer.toString().toCharArray(); + try { + handler.startElement(nsURI, elemName, elemQName, _attributes); + handler.characters(chars,0,chars.length); + handler.endElement(nsURI, elemName, elemQName); + } + catch(org.xml.sax.SAXException sx) { + throw new MarshalException(sx); + } } //-- handle all other collection types else if (isCollection(type)) { @@ -2371,29 +2389,7 @@ } //-- handle multi-value attributes else if (attDescriptor.isMultivalued() && (value != null)) { - Enumeration enumeration = null; - if (value instanceof Enumeration) { - enumeration = (Enumeration)value; - } - else { - CollectionHandler colHandler = null; - try { - colHandler = CollectionHandlers.getHandler(value.getClass()); - } - catch(MappingException mx) { - throw new MarshalException(mx); - } - enumeration = colHandler.elements(value); - } - if (enumeration.hasMoreElements()) { - StringBuffer sb = new StringBuffer(); - for (int v = 0; enumeration.hasMoreElements(); v++) { - if (v > 0) sb.append(' '); - sb.append(enumeration.nextElement().toString()); - } - value = sb; - } - else value = null; + value = processXSListType(value, attDescriptor); } else if (value != null) { //-- handle hex/base64 content @@ -2420,6 +2416,50 @@ } //-- processAttribute + private Object processXSListType(final Object value, XMLFieldDescriptor descriptor) + throws MarshalException { + Object returnValue = null; + Enumeration enumeration = null; + if (value instanceof Enumeration) { + enumeration = (Enumeration)value; + } + else { + CollectionHandler colHandler = null; + try { + colHandler = CollectionHandlers.getHandler(value.getClass()); + } + catch(MappingException mx) { + throw new MarshalException(mx); + } + enumeration = colHandler.elements(value); + } + if (enumeration.hasMoreElements()) { + StringBuffer sb = new StringBuffer(); + for (int v = 0; enumeration.hasMoreElements(); v++) { + if (v > 0) { + sb.append(' '); + } + Object collectionValue = enumeration.nextElement(); +// //-- handle hex/base64 content +// Class objType = collectionValue.getClass(); +// if (objType.isArray() && (objType.getComponentType() == Byte.TYPE)) { +// final String schemaType = descriptor.getSchemaType(); +// if (HexDecoder.DATA_TYPE.equals(schemaType)) { +// collectionValue = new String(HexDecoder.encode((byte[]) value)); +// } else { +// collectionValue = new String(Base64Encoder.encode((byte[]) value)); +// } +// } + + sb.append(collectionValue.toString()); + } + returnValue = sb; + } + + return returnValue; + } + + /** * Processes the attributes for container objects * Index: src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java =================================================================== --- src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java (Revision 7394) +++ src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java (Arbeitskopie) @@ -99,6 +99,9 @@ /** The XML Schema type of this field value. */ private String _schemaType = null; + /** The XML Schema type of the components for XML schema lists. */ + private String _componentType = null; + /** The prefix used in case the value of the field described is of type QName. */ private String _qNamePrefix = null; @@ -107,7 +110,10 @@ private FieldValidator _validator = null; - /** The XML name of the field, this is only the local name. */ + /** + * The local XML name of the field; this does not include any + * path elements. + */ private String _xmlName = null; /** The relative XML path used when wrapping in nested elements, does not @@ -116,6 +122,12 @@ private String _xmlPath = null; private List _substitutes; + + /** + * Indicates whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + */ + private boolean _derivedFromXSList; //----------------/ @@ -430,6 +442,16 @@ } /** + * Sets the type of the XML Schema type of the value for the field being + * described. + * + * @param componentType The component type for <xs:list>s. + */ + public void setComponentType(final String componentType) { + _componentType = componentType; + } + + /** * @see org.exolab.castor.xml.XMLFieldDescriptor#getSchemaType() * {@inheritDoc} */ @@ -437,6 +459,10 @@ return _schemaType; } + public String getComponentType() { + return _componentType; + } + public void setValidator(final FieldValidator validator) { if (_validator != null) { _validator.setDescriptor(null); @@ -793,4 +819,22 @@ _substitutes = substitutes; } + /** + * {@inheritDoc} + * + * @see org.exolab.castor.xml.XMLFieldDescriptor#setDerivedFromXSList(boolean) + */ + public void setDerivedFromXSList(final boolean derivedFromXSList) { + _derivedFromXSList = derivedFromXSList; + } + + /** + * {@inheritDoc} + * + * @see org.exolab.castor.xml.XMLFieldDescriptor#isDerivedFromXSList() + */ + public boolean isDerivedFromXSList() { + return _derivedFromXSList; + } + } Index: xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/xsdList.xsd =================================================================== --- xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/xsdList.xsd (Revision 0) +++ xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/xsdList.xsd (Revision 0) @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ Kein Zeilenvorschub am Ende der Datei Eigenschafts„nderungen: xmlctf\tests\MasterTestSuite\sourcegenerator\xsd-list\xsdList.xsd ___________________________________________________________________ Name: svn:mime-type + text/xml Name: svn:keywords + Id Name: svn:eol-style + native Index: xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/TestDescriptor.xml =================================================================== --- xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/TestDescriptor.xml (Revision 0) +++ xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/TestDescriptor.xml (Revision 0) @@ -0,0 +1,18 @@ + + + Test the use of xsd-list in the Marshalling Framework + Joachim Grueneis + xsd:list requires special handling for attributes and elements + and this test will ensure that it is correctly performed. + basic capability + + + xsdList.xsd + XmlListSample + + Test Generation + input.xml + input.xml + + + Eigenschafts„nderungen: xmlctf\tests\MasterTestSuite\sourcegenerator\xsd-list\TestDescriptor.xml ___________________________________________________________________ Name: svn:mime-type + text/xml Name: svn:keywords + Id Name: svn:eol-style + native Index: xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/input.xml =================================================================== --- xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/input.xml (Revision 0) +++ xmlctf/tests/MasterTestSuite/sourcegenerator/xsd-list/input.xml (Revision 0) @@ -0,0 +1,22 @@ + + + 1000 + 2000 + 3000 + 4000 + firstString + secondString + thirdString + 014A + 014A + 100 200 300 400 500 + string100 string200 string300 string400 string500 + + Eigenschafts„nderungen: xmlctf\tests\MasterTestSuite\sourcegenerator\xsd-list\input.xml ___________________________________________________________________ Name: svn:mime-type + text/xml Name: svn:keywords + Id Name: svn:eol-style + native Index: codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java (Revision 7394) +++ codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java (Arbeitskopie) @@ -59,6 +59,7 @@ import org.exolab.castor.builder.info.CollectionInfo; import org.exolab.castor.builder.info.FieldInfo; import org.exolab.castor.builder.info.XMLInfo; +import org.exolab.castor.builder.types.XSList; import org.exolab.castor.builder.types.XSListType; import org.exolab.castor.builder.types.XSType; import org.exolab.castor.xml.XMLConstants; @@ -328,6 +329,7 @@ final JSourceCode jsc) { XSType xsType = member.getSchemaType(); + XSType xsCollectionType = null; boolean any = false; boolean isElement = (member.getNodeType() == XMLInfo.ELEMENT_TYPE); boolean isAttribute = (member.getNodeType() == XMLInfo.ATTRIBUTE_TYPE); @@ -343,6 +345,7 @@ if (xsType.isCollection()) { //Attributes can handle COLLECTION type for NMTOKENS or IDREFS for instance + xsCollectionType = xsType; xsType = ((CollectionInfo) member).getContent().getSchemaType(); } @@ -435,7 +438,15 @@ } // Add the schema type as defined in the schema - jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");"); + if (xsCollectionType == null) { + jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");"); + } else { + jsc.add("desc.setSchemaType(\"list\");"); + jsc.add("desc.setComponentType(\"" + xsType.getName() + "\");"); + if (xsCollectionType instanceof XSList && ((XSList) xsCollectionType).isDerivedFromXSList()) { + jsc.add("desc.setDerivedFromXSList(true);"); + } + } jsc.add("desc.setHandler(handler);"); //-- container Index: codegen/src/main/java/org/exolab/castor/builder/types/XSList.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/types/XSList.java (Revision 7394) +++ codegen/src/main/java/org/exolab/castor/builder/types/XSList.java (Arbeitskopie) @@ -29,6 +29,12 @@ /** Type number of this XSType. */ public static final short TYPE = XSType.COLLECTION; + + /** + * Indicates whether this {@link XSList} instance has been created as a result + * of a definition. + */ + private boolean _derivedFromXSList; //-------------------------------------------------------------------------- @@ -61,6 +67,25 @@ final String fixedValue, final String validatorInstanceName) { getContentType().validationCode(jsc, fixedValue, validatorInstanceName); } + + /** + * Sets whether this {@link XSList} instance has been created as a result + * of a definition. + * @param derivedFromXSList A boolean value, true or false. + */ + public void setDerivedFromXSList(final boolean derivedFromXSList) { + _derivedFromXSList = derivedFromXSList; + } + + /** + * Indicates whether this {@link XSList} instance has been created as a result + * of a definition. + * @param derivedFromXSList True if this XSList instance has been created as a result + * of a definition. + */ + public boolean isDerivedFromXSList() { + return _derivedFromXSList; + } //-------------------------------------------------------------------------- } Index: codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java (Revision 7394) +++ codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java (Arbeitskopie) @@ -63,6 +63,7 @@ import org.exolab.castor.builder.info.CollectionInfo; import org.exolab.castor.builder.info.FieldInfo; import org.exolab.castor.builder.info.XMLInfo; +import org.exolab.castor.builder.types.XSList; import org.exolab.castor.builder.types.XSListType; import org.exolab.castor.builder.types.XSClass; import org.exolab.castor.builder.types.XSString; @@ -253,7 +254,7 @@ boolean simpleTypeCollection = false; if (xmlType != null) { - if (xmlType.isSimpleType()) { + if (xmlType.isSimpleType() ) { SimpleType simpleType = (SimpleType) xmlType; SimpleType baseType = null; @@ -392,6 +393,10 @@ if (!simpleTypeCollection) { xsList.setMaximumSize(maxOccurs); xsList.setMinimumSize(minOccurs); + } else { + if (xsList instanceof XSList) { + ((XSList) xsList).setDerivedFromXSList(true); + } } fieldInfo = cInfo; } else {