private static void AppendStringDictValue(ParsedAttribute attribute, CodeObjectCreateExpression newKeyValueExpression) { var expressionStringParser = new ExpressionStringParser(attribute.Value); expressionStringParser.Parse(); var values = expressionStringParser.ExpressionStringTokens; if (values.Count == 1) { var expressionStringToken = values[0]; if (expressionStringToken.IsExpression) { newKeyValueExpression.Parameters.Add(new CodeSnippetExpression { Value = expressionStringToken.Value }); } else { newKeyValueExpression.Parameters.Add(new CodePrimitiveExpression { Value = expressionStringToken.Value }); } } else { var concatExpression = CodeDomClassBuilder.GetConcatExpression(values); newKeyValueExpression.Parameters.Add(concatExpression); } }
public UnsupportedValue(KAOSCoreElement element, ParsedAttribute attribute, object value) : base(string.Format("'{0}' is not supported in '{1}' on '{2}'", value?.GetType()?.Name, attribute?.GetType()?.Name, element?.GetType()?.Name), attribute) { }
/// <summary> /// Parses the next attribute. /// </summary> /// <param name="headerData">The header data.</param> /// <param name="lastAttribute">The last attribute.</param> /// <returns>THe parsed attribute.</returns> private static ParsedAttribute ParseNextAttribute(string headerData, ParsedAttribute lastAttribute) { char c; var startIndex = lastAttribute?.EndIndex ?? 0; var attributePivotIndex = headerData.IndexOf("=\"", startIndex, StringComparison.Ordinal); var attributeStartIndex = -1; var attributeEndIndex = -1; // Find the attribute name for (var i = attributePivotIndex - 1; i >= 0; i--) { c = headerData[i]; if (!char.IsWhiteSpace(c)) { continue; } attributeStartIndex = i + 1; break; } // find the attribute value if (attributeStartIndex >= 0) { for (var i = attributePivotIndex + 2; i < headerData.Length; i++) { c = headerData[i]; if (c != '"') { continue; } attributeEndIndex = i; break; } if (attributeEndIndex == -1) { attributeEndIndex = headerData.Length - 1; } } if (attributeStartIndex == -1) { return(null); } return(new ParsedAttribute { Key = HttpUtility.UrlDecode(headerData.Substring(attributeStartIndex, attributePivotIndex - attributeStartIndex)), Value = HttpUtility.UrlDecode(headerData.Substring(attributePivotIndex + 2, attributeEndIndex - attributePivotIndex - 2)), EndIndex = attributeEndIndex, StartIndex = attributeStartIndex, Substring = headerData.Substring(attributeStartIndex, attributeEndIndex - attributeStartIndex + 1) }); }
/// <summary> /// Parses the next attribute. /// </summary> /// <param name="headerData">The header data.</param> /// <param name="lastAttribute">The last attribute.</param> /// <returns>THe parsed attribute</returns> private static ParsedAttribute ParseNextAttribute(string headerData, ParsedAttribute lastAttribute) { var c = default(char); var nc = default(char); var startIndex = lastAttribute == null ? 0 : lastAttribute.EndIndex; var attributePivotIndex = headerData.IndexOf("=\"", startIndex); var attributeStartIndex = -1; var attributeEndIndex = -1; for (var i = attributePivotIndex - 1; i >= 0; i--) { c = headerData[i]; if (char.IsWhiteSpace(c)) { attributeStartIndex = i + 1; break; } } if (attributeStartIndex >= 0) { for (var i = attributePivotIndex + 2; i < headerData.Length; i++) { c = headerData[i]; nc = i + 1 < headerData.Length ? headerData[i + 1] : default(char); if (c == '"' && nc != '"') { attributeEndIndex = i; break; } } if (attributeEndIndex == -1) { attributeEndIndex = headerData.Length - 1; } } if (attributeStartIndex == -1) { return(null); } return(new ParsedAttribute { Key = headerData.Substring(attributeStartIndex, attributePivotIndex - attributeStartIndex), Value = headerData.Substring(attributePivotIndex + 1, attributeEndIndex - attributePivotIndex), EndIndex = attributeEndIndex, StartIndex = attributeStartIndex, Substring = headerData.Substring(attributeStartIndex, attributeEndIndex - attributeStartIndex + 1) }); }
/// <summary> /// Parse the next element /// </summary> public ParsedToken Parse() { CharInfo c; // If end of stream when stop here if (EOF) { return(null); } // Current token defined if (_CurrentToken != null) { // End tag out Doctype : error while end tag or doctype parsing, reset parser if (_CurrentToken.TokenType == ParsedTokenType.EndTag || _CurrentToken.TokenType == ParsedTokenType.Doctype) { _CurrentRead = null; _State = ParseState.Content; ResetTagBuffer(); LastParsed = _CurrentToken; _CurrentToken = null; return(LastParsed); } } // Current Attribute defined if (_CurrentAttr != null) { LastParsed = _CurrentAttr; _CurrentAttr = null; return(LastParsed); } // Current Read not empty ? if (_CurrentRead != null) { bool returnLast = true; switch (_State) { // Returns a non closed comment case ParseState.Comment: String comment = GetCurrentRead(true); comment = comment.Substring(4).TrimStart(); LastParsed = new ParsedComment() { Position = _CurrentPosition, Text = HEntity.HtmlDecode(comment, RemoveUnknownOrInvalidEntities) }; break; // Returns a text case ParseState.Content: LastParsed = new ParsedText() { Position = _CurrentPosition, Text = HEntity.HtmlDecode(GetCurrentRead(true), RemoveUnknownOrInvalidEntities) }; break; // Returns a text case ParseState.Doctype: case ParseState.ProcessInstruction: case ParseState.EndTag: case ParseState.Tag: //LastParsed = new ParsedText() { // Position = _CurrentPosition, // Text = GetCurrentRead(true) //}; _State = ParseState.Content; LastParsed = ParseText(); break; // We forget the result //default: // returnLast = false; // break; } _State = ParseState.Content; ResetTagBuffer(); if (returnLast) { return(LastParsed); } } // Read loop while (true) { // Read next char c = ReadChar(); // EOF ? if (c == CharInfo.EOF) { // Check unexpected EOF if (_State != ParseState.Content) { _State = ParseState.Content; ResetTagBuffer(); throw new ParseError("End of file unexpected.", ReadPosition); } // Stop the parsing LastParsed = null; EOF = true; return(null); } // Other case switch (_State) { // In text case ParseState.Content: if (c == '<') { LastParsed = ParseStartTag(); } else { LastParsed = ParseText(); } return(LastParsed); // In tag or process instruction case ParseState.Tag: case ParseState.Doctype: case ParseState.ProcessInstruction: SaveChar(c); LastParsed = ParseInTag(); return(LastParsed); default: break; } } }
/// <summary> /// Parse in tag /// </summary> protected ParsedToken ParseInTag() { _CurrentRead = null; // Whitespaces CharInfo c; while ((c = ReadChar(false)) != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { ; } var cpos = c.Position; // EOF ? if (c == CharInfo.EOF) { _CurrentToken = null; _State = ParseState.Content; ResetTagBuffer(); throw new ParseError("Unexpected end of file. Tag not closed.", ReadPosition); } // End of auto closed tag ? else if (c == '/' && _State == ParseState.Tag) { CharInfo saveSlash = c; bool spaces = false; while ((c = ReadChar(false)) != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { spaces = true; } if (c != '>') { // Prepare a correct next tag SaveChar(new CharInfo('>', (c == CharInfo.EOF) ? saveSlash.Position : c.Position)); SaveChar(saveSlash); throw new ParseError("Invalid char after '/'. End of auto closed tag expected.", cpos); } if (spaces) { // Prepare a correct next tag SaveChar(c); SaveChar(saveSlash); // Raise the error throw new ParseError("Invalid auto closed tag, '/' need to be follow by '>'.", cpos); } // Returns autoclosed var result = ParsedTag.AutoClosedTag(((ParsedTag)_CurrentToken).TagName); result.Position = cpos; _CurrentToken = null; _CurrentRead = null; _State = ParseState.Content; ResetTagBuffer(); return(result); } // End of process instruction else if (c == '?' && _State == ParseState.ProcessInstruction) { c = ReadChar(false); if (c != '>') { throw new ParseError("Invalid char after '?'. End of process instruction expected.", cpos); } // Returns processinstruction var result = ParsedTag.CloseProcessInstruction(((ParsedTag)_CurrentToken).TagName); result.Position = cpos; _CurrentToken = null; _CurrentRead = null; _State = ParseState.Content; ResetTagBuffer(); return(result); } else if (c == '>') { // Check tag if (_State == ParseState.ProcessInstruction) { throw new ParseError("A process instruction need to be closed with '?>'.", cpos); } // Returns close var result = ParsedTag.CloseTag(((ParsedTag)_CurrentToken).TagName); result.Position = cpos; _CurrentToken = null; _CurrentRead = null; _State = ParseState.Content; ResetTagBuffer(); return(result); } // Get the attribute name if (!IsAttributeNameChar(c.AsChar)) { throw new ParseError("Unexpected character.", cpos); } AddToCurrentRead(c); while ((c = ReadChar(false)) != CharInfo.EOF && IsAttributeNameChar(c.AsChar)) { AddToCurrentRead(c); } if (c != CharInfo.EOF) { SaveChar(c); } String attrName = GetCurrentRead(true); ParsePosition attrPos = cpos; // Whitespaces while ((c = ReadChar(false)) != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { ; } // Attribute whithout value if (c != '=') { SaveChar(c); // Attribute whithout content return(new ParsedAttribute() { Position = attrPos, Name = attrName, Value = null, Quote = '\0' }); } // Whitespaces while ((c = ReadChar(false)) != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { ; } // Search the value if (c == 0 || c == '/' || c == '?' || c == '>') { _CurrentAttr = new ParsedAttribute() { Position = attrPos, Name = attrName, Value = null, Quote = '\0' }; if (c != CharInfo.EOF) { SaveChar(c); } throw new ParseError("Attribute value expected.", ReadPosition); } // Quoted value ? _CurrentRead = null; char quote = '\0'; if (c == '"' || c == '\'') { quote = c.AsChar; while ((c = ReadChar(false)) != CharInfo.EOF && c != quote) { AddToCurrentRead(c); } _CurrentAttr = new ParsedAttribute() { Position = attrPos, Name = attrName, Value = HEntity.HtmlDecode(GetCurrentRead(true), RemoveUnknownOrInvalidEntities), Quote = quote }; if (c == CharInfo.EOF) { throw new ParseError("Unexpected end of file. Attribute is not closed.", ReadPosition); } var result = _CurrentAttr; _CurrentAttr = null; return(result); } // Unquoted value AddToCurrentRead(c); while ((c = ReadChar(false)) != CharInfo.EOF && !Char.IsWhiteSpace(c.AsChar) && c != '"' && c != '\'' && c != '=' && c != '<' && c != '>' && c != '`') { AddToCurrentRead(c); } SaveChar(c); return(new ParsedAttribute() { Position = attrPos, Name = attrName, Value = HEntity.HtmlDecode(GetCurrentRead(true), RemoveUnknownOrInvalidEntities), Quote = quote }); }
public void TestParse_TagAttribute() { // Attributes StringReader reader = new StringReader("<div attr1 attr2 = value2 attr3=\"val&ue&test;\" attr4 = 'value' >"); HParser parser = new HParser(reader); var pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(5, 0, 5), pres.Position); Assert.Equal(new ParsePosition(12, 0, 12), parser.ReadPosition); ParsedAttribute pAttr = (ParsedAttribute)pres; Assert.Equal("attr1", pAttr.Name); Assert.Equal(null, pAttr.Value); Assert.Equal('\0', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(12, 0, 12), pres.Position); Assert.Equal(new ParsePosition(26, 0, 26), parser.ReadPosition); Assert.Equal(ParsedTokenType.Attribute, pres.TokenType); pAttr = (ParsedAttribute)pres; Assert.Equal("attr2", pAttr.Name); Assert.Equal("value2", pAttr.Value); Assert.Equal('\0', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(27, 0, 27), pres.Position); Assert.Equal(new ParsePosition(51, 0, 51), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr3", pAttr.Name); Assert.Equal("val&ue&test;", pAttr.Value); Assert.Equal('"', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(52, 0, 52), pres.Position); Assert.Equal(new ParsePosition(67, 0, 67), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr4", pAttr.Name); Assert.Equal("value", pAttr.Value); Assert.Equal('\'', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(68, 0, 68), pres.Position); Assert.Equal(new ParsePosition(69, 0, 69), parser.ReadPosition); Assert.Equal(ParsedTokenType.CloseTag, pres.TokenType); pres = parser.Parse(); Assert.Equal(new ParsePosition(69, 0, 69), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); // Attribute with remove entities option reader = new StringReader("<div attr1 attr2 = value2 attr3=\"val&ue&test;\" attr4 = 'value' >"); parser = new HParser(reader); parser.RemoveUnknownOrInvalidEntities = true; pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(5, 0, 5), pres.Position); Assert.Equal(new ParsePosition(12, 0, 12), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr1", pAttr.Name); Assert.Equal(null, pAttr.Value); Assert.Equal('\0', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(12, 0, 12), pres.Position); Assert.Equal(new ParsePosition(26, 0, 26), parser.ReadPosition); Assert.Equal(ParsedTokenType.Attribute, pres.TokenType); pAttr = (ParsedAttribute)pres; Assert.Equal("attr2", pAttr.Name); Assert.Equal("value2", pAttr.Value); Assert.Equal('\0', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(27, 0, 27), pres.Position); Assert.Equal(new ParsePosition(51, 0, 51), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr3", pAttr.Name); Assert.Equal("val&ue", pAttr.Value); Assert.Equal('"', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(52, 0, 52), pres.Position); Assert.Equal(new ParsePosition(67, 0, 67), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr4", pAttr.Name); Assert.Equal("value", pAttr.Value); Assert.Equal('\'', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(68, 0, 68), pres.Position); Assert.Equal(new ParsePosition(69, 0, 69), parser.ReadPosition); Assert.Equal(ParsedTokenType.CloseTag, pres.TokenType); pres = parser.Parse(); Assert.Equal(new ParsePosition(69, 0, 69), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); // Attribute without value reader = new StringReader("<div attr1 = >"); parser = new HParser(reader); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); var pex = Assert.Throws <ParseError>(() => parser.Parse()); Assert.Equal("Attribute value expected.", pex.Message); Assert.Equal(new ParsePosition(13, 0, 13), pex.Position); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(5, 0, 5), pres.Position); Assert.Equal(new ParsePosition(13, 0, 13), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr1", pAttr.Name); Assert.Equal(null, pAttr.Value); Assert.Equal('\0', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(13, 0, 13), pres.Position); Assert.Equal(new ParsePosition(14, 0, 14), parser.ReadPosition); Assert.Equal(ParsedTokenType.CloseTag, pres.TokenType); pres = parser.Parse(); Assert.Equal(new ParsePosition(14, 0, 14), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); // Attribute with value unclosed reader = new StringReader("<div attr1 = \"value ><div attr2=\"value\" >"); parser = new HParser(reader); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(5, 0, 5), pres.Position); Assert.Equal(new ParsePosition(33, 0, 33), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr1", pAttr.Name); Assert.Equal("value ><div attr2=", pAttr.Value); Assert.Equal('"', pAttr.Quote); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(33, 0, 33), pres.Position); Assert.Equal(new ParsePosition(38, 0, 38), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("value", pAttr.Name); Assert.Equal(null, pAttr.Value); Assert.Equal('\0', pAttr.Quote); pex = Assert.Throws <ParseError>(() => parser.Parse()); Assert.Equal("Unexpected character.", pex.Message); Assert.Equal(new ParsePosition(38, 0, 38), pex.Position); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(40, 0, 40), pres.Position); Assert.Equal(new ParsePosition(41, 0, 41), parser.ReadPosition); Assert.Equal(ParsedTokenType.CloseTag, pres.TokenType); pres = parser.Parse(); Assert.Equal(new ParsePosition(41, 0, 41), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); // Attribute with end of file reader = new StringReader("<div attr1 = \"value "); parser = new HParser(reader); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); pex = Assert.Throws <ParseError>(() => parser.Parse()); Assert.Equal("Unexpected end of file. Attribute is not closed.", pex.Message); Assert.Equal(new ParsePosition(20, 0, 20), pex.Position); pres = parser.Parse(); Assert.IsType <ParsedAttribute>(pres); Assert.Equal(new ParsePosition(5, 0, 5), pres.Position); Assert.Equal(new ParsePosition(20, 0, 20), parser.ReadPosition); pAttr = (ParsedAttribute)pres; Assert.Equal("attr1", pAttr.Name); Assert.Equal("value ", pAttr.Value); Assert.Equal('"', pAttr.Quote); pex = Assert.Throws <ParseError>(() => parser.Parse()); Assert.Equal("End of file unexpected.", pex.Message); Assert.Equal(new ParsePosition(20, 0, 20), pex.Position); pres = parser.Parse(); Assert.Equal(new ParsePosition(20, 0, 20), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); // Invalid Attribute name reader = new StringReader("<div ' >"); parser = new HParser(reader); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(0, 0, 0), pres.Position); Assert.Equal(new ParsePosition(4, 0, 4), parser.ReadPosition); Assert.Equal(ParsedTokenType.OpenTag, pres.TokenType); Assert.Equal("div", ((ParsedTag)pres).TagName); pex = Assert.Throws <ParseError>(() => parser.Parse()); Assert.Equal("Unexpected character.", pex.Message); Assert.Equal(new ParsePosition(5, 0, 5), pex.Position); pres = parser.Parse(); Assert.IsType <ParsedTag>(pres); Assert.Equal(new ParsePosition(7, 0, 7), pres.Position); Assert.Equal(new ParsePosition(8, 0, 8), parser.ReadPosition); Assert.Equal(ParsedTokenType.CloseTag, pres.TokenType); pres = parser.Parse(); Assert.Equal(new ParsePosition(8, 0, 8), parser.ReadPosition); Assert.Null(pres); Assert.True(parser.EOF); }