Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / Xslt / XsltLoader.cs / 1305376 / XsltLoader.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- #define XSLT2 using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Reflection; using System.Text; using System.IO; using System.Xml.XPath; using System.Xml.Xsl.Qil; using System.Runtime.Versioning; namespace System.Xml.Xsl.Xslt { using ContextInfo = XsltInput.ContextInfo; using f = AstFactory; using Res = System.Xml.Utils.Res; using TypeFactory = XmlQueryTypeFactory; using QName = XsltInput.DelayedQName; using XsltAttribute = XsltInput.XsltAttribute; internal class XsltLoader : IErrorHelper { private Compiler compiler; private XmlResolver xmlResolver; private QueryReaderSettings readerSettings; private KeywordsTable atoms; // XSLT keywords atomized with QueryReaderSettings.NameTabel private XsltInput input; // Current input stream private Stylesheet curStylesheet; // Current stylesheet private Template curTemplate; // Current template private object curFunction; // Current function private static QilName nullMode = f.QName(string.Empty); // Flags which control attribute versioning public static int V1Opt = 1; public static int V1Req = 2; public static int V2Opt = 4; public static int V2Req = 8; [ResourceConsumption(ResourceScope.Machine)] [ResourceExposure(ResourceScope.Machine)] public void Load(Compiler compiler, object stylesheet, XmlResolver xmlResolver) { Debug.Assert(compiler != null); this.compiler = compiler; this.xmlResolver = xmlResolver ?? XmlNullResolver.Singleton; XmlReader reader = stylesheet as XmlReader; if (reader != null) { readerSettings = new QueryReaderSettings(reader); Load(reader); } else { // We should take DefaultReaderSettings from Compiler.Settings.DefaultReaderSettings. string uri = stylesheet as string; if (uri != null) { // If xmlResolver == null, then the original uri will be resolved using XmlUrlResolver XmlResolver origResolver = xmlResolver ?? new XmlUrlResolver(); Uri resolvedUri = origResolver.ResolveUri(null, uri); if (resolvedUri == null) { throw new XslLoadException(Res.Xslt_CantResolve, uri); } readerSettings = new QueryReaderSettings(new NameTable()); using (reader = CreateReader(resolvedUri, origResolver)) { Load(reader); } } else { IXPathNavigable navigable = stylesheet as IXPathNavigable; if (navigable != null) { reader = XPathNavigatorReader.Create(navigable.CreateNavigator()); readerSettings = new QueryReaderSettings(reader.NameTable); Load(reader); } else { Debug.Fail("Should never get here"); } } } Debug.Assert(compiler.Root != null); compiler.StartApplyTemplates = f.ApplyTemplates(nullMode); ProcessOutputSettings(); foreach (AttributeSet attSet in compiler.AttributeSets.Values) { CheckAttributeSetsDfs(attSet); // Check attribute sets for circular references using dfs marking method } } private void Load(XmlReader reader) { this.atoms = new KeywordsTable(reader.NameTable); AtomizeAttributes(); LoadStylesheet(reader, /*include:*/false); } void AtomizeAttributes(XsltAttribute[] attributes) { for(int i = 0; i < attributes.Length; i ++) { attributes[i].name = atoms.NameTable.Add(attributes[i].name); } } void AtomizeAttributes() { AtomizeAttributes(stylesheetAttributes); AtomizeAttributes(importIncludeAttributes); AtomizeAttributes(loadStripSpaceAttributes); AtomizeAttributes(outputAttributes); AtomizeAttributes(keyAttributes); AtomizeAttributes(decimalFormatAttributes); AtomizeAttributes(namespaceAliasAttributes); AtomizeAttributes(attributeSetAttributes); AtomizeAttributes(templateAttributes); AtomizeAttributes(scriptAttributes); AtomizeAttributes(assemblyAttributes); AtomizeAttributes(usingAttributes); AtomizeAttributes(applyTemplatesAttributes); AtomizeAttributes(callTemplateAttributes); AtomizeAttributes(copyAttributes); AtomizeAttributes(copyOfAttributes); AtomizeAttributes(ifAttributes); AtomizeAttributes(forEachAttributes); AtomizeAttributes(messageAttributes); AtomizeAttributes(numberAttributes); AtomizeAttributes(valueOfAttributes); AtomizeAttributes(variableAttributes); AtomizeAttributes(paramAttributes); AtomizeAttributes(withParamAttributes); AtomizeAttributes(commentAttributes); AtomizeAttributes(processingInstructionAttributes); AtomizeAttributes(textAttributes); AtomizeAttributes(elementAttributes); AtomizeAttributes(attributeAttributes); AtomizeAttributes(sortAttributes); #if XSLT2 AtomizeAttributes(characterMapAttributes); AtomizeAttributes(outputCharacterAttributes); AtomizeAttributes(functionAttributes); AtomizeAttributes(importSchemaAttributes); AtomizeAttributes(documentAttributes); AtomizeAttributes(analyzeStringAttributes); AtomizeAttributes(namespaceAttributes); AtomizeAttributes(performSortAttributes); AtomizeAttributes(forEachGroupAttributes); AtomizeAttributes(sequenceAttributes); AtomizeAttributes(resultDocumentAttributes); #endif } private bool V1 { get { Debug.Assert(compiler.Version != 0, "Version should be already decided at this point"); return compiler.Version == 1; }} #if XSLT2 private bool V2 { get { return ! V1; } } #endif // Import/Include XsltInput management private HybridDictionary documentUriInUse = new HybridDictionary(); [ResourceConsumption(ResourceScope.Machine)] [ResourceExposure(ResourceScope.Machine)] private Uri ResolveUri(string relativeUri, string baseUri) { Uri resolvedBaseUri = (baseUri.Length != 0) ? xmlResolver.ResolveUri(null, baseUri) : null; Uri resolvedUri = xmlResolver.ResolveUri(resolvedBaseUri, relativeUri); if (resolvedUri == null) { throw new XslLoadException(Res.Xslt_CantResolve, relativeUri); } return resolvedUri; } private XmlReader CreateReader(Uri uri, XmlResolver xmlResolver) { object input = xmlResolver.GetEntity(uri, null, null); Stream stream = input as Stream; if (stream != null) { return readerSettings.CreateReader(stream, uri.ToString()); } XmlReader reader = input as XmlReader; if (reader != null) { return reader; } IXPathNavigable navigable = input as IXPathNavigable; if (navigable != null) { return XPathNavigatorReader.Create(navigable.CreateNavigator()); } throw new XslLoadException(Res.Xslt_CannotLoadStylesheet, uri.ToString(), input == null ? "null" : input.GetType().ToString()); } private Stylesheet LoadStylesheet(Uri uri, bool include) { using (XmlReader reader = CreateReader(uri, this.xmlResolver)) { return LoadStylesheet(reader, include); } } private Stylesheet LoadStylesheet(XmlReader reader, bool include) { string baseUri = reader.BaseURI; Debug.Assert(!documentUriInUse.Contains(baseUri), "Circular references must be checked while processing xsl:include and xsl:import"); documentUriInUse.Add(baseUri, null); compiler.AddModule(baseUri); Stylesheet prevStylesheet = curStylesheet; XsltInput prevInput = input; Stylesheet thisStylesheet = include ? curStylesheet : compiler.CreateStylesheet(); input = new XsltInput(reader, compiler, atoms); curStylesheet = thisStylesheet; try { LoadDocument(); if (!include) { compiler.MergeWithStylesheet(curStylesheet); ListimportHrefs = curStylesheet.ImportHrefs; curStylesheet.Imports = new Stylesheet[importHrefs.Count]; // Imports should be compiled in the reverse order. Template lookup logic relies on that. for (int i = importHrefs.Count; 0 <= --i; ) { curStylesheet.Imports[i] = LoadStylesheet(importHrefs[i], /*include:*/false); } } } catch (XslLoadException) { throw; } catch (Exception e) { if (!XmlException.IsCatchableException(e)) { throw; } // Note that XmlResolver or XmlReader may throw XmlException with SourceUri == null. // In that case we report current line information from XsltInput. XmlException ex = e as XmlException; ISourceLineInfo lineInfo = (ex != null && ex.SourceUri != null ? new SourceLineInfo(ex.SourceUri, ex.LineNumber, ex.LinePosition, ex.LineNumber, ex.LinePosition) : input.BuildReaderLineInfo() ); throw new XslLoadException(e, lineInfo); } finally { documentUriInUse.Remove(baseUri); input = prevInput; curStylesheet = prevStylesheet; } return thisStylesheet; } private void LoadDocument() { if (!input.FindStylesheetElement()) { ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement); return; } Debug.Assert(input.NodeType == XmlNodeType.Element); if (input.IsXsltNamespace()) { if ( input.IsKeyword(atoms.Stylesheet) || input.IsKeyword(atoms.Transform) ) { LoadRealStylesheet(); } else { ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement); input.SkipNode(); } } else { LoadSimplifiedStylesheet(); } input.Finish(); } private void LoadSimplifiedStylesheet() { Debug.Assert(!input.IsXsltNamespace()); Debug.Assert(curTemplate == null); // Prefix will be fixed later in LoadLiteralResultElement() curTemplate = f.Template(/*name:*/null, /*match:*/"/", /*mode:*/nullMode, /*priority:*/double.NaN, input.XslVersion); // This template has mode=null match="/" and no imports input.CanHaveApplyImports = true; XslNode lre = LoadLiteralResultElement(/*asStylesheet:*/true); if (lre != null) { SetLineInfo(curTemplate, lre.SourceLine); List content = new List (); content.Add(lre); SetContent(curTemplate, content); if (!curStylesheet.AddTemplate(curTemplate)) { Debug.Fail("AddTemplate() returned false for simplified stylesheet"); } } curTemplate = null; } XsltAttribute[] stylesheetAttributes = { new XsltAttribute("version" , V1Req | V2Req), new XsltAttribute("id" , V1Opt | V2Opt), new XsltAttribute("default-validation" , V2Opt), new XsltAttribute("input-type-annotations", V2Opt), }; private void LoadRealStylesheet() { Debug.Assert(input.IsXsltNamespace() && (input.IsKeyword(atoms.Stylesheet) || input.IsKeyword(atoms.Transform))); ContextInfo ctxInfo = input.GetAttributes(stylesheetAttributes); ParseValidationAttribute(2, /*defVal:*/true); ParseInputTypeAnnotationsAttribute(3); QName parentName = input.ElementName; if (input.MoveToFirstChild()) { bool atTop = true; do { bool isImport = false; switch (input.NodeType) { case XmlNodeType.Element: if (input.IsXsltNamespace()) { if (input.IsKeyword(atoms.Import)) { if (!atTop) { ReportError(/*[XT0200]*/Res.Xslt_NotAtTop, input.QualifiedName, parentName); input.SkipNode(); } else { isImport = true; LoadImport(); } } else if (input.IsKeyword(atoms.Include)) { LoadInclude(); } else if (input.IsKeyword(atoms.StripSpace)) { LoadStripSpace(ctxInfo.nsList); } else if (input.IsKeyword(atoms.PreserveSpace)) { LoadPreserveSpace(ctxInfo.nsList); } else if (input.IsKeyword(atoms.Output)) { LoadOutput(); } else if (input.IsKeyword(atoms.Key)) { LoadKey(ctxInfo.nsList); } else if (input.IsKeyword(atoms.DecimalFormat)) { LoadDecimalFormat(ctxInfo.nsList); } else if (input.IsKeyword(atoms.NamespaceAlias)) { LoadNamespaceAlias(ctxInfo.nsList); } else if (input.IsKeyword(atoms.AttributeSet)) { LoadAttributeSet(ctxInfo.nsList); } else if (input.IsKeyword(atoms.Variable)) { LoadGlobalVariableOrParameter(ctxInfo.nsList, XslNodeType.Variable); } else if (input.IsKeyword(atoms.Param)) { LoadGlobalVariableOrParameter(ctxInfo.nsList, XslNodeType.Param); } else if (input.IsKeyword(atoms.Template)) { LoadTemplate(ctxInfo.nsList); #if XSLT2 } else if (V2 && input.IsKeyword(atoms.CharacterMap)) { LoadCharacterMap(ctxInfo.nsList); } else if (V2 && input.IsKeyword(atoms.Function)) { LoadFunction(ctxInfo.nsList); } else if (V2 && input.IsKeyword(atoms.ImportSchema)) { LoadImportSchema(); #endif } else { input.GetVersionAttribute(); if (!input.ForwardCompatibility) { ReportError(/*[XT_003]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); } input.SkipNode(); } } else if (input.IsNs(atoms.UrnMsxsl) && input.IsKeyword(atoms.Script)) { LoadMsScript(ctxInfo.nsList); } else { if (input.IsNullNamespace()) { ReportError(/*[XT0130]*/Res.Xslt_NullNsAtTopLevel, input.LocalName); } // Ignoring non-recognized namespace per XSLT spec 2.2 input.SkipNode(); } atTop = isImport; break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT0120]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } } XsltAttribute[] importIncludeAttributes = {new XsltAttribute("href" , V1Req | V2Req)}; // SxS: This method reads resource names from source document and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void LoadImport() { ContextInfo ctxInfo = input.GetAttributes(importIncludeAttributes); if (input.MoveToXsltAttribute(0, "href")) { // Resolve href right away using the current BaseUri (it might change later) Uri uri = ResolveUri(input.Value, input.BaseUri); // Check for circular references if (documentUriInUse.Contains(uri.ToString())) { ReportError(/*[XT0210]*/Res.Xslt_CircularInclude, input.Value); } else { curStylesheet.ImportHrefs.Add(uri); } } else { // The error was already reported. Ignore the instruction } CheckNoContent(); } // SxS: This method reads resource names from source document and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void LoadInclude() { ContextInfo ctxInfo = input.GetAttributes(importIncludeAttributes); if (input.MoveToXsltAttribute(0, "href")) { Uri uri = ResolveUri(input.Value, input.BaseUri); // Check for circular references if (documentUriInUse.Contains(uri.ToString())) { ReportError(/*[XT0180]*/Res.Xslt_CircularInclude, input.Value); } else { LoadStylesheet(uri, /*include:*/ true); } } else { // The error was already reported. Ignore the instruction } CheckNoContent(); } XsltAttribute[] loadStripSpaceAttributes = {new XsltAttribute("elements" , V1Req | V2Req)}; private void LoadStripSpace(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(loadStripSpaceAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); if (input.MoveToXsltAttribute(0, atoms.Elements)) { ParseWhitespaceRules(input.Value, false); } CheckNoContent(); } private void LoadPreserveSpace(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(loadStripSpaceAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); if (input.MoveToXsltAttribute(0, atoms.Elements)) { ParseWhitespaceRules(input.Value, true); } CheckNoContent(); } XsltAttribute[] outputAttributes = { new XsltAttribute("name" , V2Opt), new XsltAttribute("method" , V1Opt | V2Opt), new XsltAttribute("byte-order-mark" , V2Opt), new XsltAttribute("cdata-section-elements", V1Opt | V2Opt), new XsltAttribute("doctype-public" , V1Opt | V2Opt), new XsltAttribute("doctype-system" , V1Opt | V2Opt), new XsltAttribute("encoding" , V1Opt | V2Opt), new XsltAttribute("escape-uri-attributes" , V2Opt), new XsltAttribute("include-content-type" , V2Opt), new XsltAttribute("indent" , V1Opt | V2Opt), new XsltAttribute("media-type" , V1Opt | V2Opt), new XsltAttribute("normalization-form" , V2Opt), new XsltAttribute("omit-xml-declaration" , V1Opt | V2Opt), new XsltAttribute("standalone" , V1Opt | V2Opt), new XsltAttribute("undeclare-prefixes" , V2Opt), new XsltAttribute("use-character-maps" , V2Opt), new XsltAttribute("version" , V1Opt | V2Opt) }; private void LoadOutput() { ContextInfo ctxInfo = input.GetAttributes(outputAttributes); Output output = compiler.Output; XmlWriterSettings settings = output.Settings; int currentPrec = compiler.CurrentPrecedence; TriState triState; QilName name = ParseQNameAttribute(0); if (name != null) ReportNYI("xsl:output/@name"); if (input.MoveToXsltAttribute(1, "method")) { if (output.MethodPrec <= currentPrec) { compiler.EnterForwardsCompatible(); XmlOutputMethod outputMethod; XmlQualifiedName method = ParseOutputMethod(input.Value, out outputMethod); if (compiler.ExitForwardsCompatible(input.ForwardCompatibility) && method != null) { if (currentPrec == output.MethodPrec && !output.Method.Equals(method)) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "method"); } settings.OutputMethod = outputMethod; output.Method = method; output.MethodPrec = currentPrec; } } } TriState byteOrderMask = ParseYesNoAttribute(2, "byte-order-mark"); if (byteOrderMask != TriState.Unknown) ReportNYI("xsl:output/@byte-order-mark"); if (input.MoveToXsltAttribute(3, "cdata-section-elements")) { // Do not check the import precedence, the effective value is the union of all specified values compiler.EnterForwardsCompatible(); string[] qnames = XmlConvert.SplitString(input.Value); List list = new List (); for (int i = 0; i < qnames.Length; i++) { list.Add(ResolveQName(/*ignoreDefaultNs:*/false, qnames[i])); } if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { settings.CDataSectionElements.AddRange(list); } } if (input.MoveToXsltAttribute(4, "doctype-public")) { if (output.DocTypePublicPrec <= currentPrec) { if (currentPrec == output.DocTypePublicPrec && settings.DocTypePublic != input.Value) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "doctype-public"); } settings.DocTypePublic = input.Value; output.DocTypePublicPrec = currentPrec; } } if (input.MoveToXsltAttribute(5, "doctype-system")) { if (output.DocTypeSystemPrec <= currentPrec) { if (currentPrec == output.DocTypeSystemPrec && settings.DocTypeSystem != input.Value) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "doctype-system"); } settings.DocTypeSystem = input.Value; output.DocTypeSystemPrec = currentPrec; } } if (input.MoveToXsltAttribute(6, "encoding")) { if (output.EncodingPrec <= currentPrec) { try { // Encoding.GetEncoding() should never throw NotSupportedException, only ArgumentException Encoding encoding = Encoding.GetEncoding(input.Value); if (currentPrec == output.EncodingPrec && output.Encoding != input.Value) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "encoding"); } settings.Encoding = encoding; output.Encoding = input.Value; output.EncodingPrec = currentPrec; } catch (ArgumentException) { if (!input.ForwardCompatibility) { ReportWarning(/*[XT_004]*/Res.Xslt_InvalidEncoding, input.Value); } } } } bool escapeUriAttributes = ParseYesNoAttribute(7, "escape-uri-attributes") != TriState.False; if (! escapeUriAttributes) ReportNYI("xsl:output/@escape-uri-attributes == flase()"); bool includeContentType = ParseYesNoAttribute(8, "include-content-type") != TriState.False; if (!includeContentType) ReportNYI("xsl:output/@include-content-type == flase()"); triState = ParseYesNoAttribute(9, "indent"); if (triState != TriState.Unknown) { if (output.IndentPrec <= currentPrec) { bool indent = (triState == TriState.True); if (currentPrec == output.IndentPrec && settings.Indent != indent) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "indent"); } settings.Indent = indent; output.IndentPrec = currentPrec; } } if (input.MoveToXsltAttribute(10, "media-type")) { if (output.MediaTypePrec <= currentPrec) { if (currentPrec == output.MediaTypePrec && settings.MediaType != input.Value) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "media-type"); } settings.MediaType = input.Value; output.MediaTypePrec = currentPrec; } } if (input.MoveToXsltAttribute(11, "normalization-form")) { ReportNYI("xsl:output/@normalization-form"); } triState = ParseYesNoAttribute(12, "omit-xml-declaration"); if (triState != TriState.Unknown) { if (output.OmitXmlDeclarationPrec <= currentPrec) { bool omitXmlDeclaration = (triState == TriState.True); if (currentPrec == output.OmitXmlDeclarationPrec && settings.OmitXmlDeclaration != omitXmlDeclaration) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "omit-xml-declaration"); } settings.OmitXmlDeclaration = omitXmlDeclaration; output.OmitXmlDeclarationPrec = currentPrec; } } triState = ParseYesNoAttribute(13, "standalone"); if (triState != TriState.Unknown) { if (output.StandalonePrec <= currentPrec) { XmlStandalone standalone = (triState == TriState.True) ? XmlStandalone.Yes : XmlStandalone.No; if (currentPrec == output.StandalonePrec && settings.Standalone != standalone) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "standalone"); } settings.Standalone = standalone; output.StandalonePrec = currentPrec; } } bool undeclarePrefixes = ParseYesNoAttribute(14, "undeclare-prefixes") == TriState.True; if (undeclarePrefixes) ReportNYI("xsl:output/@undeclare-prefixes == true()"); List useCharacterMaps = ParseUseCharacterMaps(15); if (useCharacterMaps.Count != 0) ReportNYI("xsl:output/@use-character-maps"); if (input.MoveToXsltAttribute(16, "version")) { if (output.VersionPrec <= currentPrec) { if (currentPrec == output.VersionPrec && output.Version != input.Value) { ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "version"); } // output.Version = input.Value; output.VersionPrec = currentPrec; } } CheckNoContent(); } /* Default values for method="xml" : version="1.0" indent="no" media-type="text/xml" Default values for method="html": version="4.0" indent="yes" media-type="text/html" Default values for method="text": media-type="text/plain" */ private void ProcessOutputSettings() { Output output = compiler.Output; XmlWriterSettings settings = output.Settings; // version is ignored, indent="no" by default if (settings.OutputMethod == XmlOutputMethod.Html && output.IndentPrec == Output.NeverDeclaredPrec) { settings.Indent = true; } if (output.MediaTypePrec == Output.NeverDeclaredPrec) { settings.MediaType = settings.OutputMethod == XmlOutputMethod.Xml ? "text/xml" : settings.OutputMethod == XmlOutputMethod.Html ? "text/html" : settings.OutputMethod == XmlOutputMethod.Text ? "text/plain" : null; } } private void CheckUseAttrubuteSetInList(IList list) { foreach (XslNode xslNode in list) { switch (xslNode.NodeType) { case XslNodeType.UseAttributeSet: AttributeSet usedAttSet; if (compiler.AttributeSets.TryGetValue(xslNode.Name, out usedAttSet)) { CheckAttributeSetsDfs(usedAttSet); } else { // The error will be reported in QilGenerator while compiling this attribute set. } break; case XslNodeType.List: CheckUseAttrubuteSetInList(xslNode.Content); break; } } } private void CheckAttributeSetsDfs(AttributeSet attSet) { Debug.Assert(attSet != null); switch (attSet.CycleCheck) { case CycleCheck.NotStarted: attSet.CycleCheck = CycleCheck.Processing; CheckUseAttrubuteSetInList(attSet.Content); attSet.CycleCheck = CycleCheck.Completed; break; case CycleCheck.Completed: break; default: Debug.Assert(attSet.CycleCheck == CycleCheck.Processing); Debug.Assert(attSet.Content[0].SourceLine != null); compiler.ReportError(/*[XT0720]*/attSet.Content[0].SourceLine, Res.Xslt_CircularAttributeSet, attSet.Name.QualifiedName); break; } } XsltAttribute[] keyAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("match" , V1Req | V2Req), new XsltAttribute("use" , V1Req | V2Opt), new XsltAttribute("collation", V2Opt) }; private void LoadKey(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(keyAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); QilName keyName = ParseQNameAttribute( 0); string match = ParseStringAttribute( 1, "match"); string use = ParseStringAttribute( 2, "use"); string collation = ParseCollationAttribute(3); input.MoveToElement(); List content = null; if (V1) { if (use == null) { input.SkipNode(); } else { CheckNoContent(); } } else { content = LoadInstructions(); // Load the end tag only if the content is not empty if (content.Count != 0) { content = LoadEndTag(content); } if ((use == null) == (content.Count == 0)) { ReportError(/*[XTSE1205]*/Res.Xslt_KeyCntUse); } else { if (use == null) ReportNYI("xsl:key[count(@use) = 0]"); } } Key key = (Key)SetInfo(f.Key(keyName, match, use, input.XslVersion), null, ctxInfo); if (compiler.Keys.Contains(keyName)) { // Add to the list of previous definitions compiler.Keys[keyName].Add(key); } else { // First definition of key with that name List defList = new List (); defList.Add(key); compiler.Keys.Add(defList); } } XsltAttribute[] decimalFormatAttributes = { new XsltAttribute("name" , V1Opt | V2Opt), new XsltAttribute("infinity" , V1Opt | V2Opt), new XsltAttribute("NaN" , V1Opt | V2Opt), new XsltAttribute("decimal-separator" , V1Opt | V2Opt), new XsltAttribute("grouping-separator", V1Opt | V2Opt), new XsltAttribute("percent" , V1Opt | V2Opt), new XsltAttribute("per-mille" , V1Opt | V2Opt), new XsltAttribute("zero-digit" , V1Opt | V2Opt), new XsltAttribute("digit" , V1Opt | V2Opt), new XsltAttribute("pattern-separator" , V1Opt | V2Opt), new XsltAttribute("minus-sign" , V1Opt | V2Opt) }; private void LoadDecimalFormat(NsDecl stylesheetNsList) { const int NumCharAttrs = 8, NumSignAttrs = 7; ContextInfo ctxInfo = input.GetAttributes(decimalFormatAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); XmlQualifiedName name; if (input.MoveToXsltAttribute(0, "name")) { compiler.EnterForwardsCompatible(); name = ResolveQName(/*ignoreDefaultNs:*/true, input.Value); if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { name = new XmlQualifiedName(); } } else { // Use name="" for the default decimal-format name = new XmlQualifiedName(); } string infinity = DecimalFormatDecl.Default.InfinitySymbol; if (input.MoveToXsltAttribute(1, "infinity")) { infinity = input.Value; } string nan = DecimalFormatDecl.Default.NanSymbol; if (input.MoveToXsltAttribute(2, "NaN")) { nan = input.Value; } char[] DefaultValues = DecimalFormatDecl.Default.Characters; char[] characters = new char[NumCharAttrs]; Debug.Assert(NumCharAttrs == DefaultValues.Length); for (int idx = 0; idx < NumCharAttrs; idx++) { characters[idx] = ParseCharAttribute(3 + idx, decimalFormatAttributes[3 + idx].name, DefaultValues[idx]); } // Check all NumSignAttrs signs are distinct for (int i = 0; i < NumSignAttrs; i++) { for (int j = i+1; j < NumSignAttrs; j++) { if (characters[i] == characters[j]) { // Try move to second attribute and if it is missing to first. bool dummy = input.MoveToXsltAttribute(3 + j, decimalFormatAttributes[3 + j].name) || input.MoveToXsltAttribute(3 + i, decimalFormatAttributes[3 + i].name); Debug.Assert(dummy, "One of the atts should have lineInfo. if both are defualt they can't conflict."); ReportError(/*[XT1300]*/Res.Xslt_DecimalFormatSignsNotDistinct, decimalFormatAttributes[3 + i].name, decimalFormatAttributes[3 + j].name); break; } } } if (compiler.DecimalFormats.Contains(name)) { // Check all attributes have the same values DecimalFormatDecl format = compiler.DecimalFormats[name]; input.MoveToXsltAttribute(1, "infinity"); CheckError(infinity != format.InfinitySymbol, /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, "infinity", infinity); input.MoveToXsltAttribute(2, "NaN"); CheckError(nan != format.NanSymbol, /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, "NaN", nan); for (int idx = 0; idx < NumCharAttrs; idx++) { input.MoveToXsltAttribute(3 + idx, decimalFormatAttributes[3 + idx].name); CheckError(characters[idx] != format.Characters[idx], /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, decimalFormatAttributes[3 + idx].name, char.ToString(characters[idx])); } Debug.Assert(name.Equals(format.Name)); } else { // Add format to the global collection DecimalFormatDecl format = new DecimalFormatDecl(name, infinity, nan, new string(characters)); compiler.DecimalFormats.Add(format); } CheckNoContent(); } XsltAttribute[] namespaceAliasAttributes = { new XsltAttribute("stylesheet-prefix", V1Req | V2Req), new XsltAttribute("result-prefix" , V1Req | V2Req) }; private void LoadNamespaceAlias(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(namespaceAliasAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); string stylesheetNsUri = null; string resultPrefix = null; string resultNsUri = null; if (input.MoveToXsltAttribute(0, "stylesheet-prefix")) { if (input.Value.Length == 0) { ReportError(/*[XT_005]*/Res.Xslt_EmptyNsAlias, "stylesheet-prefix"); } else { stylesheetNsUri = input.LookupXmlNamespace(input.Value == "#default" ? string.Empty : input.Value); } } if (input.MoveToXsltAttribute(1, "result-prefix")) { if (input.Value.Length == 0) { ReportError(/*[XT_005]*/Res.Xslt_EmptyNsAlias, "result-prefix"); } else { resultPrefix = input.Value == "#default" ? string.Empty : input.Value; resultNsUri = input.LookupXmlNamespace(resultPrefix); } } CheckNoContent(); if (stylesheetNsUri == null || resultNsUri == null) { // At least one of attributes is missing or invalid return; } if (compiler.SetNsAlias(stylesheetNsUri, resultNsUri, resultPrefix, curStylesheet.ImportPrecedence)) { // Namespace alias redefinition input.MoveToElement(); ReportWarning(/*[XT0810]*/Res.Xslt_DupNsAlias, stylesheetNsUri); } } XsltAttribute[] attributeSetAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("use-attribute-sets", V1Opt | V2Opt) }; private void LoadAttributeSet(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(attributeSetAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); QilName setName = ParseQNameAttribute(0); Debug.Assert(setName != null, "Required attribute always != null"); AttributeSet set; if (!curStylesheet.AttributeSets.TryGetValue(setName, out set)) { set = f.AttributeSet(setName); // First definition for setName within this stylesheet curStylesheet.AttributeSets[setName] = set; if (!compiler.AttributeSets.ContainsKey(setName)) { // First definition for setName overall, adding it to the list here // to ensure stable order of prototemplate functions in QilExpression compiler.AllTemplates.Add(set); } } List content = new List (); if (input.MoveToXsltAttribute(1, "use-attribute-sets")) { AddUseAttributeSets(content); } QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Element: // Only xsl:attribute's are allowed here if (input.IsXsltKeyword(atoms.Attribute)) { AddInstruction(content, XslAttribute()); } else { ReportError(/*[XT_006]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_006]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } set.AddContent(SetInfo(f.List(), LoadEndTag(content), ctxInfo)); } private void LoadGlobalVariableOrParameter(NsDecl stylesheetNsList, XslNodeType nodeType) { Debug.Assert(curTemplate == null); Debug.Assert(input.CanHaveApplyImports == false); VarPar var = XslVarPar(); // Preserving namespaces to parse content later var.Namespaces = MergeNamespaces(var.Namespaces, stylesheetNsList); CheckError(!curStylesheet.AddVarPar(var), /*[XT0630]*/Res.Xslt_DupGlobalVariable, var.Name.QualifiedName); } //: http://www.w3.org/TR/xslt#section-Defining-Template-Rules XsltAttribute[] templateAttributes = { new XsltAttribute("match" , V1Opt | V2Opt), new XsltAttribute("name" , V1Opt | V2Opt), new XsltAttribute("priority", V1Opt | V2Opt), new XsltAttribute("mode" , V1Opt | V2Opt), new XsltAttribute("as" , V2Opt) }; private void LoadTemplate(NsDecl stylesheetNsList) { Debug.Assert(curTemplate == null); ContextInfo ctxInfo = input.GetAttributes(templateAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); string match = ParseStringAttribute(0, "match"); QilName name = ParseQNameAttribute(1); double priority = double.NaN; if (input.MoveToXsltAttribute(2, "priority")) { priority = XPathConvert.StringToDouble(input.Value); if (double.IsNaN(priority) && !input.ForwardCompatibility) { ReportError(/*[XT0530]*/Res.Xslt_InvalidAttrValue, "priority", input.Value); } } QilName mode = V1 ? ParseModeAttribute(3) : ParseModeListAttribute(3); if (match == null) { CheckError(! input.AttributeExists(1, "name"), /*[XT_007]*/Res.Xslt_BothMatchNameAbsent); CheckError( input.AttributeExists(3, "mode"), /*[XT_008]*/Res.Xslt_ModeWithoutMatch ); mode = nullMode; if (input.AttributeExists(2, "priority")) { if (V1) { ReportWarning(/*[XT_008]*/Res.Xslt_PriorityWithoutMatch); } else { ReportError (/*[XT_008]*/Res.Xslt_PriorityWithoutMatch); } } } if (input.MoveToXsltAttribute(4, "as")) { ReportNYI("xsl:template/@as"); } curTemplate = f.Template(name, match, mode, priority, input.XslVersion); // Template without match considered to not have mode and can't call xsl:apply-imports input.CanHaveApplyImports = (match != null); SetInfo(curTemplate, LoadEndTag(LoadInstructions(InstructionFlags.AllowParam)), ctxInfo ); if (!curStylesheet.AddTemplate(curTemplate)) { ReportError(/*[XT0660]*/Res.Xslt_DupTemplateName, curTemplate.Name.QualifiedName); } curTemplate = null; } #if XSLT2 //: http://www.w3.org/TR/xslt20/#element-character-map XsltAttribute[] characterMapAttributes = { new XsltAttribute("name" , V2Req), new XsltAttribute("use-character-maps", V2Opt) }; XsltAttribute[] outputCharacterAttributes = { new XsltAttribute("character", V2Req), new XsltAttribute("string" , V2Req) }; private void LoadCharacterMap(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(characterMapAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); QilName name = ParseQNameAttribute(0); List useCharacterMaps = ParseUseCharacterMaps(1); ReportNYI("xsl:character-map"); QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Element: // Only xsl:output-character are allowed here if (input.IsXsltKeyword(atoms.OutputCharacter)) { input.GetAttributes(outputCharacterAttributes); ReportNYI("xsl:output-character"); char ch = ParseCharAttribute(0, "character", /*defVal:*/(char)0); string s = ParseStringAttribute(1, "string"); CheckNoContent(); } else { ReportError(/*[XT_006]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_006]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } } //: http://www.w3.org/TR/xslt20/#stylesheet-functions XsltAttribute[] functionAttributes = { new XsltAttribute("name" , V2Req), new XsltAttribute("as" , V2Opt), new XsltAttribute("override", V2Opt) }; private void LoadFunction(NsDecl stylesheetNsList) { Debug.Assert(curTemplate == null); ContextInfo ctxInfo = input.GetAttributes(functionAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); QilName name = ParseQNameAttribute(0); string asType = ParseStringAttribute(1, "as"); bool over = ParseYesNoAttribute(2, "override") == TriState.True; ReportNYI("xsl:function"); Debug.Assert(input.CanHaveApplyImports == false); curFunction = new Object(); LoadInstructions(InstructionFlags.AllowParam); curFunction = null; } //: http://www.w3.org/TR/xslt20/#element-import-schema XsltAttribute[] importSchemaAttributes = { new XsltAttribute("namespace" , V2Opt), new XsltAttribute("schema-location", V2Opt) }; private void LoadImportSchema() { ContextInfo ctxInfo = input.GetAttributes(importSchemaAttributes); ReportError(/*[XTSE1650]*/Res.Xslt_SchemaDeclaration, input.ElementName); input.SkipNode(); } #endif XsltAttribute[] scriptAttributes = { new XsltAttribute("implements-prefix", V1Req | V2Req), new XsltAttribute("language" , V1Opt | V2Opt) }; private void LoadMsScript(NsDecl stylesheetNsList) { ContextInfo ctxInfo = input.GetAttributes(scriptAttributes); ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList); string scriptNs = null; if (input.MoveToXsltAttribute(0, "implements-prefix")) { if (input.Value.Length == 0) { ReportError(/*[XT_009]*/Res.Xslt_EmptyAttrValue, "implements-prefix", input.Value); } else { scriptNs = input.LookupXmlNamespace(input.Value); if (scriptNs == XmlReservedNs.NsXslt) { ReportError(/*[XT_036]*/Res.Xslt_ScriptXsltNamespace); scriptNs = null; } } } if (scriptNs == null) { scriptNs = compiler.CreatePhantomNamespace(); } string language = ParseStringAttribute(1, "language"); if (language == null) { language = "jscript"; } if (! compiler.Settings.EnableScript) { compiler.Scripts.ScriptClasses[scriptNs] = null; input.SkipNode(); return; } ScriptClass scriptClass; StringBuilder scriptCode = new StringBuilder(); string uriString = input.Uri; int lineNumber = 0; int lastEndLine = 0; scriptClass = compiler.Scripts.GetScriptClass(scriptNs, language, (IErrorHelper)this); if (scriptClass == null) { input.SkipNode(); return; } QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Text: int startLine = input.Start.Line; int endLine = input.End.Line; if (scriptCode.Length == 0) { lineNumber = startLine; } else if (lastEndLine < startLine) { // A multiline comment, a PI, or an unrecognized element encountered within // this script block. Insert missed '\n' characters here; otherwise line numbers // in error messages and in the debugger will be ----ed up. This action may spoil // the script if the current position is situated in the middle of some identifier // or string literal; however we hope users will not put XML nodes there. scriptCode.Append('\n', startLine - lastEndLine); } scriptCode.Append(input.Value); lastEndLine = endLine; break; case XmlNodeType.Element: if (input.IsNs(atoms.UrnMsxsl) && (input.IsKeyword(atoms.Assembly) || input.IsKeyword(atoms.Using))) { if (scriptCode.Length != 0) { ReportError(/*[XT_012]*/Res.Xslt_ScriptNotAtTop, input.QualifiedName); input.SkipNode(); } else if (input.IsKeyword(atoms.Assembly)) { LoadMsAssembly(scriptClass); } else if (input.IsKeyword(atoms.Using)) { LoadMsUsing(scriptClass); } } else { ReportError(/*[XT_012]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; default: Debug.Assert( input.NodeType == XmlNodeType.SignificantWhitespace || input.NodeType == XmlNodeType.Whitespace ); // Skip leading whitespaces if (scriptCode.Length != 0) { goto case XmlNodeType.Text; } break; } } while (input.MoveToNextSibling()); } if (scriptCode.Length == 0) { lineNumber = input.Start.Line; } scriptClass.AddScriptBlock(scriptCode.ToString(), uriString, lineNumber, input.Start); } XsltAttribute[] assemblyAttributes = { new XsltAttribute("name", V1Opt | V2Opt), new XsltAttribute("href", V1Opt | V2Opt) }; // SxS: This method reads resource names from source document and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void LoadMsAssembly(ScriptClass scriptClass) { input.GetAttributes(assemblyAttributes); string name = ParseStringAttribute(0, "name"); string href = ParseStringAttribute(1, "href"); if ((name != null) == (href != null)) { ReportError(/*[XT_046]*/Res.Xslt_AssemblyNameHref); } else { string asmLocation = null; if (name != null) { try { asmLocation = Assembly.Load(name).Location; } catch { AssemblyName asmName = new AssemblyName(name); // If the assembly is simply named, let CodeDomProvider and Fusion resolve it byte[] publicKeyToken = asmName.GetPublicKeyToken(); if ((publicKeyToken == null || publicKeyToken.Length == 0) && asmName.Version == null) { asmLocation = asmName.Name + ".dll"; } else { throw; } } } else { Debug.Assert(href != null); asmLocation = Assembly.LoadFrom(ResolveUri(href, input.BaseUri).ToString()).Location; scriptClass.refAssembliesByHref = true; } if (asmLocation != null) { scriptClass.refAssemblies.Add(asmLocation); } } CheckNoContent(); } XsltAttribute[] usingAttributes = { new XsltAttribute("namespace", V1Req | V2Req) }; private void LoadMsUsing(ScriptClass scriptClass) { input.GetAttributes(usingAttributes); if (input.MoveToXsltAttribute(0, "namespace")) { scriptClass.nsImports.Add(input.Value); } CheckNoContent(); } // ----------------- Template level methods -------------------------- // Each instruction in AST tree has nsdecl list attuched to it. // Load*() methods do this treek. Xsl*() methods rely on LoadOneInstruction() to do this. // ToDo: check how LoadUnknown*() follows this gideline! private enum InstructionFlags { None = 0x00, AllowParam = 0x01, AllowSort = 0x02, AllowFallback = 0x04, } private List LoadInstructions() { return LoadInstructions(new List (), InstructionFlags.None); } private List LoadInstructions(InstructionFlags flags) { return LoadInstructions(new List (), flags); } private List LoadInstructions(List content) { return LoadInstructions(content, InstructionFlags.None); } private List LoadInstructions(List content, InstructionFlags flags) { QName parentName = input.ElementName; if (input.MoveToFirstChild()) { bool atTop = true; int sortNumber = 0; XslNode result; do { switch (input.NodeType) { case XmlNodeType.Element: string nspace = input.NamespaceUri; string name = input.LocalName; if (nspace == atoms.UriXsl) { InstructionFlags instrFlag = ( Ref.Equal(name, atoms.Param) ? InstructionFlags.AllowParam : Ref.Equal(name, atoms.Sort ) ? InstructionFlags.AllowSort : /*else */ InstructionFlags.None ); if (instrFlag != InstructionFlags.None) { string error = ( (flags & instrFlag) == 0 ? /*[XT_013]*/Res.Xslt_UnexpectedElement : !atTop ? /*[XT_014]*/Res.Xslt_NotAtTop : /*else*/ null ); if (error != null) { ReportError(error, input.QualifiedName, parentName); atTop = false; input.SkipNode(); continue; } } else { atTop = false; } result = ( Ref.Equal(name, atoms.ApplyImports ) ? XslApplyImports() : Ref.Equal(name, atoms.ApplyTemplates ) ? XslApplyTemplates() : Ref.Equal(name, atoms.CallTemplate ) ? XslCallTemplate() : Ref.Equal(name, atoms.Copy ) ? XslCopy() : Ref.Equal(name, atoms.CopyOf ) ? XslCopyOf() : Ref.Equal(name, atoms.Fallback ) ? XslFallback() : Ref.Equal(name, atoms.If ) ? XslIf() : Ref.Equal(name, atoms.Choose ) ? XslChoose() : Ref.Equal(name, atoms.ForEach ) ? XslForEach() : Ref.Equal(name, atoms.Message ) ? XslMessage() : Ref.Equal(name, atoms.Number ) ? XslNumber() : Ref.Equal(name, atoms.ValueOf ) ? XslValueOf() : Ref.Equal(name, atoms.Comment ) ? XslComment() : Ref.Equal(name, atoms.ProcessingInstruction) ? XslProcessingInstruction() : Ref.Equal(name, atoms.Text ) ? XslText() : Ref.Equal(name, atoms.Element ) ? XslElement() : Ref.Equal(name, atoms.Attribute ) ? XslAttribute() : Ref.Equal(name, atoms.Variable ) ? XslVarPar() : Ref.Equal(name, atoms.Param ) ? XslVarPar() : Ref.Equal(name, atoms.Sort ) ? XslSort(sortNumber ++) : #if XSLT2 V2 && Ref.Equal(name, atoms.AnalyzeString ) ? XslAnalyzeString() : V2 && Ref.Equal(name, "namespace" ) ? XslNamespace() : V2 && Ref.Equal(name, atoms.PerformSort ) ? XslPerformSort() : V2 && Ref.Equal(name, atoms.Document ) ? XslDocument() : V2 && Ref.Equal(name, atoms.ForEachGroup ) ? XslForEachGroup() : V2 && Ref.Equal(name, atoms.NextMatch ) ? XslNextMatch() : V2 && Ref.Equal(name, atoms.Sequence ) ? XslSequence() : V2 && Ref.Equal(name, atoms.ResultDocument ) ? XslResultDocument() : #endif /*default:*/ LoadUnknownXsltInstruction(parentName) ); } else { atTop = false; result = LoadLiteralResultElement(/*asStylesheet:*/false); } break; case XmlNodeType.SignificantWhitespace: result = SetLineInfo(f.Text(input.Value), input.BuildLineInfo()); break; case XmlNodeType.Whitespace: continue; default: Debug.Assert(input.NodeType == XmlNodeType.Text); atTop = false; goto case XmlNodeType.SignificantWhitespace; } AddInstruction(content, result); } while (input.MoveToNextSibling()); } return content; } private List LoadWithParams(InstructionFlags flags) { QName parentName = input.ElementName; List content = new List (); /* Process children */ if (input.MoveToFirstChild()) { int sortNumber = 0; do { switch (input.NodeType) { case XmlNodeType.Element: if (input.IsXsltKeyword(atoms.WithParam)) { XslNode withParam = XslVarPar(); CheckWithParam(content, withParam); AddInstruction(content, withParam); } else if (flags == InstructionFlags.AllowSort && input.IsXsltKeyword(atoms.Sort)) { AddInstruction(content, XslSort(sortNumber++)); } else if (flags == InstructionFlags.AllowFallback && input.IsXsltKeyword(atoms.Fallback)) { XslFallback(); } else { ReportError(/*[XT_016]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_016]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } return content; } // http://www.w3.org/TR/xslt#apply-imports private XslNode XslApplyImports() { ContextInfo ctxInfo = input.GetAttributes(); if (!input.CanHaveApplyImports) { ReportError(/*[XT_015]*/Res.Xslt_InvalidApplyImports); input.SkipNode(); return null; } List content = LoadWithParams(InstructionFlags.None); ctxInfo.SaveExtendedLineInfo(input); if (V1) { if (content.Count != 0) { ISourceLineInfo contentInfo = content[0].SourceLine; if (!input.ForwardCompatibility) { compiler.ReportError(contentInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, atoms.ApplyImports); } else { return SetInfo(f.Error(XslLoadException.CreateMessage(contentInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, atoms.ApplyImports)), null, ctxInfo); } } content = null; } else { if (content.Count != 0) ReportNYI("xsl:apply-imports/xsl:with-param"); content = null; } return SetInfo(f.ApplyImports(/*Mode:*/curTemplate.Mode, curStylesheet, input.XslVersion), content, ctxInfo); } // http://www.w3.org/TR/xslt#section-Applying-Template-Rules XsltAttribute[] applyTemplatesAttributes = { new XsltAttribute("select", V1Opt | V2Opt), new XsltAttribute("mode" , V1Opt | V2Opt) }; private XslNode XslApplyTemplates() { ContextInfo ctxInfo = input.GetAttributes(applyTemplatesAttributes); string select = ParseStringAttribute(0, "select"); if (select == null) { select = "node()"; } QilName mode = ParseModeAttribute(1); List content = LoadWithParams(InstructionFlags.AllowSort); ctxInfo.SaveExtendedLineInfo(input); return SetInfo(f.ApplyTemplates(mode, select, ctxInfo, input.XslVersion), content, ctxInfo ); } // http://www.w3.org/TR/xslt#named-templates // http://www.w3.org/TR/xslt#element-call-template XsltAttribute[] callTemplateAttributes = { new XsltAttribute("name", V1Req | V2Req) }; private XslNode XslCallTemplate() { ContextInfo ctxInfo = input.GetAttributes(callTemplateAttributes); QilName name = ParseQNameAttribute(0); List content = LoadWithParams(InstructionFlags.None); ctxInfo.SaveExtendedLineInfo(input); return SetInfo(f.CallTemplate(name, ctxInfo), content, ctxInfo); } // http://www.w3.org/TR/xslt#copying // http://www.w3.org/TR/xslt20/#element-copy XsltAttribute[] copyAttributes = { new XsltAttribute("copy-namespaces" , V2Opt), new XsltAttribute("inherit-namespaces", V2Opt), new XsltAttribute("use-attribute-sets", V1Opt | V2Opt), new XsltAttribute("type" , V2Opt), new XsltAttribute("validation" , V2Opt) }; private XslNode XslCopy() { ContextInfo ctxInfo = input.GetAttributes(copyAttributes); bool copyNamespaces = ParseYesNoAttribute(0, "copy-namespaces" ) != TriState.False; bool inheritNamespaces = ParseYesNoAttribute(1, "inherit-namespaces") != TriState.False; if (! copyNamespaces ) ReportNYI("xsl:copy[@copy-namespaces = 'no']"); if (! inheritNamespaces) ReportNYI("xsl:copy[@inherit-namespaces = 'no']"); List content = new List (); if (input.MoveToXsltAttribute(2, "use-attribute-sets")) { AddUseAttributeSets(content); } ParseTypeAttribute(3); ParseValidationAttribute(4, /*defVal:*/false); return SetInfo(f.Copy(), LoadEndTag(LoadInstructions(content)), ctxInfo); } XsltAttribute[] copyOfAttributes = { new XsltAttribute("select" , V1Req | V2Req), new XsltAttribute("copy-namespaces", V2Opt), new XsltAttribute("type" , V2Opt), new XsltAttribute("validation" , V2Opt) }; private XslNode XslCopyOf() { ContextInfo ctxInfo = input.GetAttributes(copyOfAttributes); string select = ParseStringAttribute(0, "select"); bool copyNamespaces = ParseYesNoAttribute(1, "copy-namespaces") != TriState.False; if (!copyNamespaces) ReportNYI("xsl:copy-of[@copy-namespaces = 'no']"); ParseTypeAttribute(2); ParseValidationAttribute(3, /*defVal:*/false); CheckNoContent(); return SetInfo(f.CopyOf(select, input.XslVersion), null, ctxInfo); } // http://www.w3.org/TR/xslt#fallback // See LoadFallbacks() for real fallback implementation private XslNode XslFallback() { input.GetAttributes(); input.SkipNode(); return null; } XsltAttribute[] ifAttributes = { new XsltAttribute("test", V1Req | V2Req) }; private XslNode XslIf() { ContextInfo ctxInfo = input.GetAttributes(ifAttributes); string test = ParseStringAttribute(0, "test"); return SetInfo(f.If(test, input.XslVersion), LoadInstructions(), ctxInfo); } private XslNode XslChoose() { ContextInfo ctxInfo = input.GetAttributes(); List content = new List (); bool otherwise = false; bool when = false; QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Element: XslNode node = null; if (Ref.Equal(input.NamespaceUri, atoms.UriXsl)) { if (Ref.Equal(input.LocalName, atoms.When)) { if (otherwise) { ReportError(/*[XT_018]*/Res.Xslt_WhenAfterOtherwise); input.SkipNode(); continue; } else { when = true; node = XslIf(); } } else if (Ref.Equal(input.LocalName, atoms.Otherwise)) { if (otherwise) { ReportError(/*[XT_019]*/Res.Xslt_DupOtherwise); input.SkipNode(); continue; } else { otherwise = true; node = XslOtherwise(); } } } if (node == null) { ReportError(/*[XT_020]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); continue; } AddInstruction(content, node); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_020]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } CheckError(!when, /*[XT_021]*/Res.Xslt_NoWhen); return SetInfo(f.Choose(), content, ctxInfo); } private XslNode XslOtherwise() { ContextInfo ctxInfo = input.GetAttributes(); return SetInfo(f.Otherwise(), LoadInstructions(), ctxInfo); } XsltAttribute[] forEachAttributes = { new XsltAttribute("select", V1Req | V2Req) }; private XslNode XslForEach() { ContextInfo ctxInfo = input.GetAttributes(forEachAttributes); string select = ParseStringAttribute(0, "select"); // The current template rule becomes null, so we must not allow xsl:apply-import's within this element input.CanHaveApplyImports = false; List content = LoadInstructions(InstructionFlags.AllowSort); ctxInfo.SaveExtendedLineInfo(input); return SetInfo(f.ForEach(select, ctxInfo, input.XslVersion), content, ctxInfo ); } // http://www.w3.org/TR/xslt#message // http://www.w3.org/TR/xslt20/#element-message XsltAttribute[] messageAttributes = { new XsltAttribute("select" , V2Opt), new XsltAttribute("terminate", V1Opt | V2Opt) }; private XslNode XslMessage() { ContextInfo ctxInfo = input.GetAttributes(messageAttributes); string select = ParseStringAttribute(0, "select"); bool terminate = ParseYesNoAttribute(1, /*attName:*/"terminate") == TriState.True; List content = LoadInstructions(); if (content.Count != 0) { content = LoadEndTag(content); } if (select != null) { content.Insert(0, f.CopyOf(select, input.XslVersion)); } return SetInfo(f.Message(terminate), content, ctxInfo); } // http://www.w3.org/TR/xslt#number // http://www.w3.org/TR/xslt20/#element-number XsltAttribute[] numberAttributes = { new XsltAttribute("value" , V1Opt | V2Opt), new XsltAttribute("select" , V2Opt), new XsltAttribute("level" , V1Opt | V2Opt), new XsltAttribute("count" , V1Opt | V2Opt), new XsltAttribute("from" , V1Opt | V2Opt), new XsltAttribute("format" , V1Opt | V2Opt), new XsltAttribute("lang" , V1Opt | V2Opt), new XsltAttribute("letter-value" , V1Opt | V2Opt), new XsltAttribute("ordinal" , V2Opt), new XsltAttribute("grouping-separator", V1Opt | V2Opt), new XsltAttribute("grouping-size" , V1Opt | V2Opt) }; private XslNode XslNumber() { ContextInfo ctxInfo = input.GetAttributes(numberAttributes); string value = ParseStringAttribute(0, "value"); string select = ParseStringAttribute(1, "select"); if (select != null) ReportNYI("xsl:number/@select"); NumberLevel level = NumberLevel.Single; if (input.MoveToXsltAttribute(2, "level")) { switch (input.Value) { case "single" : level = NumberLevel.Single ; break; case "multiple": level = NumberLevel.Multiple; break; case "any" : level = NumberLevel.Any ; break; default: if (!input.ForwardCompatibility) { ReportError(/*[XT_022]*/Res.Xslt_InvalidAttrValue, "level", input.Value); } break; } } string count = ParseStringAttribute(3, "count" ); string from = ParseStringAttribute(4, "from" ); string format = ParseStringAttribute(5, "format"); string lang = ParseStringAttribute(6, "lang" ); string letterValue = ParseStringAttribute(7, "letter-value"); string ordinal = ParseStringAttribute(8, "ordinal"); if (!string.IsNullOrEmpty(ordinal)) ReportNYI("xsl:number/@ordinal"); string groupingSeparator = ParseStringAttribute(9, "grouping-separator"); string groupingSize = ParseStringAttribute(10, "grouping-size" ); // Default values for xsl:number : level="single" format="1" if (format == null) { format = "1"; } CheckNoContent(); return SetInfo( f.Number(level, count, from, value, format, lang, letterValue, groupingSeparator, groupingSize, input.XslVersion ), null, ctxInfo ); } // http://www.w3.org/TR/xslt#value-of XsltAttribute[] valueOfAttributes = { new XsltAttribute("select" , V1Req | V2Opt), new XsltAttribute("separator" , V2Opt), new XsltAttribute("disable-output-escaping", V1Opt | V2Opt) }; private XslNode XslValueOf() { ContextInfo ctxInfo = input.GetAttributes(valueOfAttributes); string select = ParseStringAttribute(0, "select"); string separator = ParseStringAttribute(1, "separator"); bool doe = ParseYesNoAttribute(2, /*attName:*/"disable-output-escaping") == TriState.True; if (separator == null) { if (!input.BackwardCompatibility) { separator = select != null ? " " : string.Empty; } } else { ReportNYI("xsl:value-of/@separator"); } List content = null; if (V1) { if (select == null) { input.SkipNode(); return SetInfo(f.Error(XslLoadException.CreateMessage(ctxInfo.lineInfo, Res.Xslt_MissingAttribute, "select")), null, ctxInfo); } CheckNoContent(); } else { content = LoadContent(select != null); CheckError(select == null && content.Count == 0, /*[???]*/Res.Xslt_NoSelectNoContent, input.ElementName); if (content.Count != 0) { ReportNYI("xsl:value-of/*"); content = null; } } return SetInfo(f.XslNode(doe ? XslNodeType.ValueOfDoe : XslNodeType.ValueOf, null, select, input.XslVersion), null, ctxInfo ); } // required tunnel select // variable - - + // with-param - + + // stylesheet/param + - + // template/param + + + // function/param - - - // xsl:variable http://www.w3.org/TR/xslt#local-variables // xsl:param http://www.w3.org/TR/xslt#element-param // xsl:with-param http://www.w3.org/TR/xslt#element-with-param XsltAttribute[] variableAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("select" , V1Opt | V2Opt), new XsltAttribute("as" , V2Opt), new XsltAttribute("required", 0), new XsltAttribute("tunnel" , 0) }; XsltAttribute[] paramAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("select" , V1Opt | V2Opt), new XsltAttribute("as" , V2Opt), new XsltAttribute("required", V2Opt), new XsltAttribute("tunnel" , V2Opt) }; XsltAttribute[] withParamAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("select" , V1Opt | V2Opt), new XsltAttribute("as" , V2Opt), new XsltAttribute("required", 0), new XsltAttribute("tunnel" , V2Opt) }; private VarPar XslVarPar() { string localName = input.LocalName; XslNodeType nodeType = ( Ref.Equal(localName, atoms.Variable ) ? XslNodeType.Variable : Ref.Equal(localName, atoms.Param ) ? XslNodeType.Param : Ref.Equal(localName, atoms.WithParam) ? XslNodeType.WithParam : XslNodeType.Unknown ); Debug.Assert(nodeType != XslNodeType.Unknown); bool isParam = Ref.Equal(localName, atoms.Param); ContextInfo ctxInfo = input.GetAttributes( nodeType == XslNodeType.Variable ? variableAttributes : nodeType == XslNodeType.Param ? paramAttributes : /*default:*/ withParamAttributes ); QilName name = ParseQNameAttribute(0); string select = ParseStringAttribute(1, "select"); string asType = ParseStringAttribute(2, "as"); TriState required = ParseYesNoAttribute(3, "required"); if (nodeType == XslNodeType.Param && curFunction != null) { if (!input.ForwardCompatibility) { CheckError(required != TriState.Unknown, /*[???]*/Res.Xslt_RequiredOnFunction, name.ToString()); } required = TriState.True; } else { if (required == TriState.True) ReportNYI("xsl:param/@required == true()"); } if (asType != null) { ReportNYI("xsl:param/@as"); } TriState tunnel = ParseYesNoAttribute(4, "tunnel"); if (tunnel != TriState.Unknown) { if (nodeType == XslNodeType.Param && curTemplate == null) { if (!input.ForwardCompatibility) { ReportError(/*[???]*/Res.Xslt_NonTemplateTunnel, name.ToString()); } } else { if (tunnel == TriState.True) ReportNYI("xsl:param/@tunnel == true()"); } } List content = LoadContent(select != null); CheckError((required == TriState.True) && (select != null || content.Count != 0), /*[???]*/Res.Xslt_RequiredAndSelect, name.ToString()); VarPar result = f.VarPar(nodeType, name, select, input.XslVersion); SetInfo(result, content, ctxInfo); return result; } // http://www.w3.org/TR/xslt#section-Creating-Comments // http://www.w3.org/TR/xslt20/#element-comment XsltAttribute[] commentAttributes = { new XsltAttribute("select", V2Opt) }; private XslNode XslComment() { ContextInfo ctxInfo = input.GetAttributes(commentAttributes); string select = ParseStringAttribute(0, "select"); if (select != null) ReportNYI("xsl:comment/@select"); return SetInfo(f.Comment(), LoadContent(select != null), ctxInfo); } private List LoadContent(bool hasSelect) { QName parentName = input.ElementName; List content = LoadInstructions(); CheckError(hasSelect && content.Count != 0, /*[XT0620]*/Res.Xslt_ElementCntSel, parentName); // Load the end tag only if the content is not empty if (content.Count != 0) { content = LoadEndTag(content); } return content; } // http://www.w3.org/TR/xslt#section-Creating-Processing-Instructions // http://www.w3.org/TR/xslt20/#element-processing-instruction XsltAttribute[] processingInstructionAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("select", V2Opt) }; private XslNode XslProcessingInstruction() { ContextInfo ctxInfo = input.GetAttributes(processingInstructionAttributes); string name = ParseNCNameAttribute(0); string select = ParseStringAttribute(1, "select"); if (select != null) ReportNYI("xsl:processing-instruction/@select"); return SetInfo(f.PI(name, input.XslVersion), LoadContent(select != null), ctxInfo); } // http://www.w3.org/TR/xslt#section-Creating-Text XsltAttribute[] textAttributes = { new XsltAttribute("disable-output-escaping", V1Opt | V2Opt) }; private XslNode XslText() { ContextInfo ctxInfo = input.GetAttributes(textAttributes); bool doe = ParseYesNoAttribute(0, /*attName:*/ "disable-output-escaping") == TriState.True; SerializationHints hints = doe ? SerializationHints.DisableOutputEscaping : SerializationHints.None; // We are not using StringBuilder here because in most cases there will be just one text node. List content = new List (); QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Text: case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: // xsl:text may contain multiple child text nodes separated by comments and PIs, which are ignored by XsltInput content.Add(f.Text(input.Value, hints)); break; default: Debug.Assert(input.NodeType == XmlNodeType.Element); ReportError(/*[XT_023]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); break; } } while (input.MoveToNextSibling()); } // Empty xsl:text elements will be ignored return SetInfo(f.List(), content, ctxInfo); } // http://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element // http://www.w3.org/TR/xslt20/#element-element XsltAttribute[] elementAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("namespace" , V1Opt | V2Opt), new XsltAttribute("inherit-namespaces", V2Opt), new XsltAttribute("use-attribute-sets" , V1Opt | V2Opt), new XsltAttribute("type" , V2Opt), new XsltAttribute("validation" , V2Opt) }; private XslNode XslElement() { ContextInfo ctxInfo = input.GetAttributes(elementAttributes); string name = ParseNCNameAttribute(0); ; string ns = ParseStringAttribute(1, "namespace"); CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns); bool inheritNamespaces = ParseYesNoAttribute(2, "inherit-namespaces") != TriState.False; if (!inheritNamespaces) ReportNYI("xsl:copy[@inherit-namespaces = 'no']"); ParseTypeAttribute(4); ParseValidationAttribute(5, /*defVal:*/false); List content = new List (); if (input.MoveToXsltAttribute(3, "use-attribute-sets")) { AddUseAttributeSets(content); } return SetInfo(f.Element(name, ns, input.XslVersion), LoadEndTag(LoadInstructions(content)), ctxInfo ); } // http://www.w3.org/TR/xslt#creating-attributes // http://www.w3.org/TR/xslt20#creating-attributes XsltAttribute[] attributeAttributes = { new XsltAttribute("name" , V1Req | V2Req), new XsltAttribute("namespace" , V1Opt | V2Opt), new XsltAttribute("select" , V2Opt), new XsltAttribute("separator" , V2Opt), new XsltAttribute("type" , V2Opt), new XsltAttribute("validation", V2Opt) }; private XslNode XslAttribute() { ContextInfo ctxInfo = input.GetAttributes(attributeAttributes); string name = ParseNCNameAttribute(0); string ns = ParseStringAttribute(1, "namespace"); CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns); string select = ParseStringAttribute(2, "select"); if (select != null) ReportNYI("xsl:attribute/@select"); string separator = ParseStringAttribute(3, "separator"); if (separator != null) ReportNYI("xsl:attribute/@separator"); separator = separator != null ? separator : (select != null ? " " : string.Empty); ParseTypeAttribute(4); ParseValidationAttribute(5, /*defVal:*/false); return SetInfo(f.Attribute(name, ns, input.XslVersion), LoadContent(select != null), ctxInfo); } // http://www.w3.org/TR/xslt#sorting // http://www.w3.org/TR/xslt20/#element-sort XsltAttribute[] sortAttributes = { new XsltAttribute("select" , V1Opt | V2Opt), new XsltAttribute("lang" , V1Opt | V2Opt), new XsltAttribute("order" , V1Opt | V2Opt), new XsltAttribute("collation" , V1Opt | V2Opt), new XsltAttribute("stable" , V1Opt | V2Opt), new XsltAttribute("case-order", V1Opt | V2Opt), new XsltAttribute("data-type" , V1Opt | V2Opt) }; private XslNode XslSort(int sortNumber) { ContextInfo ctxInfo = input.GetAttributes(sortAttributes); string select = ParseStringAttribute( 0, "select" ); string lang = ParseStringAttribute( 1, "lang" ); string order = ParseStringAttribute( 2, "order" ); string collation = ParseCollationAttribute(3); TriState stable = ParseYesNoAttribute ( 4, "stable" ); string caseOrder = ParseStringAttribute( 5, "case-order"); string dataType = ParseStringAttribute( 6, "data-type" ); if (stable != TriState.Unknown) { CheckError(sortNumber != 0, Res.Xslt_SortStable); } List content = null; if (V1) { if (input.ForwardCompatibility) { content = LoadContent(/*hasSelect:*/false); if (content.Count != 0) { content = new List (); content.Add(SetInfo(f.Error(XslLoadException.CreateMessage(ctxInfo.lineInfo, Res.Xslt_MissingAttribute, "select")), null, ctxInfo)); } /*ToDo*/ { // in future 'select' will be part of content for such instructions. // for now we will just ignore this error. content = null; select = "."; } } else { CheckNoContent(); } } else { content = LoadContent(select != null); if (content.Count != 0) { ReportNYI("xsl:sort/*"); content = null; } } if (select == null /*&& content.Count == 0*/) { select = "."; } return SetInfo(f.Sort(select, lang, dataType, order, caseOrder, input.XslVersion), null, ctxInfo ); } #if XSLT2 // http://www.w3.org/TR/xslt20/#element-document XsltAttribute[] documentAttributes = { new XsltAttribute("type" , V2Opt), new XsltAttribute("validation", V2Opt) }; private XslNode XslDocument() { ContextInfo ctxInfo = input.GetAttributes(documentAttributes); ParseTypeAttribute(0); ParseValidationAttribute(1, /*defVal:*/false); ReportNYI("xsl:document"); List content = LoadEndTag(LoadInstructions()); return null; } // http://www.w3.org/TR/xslt20/#element-analyze-string XsltAttribute[] analyzeStringAttributes = { new XsltAttribute("select", V2Req), new XsltAttribute("regex" , V2Req), new XsltAttribute("flags" , V2Opt) }; private XslNode XslAnalyzeString() { ContextInfo ctxInfo = input.GetAttributes(analyzeStringAttributes); string select = ParseStringAttribute(0, "select"); string regex = ParseStringAttribute(1, "regex" ); string flags = ParseStringAttribute(2, "flags" ); if (flags == null) { flags = ""; } ReportNYI("xsl:analyze-string"); XslNode matching = null; XslNode nonMatching = null; QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Element: if (input.IsXsltKeyword(atoms.MatchingSubstring)) { ContextInfo ctxInfoChld = input.GetAttributes(); CheckError(nonMatching != null, /*[???]*/Res.Xslt_AnalyzeStringChildOrder); CheckError(matching != null, /*[???]*/Res.Xslt_AnalyzeStringDupChild, atoms.MatchingSubstring); // The current template rule becomes null, so we must not allow xsl:apply-import's within this element input.CanHaveApplyImports = false; matching = SetInfo(f.List(), LoadInstructions(), ctxInfoChld); } else if (input.IsXsltKeyword(atoms.NonMatchingSubstring)) { ContextInfo ctxInfoChld = input.GetAttributes(); CheckError(nonMatching != null, /*[???]*/Res.Xslt_AnalyzeStringDupChild, atoms.NonMatchingSubstring); input.CanHaveApplyImports = false; nonMatching = SetInfo(f.List(), LoadInstructions(), ctxInfoChld); } else if (input.IsXsltKeyword(atoms.Fallback)) { XslFallback(); } else { ReportError(/*[XT_017]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_017]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } CheckError(matching == nonMatching, /*[XTSE1130]*/Res.Xslt_AnalyzeStringEmpty); ctxInfo.SaveExtendedLineInfo(input); return null; } // http://www.w3.org/TR/xslt20/#element-namespace XsltAttribute[] namespaceAttributes = { new XsltAttribute("name" , V2Req), new XsltAttribute("select", V2Opt) }; private XslNode XslNamespace() { ContextInfo ctxInfo = input.GetAttributes(namespaceAttributes); string name = ParseNCNameAttribute(0); string select= ParseStringAttribute(1, "select"); List content = LoadContent(select != null); CheckError(select == null && content.Count == 0, /*[???]*/Res.Xslt_NoSelectNoContent, input.ElementName); ReportNYI("xsl:namespace"); return null; } // http://www.w3.org/TR/xslt20/#element-perform-sort XsltAttribute[] performSortAttributes = { new XsltAttribute("select", V2Opt) }; private XslNode XslPerformSort() { ContextInfo ctxInfo = input.GetAttributes(performSortAttributes); string select = ParseStringAttribute(0, "select"); List content = LoadInstructions(InstructionFlags.AllowSort); ctxInfo.SaveExtendedLineInfo(input); if (select != null) { foreach (XslNode node in content) { if (node.NodeType != XslNodeType.Sort) { ReportError(Res.Xslt_PerformSortCntSel); break; } } } ReportNYI("xsl:perform-sort"); return null; } // http://www.w3.org/TR/xslt20/#element-for-each-group XsltAttribute[] forEachGroupAttributes = { new XsltAttribute("select" , V2Req), new XsltAttribute("group-by" , V2Opt), new XsltAttribute("group-adjacent" , V2Opt), new XsltAttribute("group-starting-with", V2Opt), new XsltAttribute("group-ending-with" , V2Opt), new XsltAttribute("collation" , V2Opt) }; private XslNode XslForEachGroup() { ContextInfo ctxInfo = input.GetAttributes(forEachGroupAttributes); string select = ParseStringAttribute( 0, "select" ); string groupBy = ParseStringAttribute( 1, "group-by" ); string groupAdjacent = ParseStringAttribute( 2, "group-adjacent" ); string groupStartingWith = ParseStringAttribute( 3, "group-starting-with"); string groupEndingWith = ParseStringAttribute( 4, "group-ending-with" ); string collation = ParseCollationAttribute(5); ReportNYI("xsl:for-each-group"); // The current template rule becomes null, so we must not allow xsl:apply-import's within this element input.CanHaveApplyImports = false; List content = LoadInstructions(InstructionFlags.AllowSort); ctxInfo.SaveExtendedLineInfo(input); return null; } // http://www.w3.org/TR/xslt20/#element-next-match private XslNode XslNextMatch() { ContextInfo ctxInfo = input.GetAttributes(); // We need to do this dynamic any way: //if (!input.CanHaveApplyImports) { // ReportError(/*[XT_015]*/Res.Xslt_InvalidApplyImports); // input.SkipNode(); // return null; //} ReportNYI("xsl:next-match"); List content = LoadWithParams(InstructionFlags.AllowFallback); ctxInfo.SaveExtendedLineInfo(input); return null; } // http://www.w3.org/TR/xslt20/#element-sequence XsltAttribute[] sequenceAttributes = { new XsltAttribute("select", V2Req) }; private XslNode XslSequence() { ContextInfo ctxInfo = input.GetAttributes(sequenceAttributes); string select = ParseStringAttribute(0, "select"); ReportNYI("xsl:sequence"); QName parentName = input.ElementName; if (input.MoveToFirstChild()) { do { switch (input.NodeType) { case XmlNodeType.Element: if (input.IsXsltKeyword(atoms.Fallback)) { XslFallback(); } else { ReportError(/*[XT_017]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); } break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: break; default: Debug.Assert(input.NodeType == XmlNodeType.Text); ReportError(/*[XT_017]*/Res.Xslt_TextNodesNotAllowed, parentName); break; } } while (input.MoveToNextSibling()); } return null; } // http://www.w3.org/TR/xslt20/#element-result-document XsltAttribute[] resultDocumentAttributes = { new XsltAttribute("format" , V2Opt), // 0 new XsltAttribute("href" , V2Opt), // 1 new XsltAttribute("validation" , V2Opt), // 2 new XsltAttribute("type" , V2Opt), // 3 new XsltAttribute("name" , V2Opt), // 4 new XsltAttribute("method" , V2Opt), // 5 new XsltAttribute("byte-order-mark" , V2Opt), // 6 new XsltAttribute("cdata-section-elements", V2Opt), // 7 new XsltAttribute("doctype-public" , V2Opt), // 8 new XsltAttribute("doctype-system" , V2Opt), // 9 new XsltAttribute("encoding" , V2Opt), // 10 new XsltAttribute("escape-uri-attributes" , V2Opt), // 11 new XsltAttribute("include-content-type" , V2Opt), // 12 new XsltAttribute("indent" , V2Opt), // 13 new XsltAttribute("media-type" , V2Opt), // 14 new XsltAttribute("normalization-form" , V2Opt), // 15 new XsltAttribute("omit-xml-declaration" , V2Opt), // 16 new XsltAttribute("standalone" , V2Opt), // 17 new XsltAttribute("undeclare-prefixes" , V2Opt), // 18 new XsltAttribute("use-character-maps" , V2Opt), // 19 new XsltAttribute("output-version" , V2Opt) // 20 }; private XslNode XslResultDocument() { ContextInfo ctxInfo = input.GetAttributes(resultDocumentAttributes); string format = ParseStringAttribute(0 , "format"); XmlWriterSettings settings = new XmlWriterSettings(); // we should use attFormat to determing settings string href = ParseStringAttribute(1 , "href"); ParseValidationAttribute(2, /*defVal:*/false); ParseTypeAttribute(3); QilName name = ParseQNameAttribute( 4); TriState byteOrderMask = ParseYesNoAttribute( 6 , "byte-order-mark"); string docTypePublic = ParseStringAttribute(8 , "doctype-public"); string docTypeSystem = ParseStringAttribute(9 , "doctype-system"); bool escapeUriAttributes = ParseYesNoAttribute( 11, "escape-uri-attributes") != TriState.False; bool includeContentType = ParseYesNoAttribute( 12, "include-content-type") != TriState.False; settings.Indent = ParseYesNoAttribute( 13, "indent") == TriState.True; string mediaType = ParseStringAttribute(14, "media-type"); string normalizationForm = ParseStringAttribute(15, "normalization-form"); settings.OmitXmlDeclaration = ParseYesNoAttribute( 16, "omit-xml-declaration") == TriState.True; settings.Standalone = ParseYesNoAttribute( 17, "standalone" ) == TriState.True ? XmlStandalone.Yes : XmlStandalone.No; bool undeclarePrefixes = ParseYesNoAttribute( 18, "undeclare-prefixes") == TriState.True; List useCharacterMaps = ParseUseCharacterMaps(19); string outputVersion = ParseStringAttribute(20, "output-version"); ReportNYI("xsl:result-document"); if (format != null) ReportNYI("xsl:result-document/@format"); if (href == null) { href = string.Empty; } // attHref is a BaseUri of new output tree. It should be resolved relative to "base output URI" if (input.MoveToXsltAttribute(5, "method")) { compiler.EnterForwardsCompatible(); XmlOutputMethod outputMethod; ParseOutputMethod(input.Value, out outputMethod); if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { settings.OutputMethod = outputMethod; } } if (input.MoveToXsltAttribute(7, "cdata-section-elements")) { // Do not check the import precedence, the effective value is the union of all specified values compiler.EnterForwardsCompatible(); string[] qnames = XmlConvert.SplitString(input.Value); List list = new List (); for (int i = 0; i < qnames.Length; i++) { list.Add(ResolveQName(/*ignoreDefaultNs:*/false, qnames[i])); } if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { foreach (XmlQualifiedName qname in list) { settings.CDataSectionElements.Add(qname); } } } if (input.MoveToXsltAttribute(10, "encoding")) { try { // Encoding.GetEncoding() should never throw NotSupportedException, only ArgumentException settings.Encoding = Encoding.GetEncoding(input.Value); } catch (ArgumentException) { if (!input.ForwardCompatibility) { ReportWarning(/*[XT_004]*/Res.Xslt_InvalidEncoding, input.Value); } } } if (byteOrderMask != TriState.Unknown) ReportNYI("xsl:result-document/@byte-order-mark"); if (!escapeUriAttributes) ReportNYI("xsl:result-document/@escape-uri-attributes == flase()"); if (!includeContentType) ReportNYI("xsl:output/@include-content-type == flase()"); if (normalizationForm != null) ReportNYI("xsl:result-document/@normalization-form"); if (undeclarePrefixes) ReportNYI("xsl:result-document/@undeclare-prefixes == true()"); if (docTypePublic != null) { settings.DocTypePublic = docTypePublic; } if (docTypeSystem != null) { settings.DocTypeSystem = docTypeSystem; } if (mediaType != null) { settings.MediaType = mediaType; } if (useCharacterMaps != null) ReportNYI("xsl:result-document/@use-character-maps"); if (outputVersion != null) { // ReportNYI("xsl:result-document/@output-version"); } LoadInstructions(); return null; } #endif // http://www.w3.org/TR/xslt#literal-result-element private XslNode LoadLiteralResultElement(bool asStylesheet) { Debug.Assert(input.NodeType == XmlNodeType.Element); string prefix = input.Prefix; string name = input.LocalName; string nsUri = input.NamespaceUri; ContextInfo ctxInfo = input.GetLiteralAttributes(asStylesheet); if (input.IsExtensionNamespace(nsUri)) { // This is not a literal result element, so drop all attributes we have collected return SetInfo(f.List(), LoadFallbacks(name), ctxInfo); } List content = new List (); for (int i = 1; input.MoveToLiteralAttribute(i); i++) { if (input.IsXsltNamespace() && input.IsKeyword(atoms.UseAttributeSets)) { AddUseAttributeSets(content); } } for (int i = 1; input.MoveToLiteralAttribute(i); i++) { if (! input.IsXsltNamespace()) { XslNode att = f.LiteralAttribute(f.QName(input.LocalName, input.NamespaceUri, input.Prefix), input.Value, input.XslVersion); // QilGenerator takes care of AVTs, and needs line info AddInstruction(content, SetLineInfo(att, ctxInfo.lineInfo)); } else { // ignore all other xslt attributes. See XslInput.GetLiteralAttributes() } } content = LoadEndTag(LoadInstructions(content)); return SetInfo(f.LiteralElement(f.QName(name, nsUri, prefix)), content, ctxInfo); } private void CheckWithParam(List content, XslNode withParam) { Debug.Assert(content != null && withParam != null); Debug.Assert(withParam.NodeType == XslNodeType.WithParam); foreach (XslNode node in content) { if (node.NodeType == XslNodeType.WithParam && node.Name.Equals(withParam.Name)) { ReportError(/*[XT0670]*/Res.Xslt_DuplicateWithParam, withParam.Name.QualifiedName); break; } } } private static void AddInstruction(List content, XslNode instruction) { Debug.Assert(content != null); if (instruction != null) { content.Add(instruction); } } private List LoadEndTag(List content) { Debug.Assert(content != null); if (compiler.IsDebug && !input.IsEmptyElement) { AddInstruction(content, SetLineInfo(f.Nop(), input.BuildLineInfo())); } return content; } private XslNode LoadUnknownXsltInstruction(string parentName) { input.GetVersionAttribute(); if (!input.ForwardCompatibility) { ReportError(/*[XT_026]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName); input.SkipNode(); return null; } else { ContextInfo ctxInfo = input.GetAttributes(); List fallbacks = LoadFallbacks(input.LocalName); return SetInfo(f.List(), fallbacks, ctxInfo); } } private List LoadFallbacks(string instrName) { input.MoveToElement(); ISourceLineInfo extElmLineInfo = input.BuildNameLineInfo(); List fallbacksArray = new List (); // /* Process children */ if (input.MoveToFirstChild()) { do { if (input.IsXsltKeyword(atoms.Fallback)) { ContextInfo ctxInfo = input.GetAttributes(); fallbacksArray.Add(SetInfo(f.List(), LoadInstructions(), ctxInfo)); } else { input.SkipNode(); } } while (input.MoveToNextSibling()); } // Generate runtime error if there is no fallbacks if (fallbacksArray.Count == 0) { fallbacksArray.Add( f.Error(XslLoadException.CreateMessage(extElmLineInfo, Res.Xslt_UnknownExtensionElement, instrName)) ); } return fallbacksArray; } // ------------------ little helper methods --------------------- // Suppresses errors if FCB is enabled private QilName ParseModeAttribute(int attNum) { //Debug.Assert( // input.IsXsltKeyword(atoms.ApplyTemplates) || // input.IsXsltKeyword(atoms.Template) && V1 //); if (! input.MoveToXsltAttribute(attNum, "mode")) { return nullMode; } // mode is always optional attribute compiler.EnterForwardsCompatible(); string qname = input.Value; QilName mode; if (!V1 && qname == "#default") { mode = nullMode; } else if (!V1 && qname == "#current") { ReportNYI("xsl:apply-templates[@mode='#current']"); mode = nullMode; } else if (!V1 && qname == "#all") { ReportError(Res.Xslt_ModeListAll); mode = nullMode; } else { mode = CreateXPathQName(qname); } if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { mode = nullMode; } return mode; } // Parse mode when it is list. V1: -, V2: xsl:template // Suppresses errors if FCB is enabled private QilName ParseModeListAttribute(int attNum) { //Debug.Assert(input.IsXsltKeyword(atoms.Template) && !V1); if (! input.MoveToXsltAttribute(attNum, "mode")) { return nullMode; } string modeList = input.Value; if (modeList == "#all") { ReportNYI("xsl:template[@mode='#all']"); return nullMode; } else { string[] list = XmlConvert.SplitString(modeList); List modes = new List (list.Length); compiler.EnterForwardsCompatible(); // mode is always optional attribute if (list.Length == 0) { ReportError(Res.Xslt_ModeListEmpty); } else { foreach (string qname in list) { QilName mode; if (qname == "#default") { mode = nullMode; } else if (qname == "#current") { ReportNYI("xsl:apply-templates[@mode='#current']"); break; } else if (qname == "#all") { ReportError(Res.Xslt_ModeListAll); break; } else { mode = CreateXPathQName(qname); } bool dup = false; foreach (QilName m in modes) { dup |= m.Equals(mode); } if (dup) { ReportError(Res.Xslt_ModeListDup, qname); } else { modes.Add(mode); } } } if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { modes.Clear(); modes.Add(nullMode); } if (1 < modes.Count) { ReportNYI("Multipe modes"); return nullMode; } if (modes.Count == 0) { return nullMode; } return modes[0]; } } private string ParseCollationAttribute(int attNum) { if (input.MoveToXsltAttribute(attNum, "collation")) { ReportNYI("@collation"); } return null; } // Does not suppress errors private bool ResolveQName(bool ignoreDefaultNs, string qname, out string localName, out string namespaceName, out string prefix) { if (qname == null) { // That means stylesheet is incorrect prefix = compiler.PhantomNCName; localName = compiler.PhantomNCName; namespaceName = compiler.CreatePhantomNamespace(); return false; } if (!compiler.ParseQName(qname, out prefix, out localName, (IErrorHelper)this)) { namespaceName = compiler.CreatePhantomNamespace(); return false; } if (ignoreDefaultNs && prefix.Length == 0) { namespaceName = string.Empty; } else { namespaceName = input.LookupXmlNamespace(prefix); if (namespaceName == null) { namespaceName = compiler.CreatePhantomNamespace(); return false; } } return true; } // Does not suppress errors private QilName ParseQNameAttribute(int attNum) { bool required = input.IsRequiredAttribute(attNum); QilName result = null; if (!required) { compiler.EnterForwardsCompatible(); } if (input.MoveToXsltAttribute(attNum, "name")) { string prefix, localName, namespaceName; if (ResolveQName(/*ignoreDefaultNs:*/true, input.Value, out localName, out namespaceName, out prefix)) { result = f.QName(localName, namespaceName, prefix); } } if (!required) { compiler.ExitForwardsCompatible(input.ForwardCompatibility); } if (result == null && required) { result = f.QName(compiler.PhantomNCName, compiler.CreatePhantomNamespace(), compiler.PhantomNCName); } return result; } private string ParseNCNameAttribute(int attNum) { Debug.Assert(input.IsRequiredAttribute(attNum), "It happened that @name as NCName is always required attribute"); if (input.MoveToXsltAttribute(attNum, "name")) { return input.Value; } return compiler.PhantomNCName; } // Does not suppress errors private QilName CreateXPathQName(string qname) { string prefix, localName, namespaceName; ResolveQName(/*ignoreDefaultNs:*/true, qname, out localName, out namespaceName, out prefix); return f.QName(localName, namespaceName, prefix); } // Does not suppress errors private XmlQualifiedName ResolveQName(bool ignoreDefaultNs, string qname) { string prefix, localName, namespaceName; ResolveQName(ignoreDefaultNs, qname, out localName, out namespaceName, out prefix); return new XmlQualifiedName(localName, namespaceName); } // Does not suppress errors private void ParseWhitespaceRules(string elements, bool preserveSpace) { if (elements != null && elements.Length != 0) { string[] tokens = XmlConvert.SplitString(elements); for (int i = 0; i < tokens.Length; i++) { string prefix, localName, namespaceName; if (!compiler.ParseNameTest(tokens[i], out prefix, out localName, (IErrorHelper)this)) { namespaceName = compiler.CreatePhantomNamespace(); } else if (prefix == null || prefix.Length == 0) { namespaceName = prefix; } else { namespaceName = input.LookupXmlNamespace(prefix); if (namespaceName == null) { namespaceName = compiler.CreatePhantomNamespace(); } } int index = ( (localName == null ? 1 : 0) + (namespaceName == null ? 1 : 0) ); curStylesheet.AddWhitespaceRule(index, new WhitespaceRule(localName, namespaceName, preserveSpace)); } } } // Does not suppress errors. In case of error, null is returned. private XmlQualifiedName ParseOutputMethod(string attValue, out XmlOutputMethod method) { string prefix, localName, namespaceName; ResolveQName(/*ignoreDefaultNs:*/true, attValue, out localName, out namespaceName, out prefix); method = XmlOutputMethod.AutoDetect; if (compiler.IsPhantomNamespace(namespaceName)) { return null; } else if (prefix.Length == 0) { switch (localName) { case "xml" : method = XmlOutputMethod.Xml; break; case "html" : method = XmlOutputMethod.Html; break; case "text" : method = XmlOutputMethod.Text; break; default: ReportError(/*[XT1570]*/Res.Xslt_InvalidAttrValue, "method", attValue); return null; } } else { if (!input.ForwardCompatibility) { ReportWarning(/*[XT1570]*/Res.Xslt_InvalidMethod, attValue); } } return new XmlQualifiedName(localName, namespaceName); } // Suppresses errors if FCB is enabled private void AddUseAttributeSets(List list) { Debug.Assert(input.LocalName == "use-attribute-sets", "we are positioned on this attribute"); Debug.Assert(list != null && list.Count == 0, "It happened that we always add use-attribute-sets first. Otherwise we can't call list.Clear()"); compiler.EnterForwardsCompatible(); foreach (string qname in XmlConvert.SplitString(input.Value)) { AddInstruction(list, SetLineInfo(f.UseAttributeSet(CreateXPathQName(qname)), input.BuildLineInfo())); } if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { // There were errors in the list, ignore the whole list list.Clear(); } } private List ParseUseCharacterMaps(int attNum) { List useCharacterMaps = new List (); if (input.MoveToXsltAttribute(attNum, "use-character-maps")) { compiler.EnterForwardsCompatible(); foreach (string qname in XmlConvert.SplitString(input.Value)) { useCharacterMaps.Add(CreateXPathQName(qname)); } if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) { useCharacterMaps.Clear(); // There were errors in the list, ignore the whole list } } return useCharacterMaps; } private string ParseStringAttribute(int attNum, string attName) { if (input.MoveToXsltAttribute(attNum, attName)) { return input.Value; } return null; } private char ParseCharAttribute(int attNum, string attName, char defVal) { if (input.MoveToXsltAttribute(attNum, attName)) { if (input.Value.Length == 1) { return input.Value[0]; } else { if (input.IsRequiredAttribute(attNum) || !input.ForwardCompatibility) { ReportError(/*[XT_029]*/Res.Xslt_CharAttribute, attName); } } } return defVal; } // Suppresses errors if FCB is enabled private TriState ParseYesNoAttribute(int attNum, string attName) { Debug.Assert(!input.IsRequiredAttribute(attNum), "All Yes/No attributes are optional."); if (input.MoveToXsltAttribute(attNum, attName)) { switch (input.Value) { case "yes" : return TriState.True; case "no" : return TriState.False; default: if (!input.ForwardCompatibility) { ReportError(/*[XT_028]*/Res.Xslt_BistateAttribute, attName, "yes", "no"); } break; } } return TriState.Unknown; } private void ParseTypeAttribute(int attNum) { Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'type' attributes are optional."); if (input.MoveToXsltAttribute(attNum, "type")) { CheckError(true, /*[???]*/Res.Xslt_SchemaAttribute, "type"); } } private void ParseValidationAttribute(int attNum, bool defVal) { Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'validation' attributes are optional."); string attributeName = defVal ? atoms.DefaultValidation : "validation"; if (input.MoveToXsltAttribute(attNum, attributeName)) { string value = input.Value; if (value == "strip") { // no error } else if ( value == "preserve" || value == "strict" && !defVal || value == "lax" && !defVal ) { ReportError(/*[???]*/Res.Xslt_SchemaAttributeValue, attributeName, value); } else if (!input.ForwardCompatibility) { ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, attributeName, value); } } } private void ParseInputTypeAnnotationsAttribute(int attNum) { Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'input-type-validation' attributes are optional."); if (input.MoveToXsltAttribute(attNum, "input-type-annotations")) { string value = input.Value; switch (value) { case "unspecified": break; case "strip": case "preserve": if (compiler.inputTypeAnnotations == null) { compiler.inputTypeAnnotations = value; } else { CheckError(compiler.inputTypeAnnotations != value, /*[XTSE0265]*/Res.Xslt_InputTypeAnnotations); } break; default: if (!input.ForwardCompatibility) { ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, "input-type-annotations", value); } break; } } } // ToDo: We don't need separation on SkipEmptyContent() and CheckNoContent(). Merge them back when we are done with parsing. private void CheckNoContent() { input.MoveToElement(); QName parentName = input.ElementName; ISourceLineInfo errorLineInfo = SkipEmptyContent(); if (errorLineInfo != null) { compiler.ReportError(errorLineInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, parentName); } } // Returns ISourceLineInfo of the first violating (non-whitespace) node, or null otherwise private ISourceLineInfo SkipEmptyContent() { ISourceLineInfo result = null; // Really EMPTY means no content at all, but for the sake of compatibility with MSXML we allow whitespaces if (input.MoveToFirstChild()) { do { // NOTE: XmlNodeType.SignificantWhitespace are not allowed here if (input.NodeType != XmlNodeType.Whitespace) { if (result == null) { result = input.BuildNameLineInfo(); } input.SkipNode(); } } while (input.MoveToNextSibling()); } return result; } private static XslNode SetLineInfo(XslNode node, ISourceLineInfo lineInfo) { Debug.Assert(node != null); node.SourceLine = lineInfo; return node; } private static void SetContent(XslNode node, List content) { Debug.Assert(node != null); if (content != null && content.Count == 0) { content = null; // Actualy we can reuse this ArayList. } node.SetContent(content); } private static XslNode SetInfo(XslNode to, List content, ContextInfo info) { Debug.Assert(to != null); to.Namespaces = info.nsList; SetContent(to, content); SetLineInfo(to, info.lineInfo); return to; } // NOTE! We inverting namespace order that is irelevant for namespace of the same node, but // for included styleseets we don't keep stylesheet as a node and adding it's namespaces to // each toplevel element by MergeNamespaces(). // Namespaces of stylesheet can be overriden in template and to make this works correclety we // should attache them after NsDec of top level elements. // Toplevel element almost never contais NsDecl and in practice node duplication will not happened, but if they have // we should copy NsDecls of stylesheet localy in toplevel elements. private static NsDecl MergeNamespaces(NsDecl thisList, NsDecl parentList) { if (parentList == null) { return thisList; } if (thisList == null) { return parentList; } // Clone all nodes and attache them to nodes of thisList; while (parentList != null) { bool duplicate = false; for (NsDecl tmp = thisList; tmp != null; tmp = tmp.Prev) { if (Ref.Equal(tmp.Prefix, parentList.Prefix) && ( tmp.Prefix != null || // Namespace declaration tmp.NsUri == parentList.NsUri // Extension or excluded namespace )) { duplicate = true; break; } } if (!duplicate) { thisList = new NsDecl(thisList, parentList.Prefix, parentList.NsUri); } parentList = parentList.Prev; } return thisList; } // -------------------------------- IErrorHelper -------------------------------- public void ReportError(string res, params string[] args) { compiler.ReportError(input.BuildNameLineInfo(), res, args); } public void ReportWarning(string res, params string[] args) { compiler.ReportWarning(input.BuildNameLineInfo(), res, args); } private void ReportNYI(string arg) { if (! input.ForwardCompatibility) { ReportError(Res.Xslt_NotYetImplemented, arg); } } public void CheckError(bool cond, string res, params string[] args) { if (cond) { compiler.ReportError(input.BuildNameLineInfo(), res, args); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BitmapDownload.cs
- Transform.cs
- AndCondition.cs
- SqlParameterCollection.cs
- LogicalExpr.cs
- SingleStorage.cs
- XmlSchemaAttribute.cs
- __Filters.cs
- WebPartDisplayModeCancelEventArgs.cs
- DataGridSortCommandEventArgs.cs
- EventLogPermissionEntry.cs
- LiteralControl.cs
- WebPartConnectionsCancelVerb.cs
- RowUpdatedEventArgs.cs
- Parser.cs
- GroupAggregateExpr.cs
- SQLMoney.cs
- HttpApplicationFactory.cs
- WsdlHelpGeneratorElement.cs
- IncrementalCompileAnalyzer.cs
- JsonFormatReaderGenerator.cs
- StrokeCollection.cs
- AbandonedMutexException.cs
- DateTimeOffset.cs
- CacheDependency.cs
- AnchorEditor.cs
- UInt64Storage.cs
- SafeNativeMethods.cs
- XmlUtil.cs
- DesignerAutoFormatStyle.cs
- FixedTextSelectionProcessor.cs
- Matrix3DStack.cs
- Error.cs
- SqlCacheDependencyDatabase.cs
- URLMembershipCondition.cs
- WebRequestModuleElementCollection.cs
- AssemblyCache.cs
- Encoder.cs
- TreeNodeStyleCollection.cs
- TableProvider.cs
- List.cs
- TypeSchema.cs
- ApplicationHost.cs
- GroupItemAutomationPeer.cs
- MultipleViewProviderWrapper.cs
- CodeCompileUnit.cs
- SchemaElementDecl.cs
- XPathAncestorQuery.cs
- EmptyCollection.cs
- PolyBezierSegmentFigureLogic.cs
- ClientSponsor.cs
- DPTypeDescriptorContext.cs
- BindingSource.cs
- DSASignatureDeformatter.cs
- DocumentReferenceCollection.cs
- WMIGenerator.cs
- DownloadProgressEventArgs.cs
- UIElementIsland.cs
- EntityDataSourceContainerNameItem.cs
- Typography.cs
- SimpleRecyclingCache.cs
- FilterQueryOptionExpression.cs
- ApplicationFileCodeDomTreeGenerator.cs
- Simplifier.cs
- PerformanceCounter.cs
- DecoderFallbackWithFailureFlag.cs
- Variable.cs
- SystemNetHelpers.cs
- login.cs
- __Error.cs
- LinearGradientBrush.cs
- PageAdapter.cs
- TypeBuilderInstantiation.cs
- WebDescriptionAttribute.cs
- CodeAttributeDeclaration.cs
- ModelPropertyCollectionImpl.cs
- Visual3D.cs
- SpecialNameAttribute.cs
- ThrowOnMultipleAssignment.cs
- ReceiveDesigner.xaml.cs
- XmlAttributes.cs
- entitydatasourceentitysetnameconverter.cs
- CollectionConverter.cs
- DataSourceConverter.cs
- EncodingDataItem.cs
- LineServices.cs
- BulletedListEventArgs.cs
- SoapSchemaMember.cs
- SelectorAutomationPeer.cs
- DeclarationUpdate.cs
- ApplicationSettingsBase.cs
- XamlReader.cs
- FactoryGenerator.cs
- TriggerBase.cs
- AuthenticationService.cs
- FillBehavior.cs
- StringAnimationUsingKeyFrames.cs
- GuidTagList.cs
- MethodImplAttribute.cs
- JulianCalendar.cs