Example #1
0
        /// <summary>
        /// Reads the current element's content as an ODataValue.
        /// </summary>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read values in ATOM.</param>
        /// <param name="expectedType">The expected type of the annotation, may be null if the term is not defined in the model.</param>
        /// <returns>The deserialized value.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element    - The XML element containing the value to read (also the attributes will be read from it)
        /// Post-Condition:  XmlNodeType.EndElement - The end tag of the element.
        ///                  XmlNodeType.Element    - The empty element node.
        /// </remarks>
        private static ODataValue ReadValueFromElementContent(ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer, IEdmTypeReference expectedType)
        {
            object result = propertyAndValueDeserializer.ReadNonEntityValue(
                expectedType,
                null /*duplicatePropertyNamesChecker*/,
                null /*collectionValidator*/,
                true /*validateNullValue*/,
                false /*epmPresent*/);

            return(result.ToODataValue());
        }
Example #2
0
        /// <summary>
        /// Creates a new ATOM annotation parser.
        /// </summary>
        /// <param name="inputContext">The input context this annotation reader should use to read annotation elements.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read the value of an annotation element.</param>
        internal ODataAtomAnnotationReader(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            DebugUtils.CheckNoExternalCallers();

            this.inputContext = inputContext;
            this.propertyAndValueDeserializer = propertyAndValueDeserializer;
            BufferingXmlReader xmlReader = this.inputContext.XmlReader;

            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTargetAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTermAttribute);
            xmlReader.NameTable.Add(AtomConstants.AtomTypeAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataNullAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationStringAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationBoolAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationDecimalAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationIntAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationFloatAttribute);
            this.odataMetadataNamespace = xmlReader.NameTable.Add(AtomConstants.ODataMetadataNamespace);
            this.attributeElementName   = xmlReader.NameTable.Add(AtomConstants.ODataAnnotationElementName);
        }
 /// <summary>
 /// This method creates and reads the property from the input and 
 /// returns an <see cref="ODataProperty"/> representing the read property.
 /// </summary>
 /// <param name="expectedPropertyTypeReference">The expected type reference of the property to read.</param>
 /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns>
 private ODataProperty ReadPropertyImplementation(IEdmTypeReference expectedPropertyTypeReference)
 {
     ODataAtomPropertyAndValueDeserializer atomPropertyAndValueDeserializer = new ODataAtomPropertyAndValueDeserializer(this);
     return atomPropertyAndValueDeserializer.ReadTopLevelProperty(expectedPropertyTypeReference);
 }
Example #4
0
        /// <summary>
        /// This method creates and reads the property from the input and
        /// returns an <see cref="ODataProperty"/> representing the read property.
        /// </summary>
        /// <param name="property">The <see cref="IEdmProperty"/> producing the property to be read.</param>
        /// <param name="expectedPropertyTypeReference">The expected type reference of the property to read.</param>
        /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns>
        private ODataProperty ReadPropertyImplementation(IEdmStructuralProperty property, IEdmTypeReference expectedPropertyTypeReference)
        {
            ODataAtomPropertyAndValueDeserializer atomPropertyAndValueDeserializer = new ODataAtomPropertyAndValueDeserializer(this);

            return(atomPropertyAndValueDeserializer.ReadTopLevelProperty(property, expectedPropertyTypeReference));
        }
