/// <summary>See <see cref="XmlReader.Read"/></summary> public override bool Read() { _state = XIncludingReaderState.Default; //Read internal reader bool baseRead = _reader.Read(); if (baseRead) { //If we are including and including reader is at 0 depth - //we are at a top level included item _topLevel = (_readers.Count > 0 && _reader.Depth == 0) ? true : false; if (_topLevel && _reader.NodeType == XmlNodeType.Attribute) //Attempt to include an attribute or namespace node throw new AttributeOrNamespaceInIncludeLocationError(Monobjc.Tools.Sdp.Properties.Resources.AttributeOrNamespaceInIncludeLocationError); if (_topLevel && ((XmlReader)_readers.Peek()).Depth == 0 && _reader.NodeType == XmlNodeType.Element) { if (_gotTopIncludedElem) //Attempt to include more than one element at the top level throw new MalformedXInclusionResultError(Monobjc.Tools.Sdp.Properties.Resources.MalformedXInclusionResult); else _gotTopIncludedElem = true; } if (_topLevel) { //Check if included item has different language _differentLang = AreDifferentLangs(_reader.XmlLang, ((XmlReader)_readers.Peek()).XmlLang); if (_reader.NodeType == XmlNodeType.Element) { //Record real xml:base index _realXmlBaseIndex = -1; int i = 0; while (_reader.MoveToNextAttribute()) { if (_reader.Name == _keywords.XmlBase) { _realXmlBaseIndex = i; break; } i++; } _reader.MoveToElement(); } } switch (_reader.NodeType) { case XmlNodeType.XmlDeclaration: case XmlNodeType.Document: case XmlNodeType.DocumentType: case XmlNodeType.DocumentFragment: //This stuff should not be included into resulting infoset, //but should be inclused into acquired infoset return _readers.Count > 0 ? Read() : baseRead; case XmlNodeType.Element: //Check for xi:include if (IsIncludeElement(_reader)) { //xi:include element found //Save current reader to possible fallback processing XmlReader current = _reader; try { return ProcessIncludeElement(); } catch (FatalException fe) { throw fe; } catch (Exception e) { //Let's be liberal - any exceptions other than fatal one //should be treated as resource error //Console.WriteLine("Resource error has been detected: " + e.Message); //Start fallback processing if (!current.Equals(_reader)) { _reader.Close(); _reader = current; } _prevFallbackState = _fallbackState; return ProcessFallback(_reader.Depth, e); } //No, it's not xi:include, check it for xi:fallback } else if (IsFallbackElement(_reader)) { //Found xi:fallback not child of xi:include IXmlLineInfo li = _reader as IXmlLineInfo; if (li != null && li.HasLineInfo()) { throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.FallbackNotChildOfIncludeLong, _reader.BaseURI.ToString(), li.LineNumber, li.LinePosition)); } else throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.FallbackNotChildOfInclude, _reader.BaseURI.ToString())); } else { _gotElement = true; goto default; } case XmlNodeType.EndElement: //Looking for end of xi:fallback if (_fallbackState.Fallbacking && _reader.Depth == _fallbackState.FallbackDepth && IsFallbackElement(_reader)) { //End of fallback processing _fallbackState.FallbackProcessed = true; //Now read other ignored content till </xi:fallback> return ProcessFallback(_reader.Depth - 1, null); } else goto default; default: return baseRead; } } else { //No more input - finish possible xi:include processing if (_topLevel) _topLevel = false; if (_readers.Count > 0) { _reader.Close(); //Pop previous reader _reader = (XmlReader)_readers.Pop(); //Successful include - skip xi:include content if (!_reader.IsEmptyElement) CheckAndSkipContent(); return Read(); } else { if (!_gotElement) throw new MalformedXInclusionResultError(Monobjc.Tools.Sdp.Properties.Resources.MalformedXInclusionResult); //That's all, folks return false; } } }
/// <summary> /// Fallback processing. /// </summary> /// <param name="depth"><c>xi:include</c> depth level.</param> /// <param name="e">Resource error, which caused this processing.</param> /// <remarks>When inluding fails due to any resource error, <c>xi:inlcude</c> /// element content is processed as follows: each child <c>xi:include</c> - /// fatal error, more than one child <c>xi:fallback</c> - fatal error. No /// <c>xi:fallback</c> - the resource error results in a fatal error. /// Content of first <c>xi:fallback</c> element is included in a usual way.</remarks> private bool ProcessFallback(int depth, Exception e) { //Read to the xi:include end tag while (_reader.Read() && depth < _reader.Depth) { switch (_reader.NodeType) { case XmlNodeType.Element: if (IsIncludeElement(_reader)) { //xi:include child of xi:include - fatal error IXmlLineInfo li = _reader as IXmlLineInfo; if (li != null && li.HasLineInfo()) { throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.IncludeChildOfIncludeLong, BaseURI.ToString(), li.LineNumber, li.LinePosition)); } else throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.IncludeChildOfInclude, BaseURI.ToString())); } if (IsFallbackElement(_reader)) { //Found xi:fallback if (_fallbackState.FallbackProcessed) { IXmlLineInfo li = _reader as IXmlLineInfo; if (li != null && li.HasLineInfo()) { //Two xi:fallback throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.TwoFallbacksLong, BaseURI.ToString(), li.LineNumber, li.LinePosition)); } else throw new XIncludeSyntaxError(String.Format( CultureInfo.CurrentCulture, Monobjc.Tools.Sdp.Properties.Resources.TwoFallbacks, BaseURI.ToString())); } if (_reader.IsEmptyElement) { //Empty xi:fallback - nothing to include _fallbackState.FallbackProcessed = true; break; } _fallbackState.Fallbacking = true; _fallbackState.FallbackDepth = _reader.Depth; return Read(); } else //Ignore anything else along with its content SkipContent(); break; default: break; } } //xi:include content is read if (!_fallbackState.FallbackProcessed) //No xi:fallback, fatal error throw new FatalResourceException(e); else { //End of xi:include content processing, reset and go forth _fallbackState = _prevFallbackState; return Read(); } }