/// <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()); }
/// <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); }
/// <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)); }
/// <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)); }