Example #5
0
        /// <summary>
        /// Creates a new instance of this class by consuming xml from the given input context.
        /// </summary>
        /// <param name="inputContext">The input context to use to create the annotation.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use when reading values in the annotation element content.</param>
        /// <returns>The <see cref="AtomInstanceAnnotation"/> populated with the information from the 'm:annotation' XML element, as long as the value is a string. Returns null otherwise.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element    - The annotation element to read.
        /// Post-Condition:  XmlNodeType.Any        - The node after the end of the annotation element, or the same element as in the pre-condition if the annotation was skipped.
        /// </remarks>
        internal static AtomInstanceAnnotation CreateFrom(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            DebugUtils.CheckNoExternalCallers();

            var xmlReader = inputContext.XmlReader;

            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NodeType == XmlNodeType.Element, "xmlReader must be positioned on an Element");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            Debug.Assert(xmlReader.LocalName == "annotation", "Must be positioned on an annotation element");

            string termAttributeValue                 = null;
            string targetAttributeValue               = null;
            string typeAttributeValue                 = null;
            bool   nullAttributePresentAndTrue        = false;
            bool   sawMultipleAttributeValueNotations = false;

            // Notes on "attribute value notation":
            // Empty elements may have the annotation value specified via an attribute on the annotation element.
            // Exactly one of the following attributes must be present if this notation is being used: "string", "int", "bool", "float", "decimal".
            // The value of the annotation is the value of this value-specifying attribute.
            string attributeValueNotationAttributeName  = null;
            string attributeValueNotationAttributeValue = null;
            IEdmPrimitiveTypeReference attributeValueNotationTypeReference = null;

            XmlNameTable xmlNameTable        = xmlReader.NameTable;
            string       metadataNamespace   = xmlNameTable.Get(AtomConstants.ODataMetadataNamespace);
            string       nullAttributeName   = xmlNameTable.Get(AtomConstants.ODataNullAttributeName);
            string       typeAttributeName   = xmlNameTable.Get(AtomConstants.AtomTypeAttributeName);
            string       emptyNamespace      = xmlNameTable.Get(string.Empty);
            string       termAttributeName   = xmlNameTable.Get(AtomConstants.ODataAnnotationTermAttribute);
            string       targetAttributeName = xmlNameTable.Get(AtomConstants.ODataAnnotationTargetAttribute);

            // Loop through all the attributes and remember the ones specific to annotations.
            while (xmlReader.MoveToNextAttribute())
            {
                if (xmlReader.NamespaceEquals(metadataNamespace))
                {
                    if (xmlReader.LocalNameEquals(typeAttributeName))
                    {
                        typeAttributeValue = xmlReader.Value;
                    }
                    else if (xmlReader.LocalNameEquals(nullAttributeName))
                    {
                        nullAttributePresentAndTrue = ODataAtomReaderUtils.ReadMetadataNullAttributeValue(xmlReader.Value);
                    }

                    // Ignore all other attributes in the metadata namespace.
                    // In general, we only fail on reading if we can't make sense of the document any more. Reader should be loose.
                    // If we choose to start recognizing an additional attribute in the metadata namespace later, be careful not to
                    // fail if it doesn't parse correctly (so that we don't cause a breaking change).
                }
                else if (xmlReader.NamespaceEquals(emptyNamespace))
                {
                    if (xmlReader.LocalNameEquals(termAttributeName))
                    {
                        termAttributeValue = xmlReader.Value;

                        // Before doing any other validation or further reading, check whether or not to read this annotation according to the filter.
                        if (propertyAndValueDeserializer.MessageReaderSettings.ShouldSkipAnnotation(termAttributeValue))
                        {
                            xmlReader.MoveToElement();
                            return(null);
                        }
                    }
                    else if (xmlReader.LocalNameEquals(targetAttributeName))
                    {
                        targetAttributeValue = xmlReader.Value;
                    }
                    else
                    {
                        // Check if this attribute is one used by attribute value notation.
                        IEdmPrimitiveTypeReference potentialTypeFromAttributeValueNotation = LookupEdmTypeByAttributeValueNotationName(xmlReader.LocalName);
                        if (potentialTypeFromAttributeValueNotation != null)
                        {
                            // If we've already seen an attribute used for attribute value notation,
                            // throw since we don't know which type to use (even if the values are the same).
                            // But don't throw yet, because we might not have encountered the term name yet,
                            // and the annotation filter might say to ignore this annotation (and so we shouldn't throw).
                            if (attributeValueNotationTypeReference != null)
                            {
                                sawMultipleAttributeValueNotations = true;
                            }

                            attributeValueNotationTypeReference  = potentialTypeFromAttributeValueNotation;
                            attributeValueNotationAttributeName  = xmlReader.LocalName;
                            attributeValueNotationAttributeValue = xmlReader.Value;
                        }
                    }

                    // Ignore all other attributes in the empty namespace.
                }

                // Ignore all other attributes in all other namespaces.
            }

            xmlReader.MoveToElement();

            // The term attribute is required.
            if (termAttributeValue == null)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MissingTermAttributeOnAnnotationElement);
            }

            if (sawMultipleAttributeValueNotations)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MultipleAttributeValueNotationAttributes);
            }

            // If this term is defined in the model, look up its type. If the term is not in the model, this will be null.
            IEdmTypeReference expectedTypeReference = MetadataUtils.LookupTypeOfValueTerm(termAttributeValue, propertyAndValueDeserializer.Model);

            ODataValue annotationValue;

            if (nullAttributePresentAndTrue)
            {
                // The m:null attribute has precedence over the content of the element, thus if we find m:null='true' we ignore the content of the element.
                ReaderValidationUtils.ValidateNullValue(
                    propertyAndValueDeserializer.Model,
                    expectedTypeReference,
                    propertyAndValueDeserializer.MessageReaderSettings,
                    /*validateNullValue*/ true,
                    propertyAndValueDeserializer.Version,
                    termAttributeValue);
                annotationValue = new ODataNullValue();
            }
            else if (attributeValueNotationTypeReference != null)
            {
                annotationValue = GetValueFromAttributeValueNotation(
                    expectedTypeReference,
                    attributeValueNotationTypeReference,
                    attributeValueNotationAttributeName,
                    attributeValueNotationAttributeValue,
                    typeAttributeValue,
                    xmlReader.IsEmptyElement,
                    propertyAndValueDeserializer.Model,
                    propertyAndValueDeserializer.MessageReaderSettings,
                    propertyAndValueDeserializer.Version);
            }
            else
            {
                annotationValue = ReadValueFromElementContent(propertyAndValueDeserializer, expectedTypeReference);
            }

            // Read the end tag (or the start tag if it was an empty element).
            xmlReader.Read();

            return(new AtomInstanceAnnotation(
                       targetAttributeValue,
                       termAttributeValue,
                       annotationValue));
        }