/// <summary> /// Reads a property value and adds it as a text or a sub-property of /// the specified <paramref name="property"/>. /// </summary> /// <param name="property">Property to read content into.</param> private void ReadPropertyValueIntoResult(AtomContentProperty property) { Debug.Assert(this.reader != null, "reader != null"); Debug.Assert(property != null, "property != null"); switch (this.reader.NodeType) { case XmlNodeType.CDATA: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Text: if (property.PrimitiveToken != null) { throw Error.InvalidOperation(Strings.Deserialize_MixedTextWithComment); } // this is a string token property.PrimitiveToken = new TextPrimitiveParserToken(this.reader.Value); break; case XmlNodeType.Comment: case XmlNodeType.Whitespace: case XmlNodeType.ProcessingInstruction: case XmlNodeType.EndElement: // Do nothing. // ProcessingInstruction, Whitespace would have thrown before break; case XmlNodeType.Element: // We found an element while reading a property value. This should be // a complex type. if (property.PrimitiveToken != null) { throw Error.InvalidOperation(Strings.Deserialize_ExpectingSimpleValue); } // Complex types: property.EnsureProperties(); AtomContentProperty prop = this.ReadPropertyValue(); if (prop != null) { property.Properties.Add(prop); } break; default: throw Error.InvalidOperation(Strings.Deserialize_ExpectingSimpleValue); } }
/// <summary>This method will read a string or a complex type.</summary> /// <returns>The property value read.</returns> /// <remarks>Always checks for null attribute.</remarks> private AtomContentProperty ReadPropertyValue() { Debug.Assert(this.reader != null, "reader != null"); Debug.Assert( this.reader.NodeType == XmlNodeType.Element, "reader.NodeType == XmlNodeType.Element -- otherwise caller is confused as to where the reader is"); if (!this.IsDataWebElement) { // we expect <d:PropertyName>...</d:PropertyName> only CommonUtil.SkipToEndAtDepth(this.reader, this.reader.Depth); return null; } AtomContentProperty result = new AtomContentProperty(); result.Name = this.reader.LocalName; result.TypeName = this.reader.GetAttributeEx(XmlConstants.AtomTypeAttributeName, XmlConstants.DataWebMetadataNamespace); result.IsNull = Util.DoesNullAttributeSayTrue(this.reader); // simple optimization for empty and obviously null properties if (result.IsNull && this.reader.IsEmptyElement) { return result; } PrimitiveType type; if (result.TypeName != null && PrimitiveType.TryGetPrimitiveType(result.TypeName, out type)) { // primitive type - tokenize it // DEVNOTE(pqian): // 1. If the typeName is null, it can be either a complex type or edm.string // We must drill into the element to find out // 2. We should throw if the Edm type is unrecognized, but this was not in V1/V2 // So we need to ignore unknown types result.PrimitiveToken = this.TokenizeFromXml(type); } else { // complex or collection type - recursive parse and store into result if (!this.reader.IsEmptyElement) { int depth = this.reader.Depth; while (this.reader.Read()) { this.ReadPropertyValueIntoResult(result); if (this.reader.Depth == depth) { break; } } } } if (result.PrimitiveToken == null && !result.IsNull) { // Empty String or actual null property can both cause PrimitiveToken to be null // NOTE: Ideally we should leave this null when parsing complex types or collection // But the V1/V2 behavior is to set them as Empty result.PrimitiveToken = TextPrimitiveParserToken.Empty; } return result; }
private void HandleExpandedNavigationProperties(AtomEntry targetEntry, string propertyName, bool isFeed) { Debug.Assert(!this.reader.IsEmptyElement, "the current element has some child content"); if (!ReadChildElement(this.reader, XmlConstants.AtomInlineElementName, XmlConstants.DataWebMetadataNamespace)) { return; } bool emptyInlineCollection = this.reader.IsEmptyElement; object propertyValue = null; if (!emptyInlineCollection) { AtomFeed nestedFeed = null; AtomEntry nestedEntry = null; List<AtomEntry> feedEntries = null; Debug.Assert(this.reader is Xml.XmlWrappingReader, "reader must be a instance of XmlWrappingReader"); Uri readerBaseUri = string.IsNullOrEmpty(this.reader.BaseURI) ? null : new Uri(this.reader.BaseURI, UriKind.Absolute); XmlReader nestedReader = Xml.XmlWrappingReader.CreateReader(readerBaseUri, this.reader.ReadSubtree()); nestedReader.Read(); Debug.Assert(nestedReader.LocalName == "inline", "nestedReader.LocalName == 'inline'"); AtomParser nested = new AtomParser(nestedReader, this.entryCallback, this.typeScheme, this.currentDataNamespace, this.baseUriResolver, this.MaxProtocolVersion); while (nested.Read()) { switch (nested.DataKind) { case AtomDataKind.Feed: feedEntries = new List<AtomEntry>(); nestedFeed = nested.CurrentFeed; propertyValue = nestedFeed; break; case AtomDataKind.Entry: nestedEntry = nested.CurrentEntry; if (feedEntries != null) { feedEntries.Add(nestedEntry); } else { propertyValue = nestedEntry; } break; case AtomDataKind.PagingLinks: // Here the inner feed parser found a paging link, and stored it on nestedFeed.NextPageLink // we are going to add it into a link table and associate // with the collection at AtomMaterializer::Materialize() // Do nothing for now. break; default: throw new InvalidOperationException(Strings.AtomParser_UnexpectedContentUnderExpandedLink); } } if (nestedFeed != null) { Debug.Assert( nestedFeed.Entries == null, "nestedFeed.Entries == null -- otherwise someone initialized this for us"); nestedFeed.Entries = feedEntries; } } AtomContentProperty property = new AtomContentProperty(); property.Name = propertyName; if (emptyInlineCollection || propertyValue == null) { property.IsNull = true; if (isFeed) { property.Feed = new AtomFeed(); property.Feed.Entries = Enumerable.Empty<AtomEntry>(); } else { property.Entry = new AtomEntry(this.MaxProtocolVersion); property.Entry.IsNull = true; } } else { property.Feed = propertyValue as AtomFeed; property.Entry = propertyValue as AtomEntry; } targetEntry.DataValues.Add(property); }