// TODO: Should add support to force commas or not, then just use newline as a text separator #if !WINDOWS_UWP /// <summary> /// Parses the passed in file at the given file path, and returns a non-<c>null</c> <see cref="Json"/> instance. /// </summary> /// <param name="filePath">Path of the file to parse</param> /// <param name="rules">Parser rules</param> /// <returns>A non-<c>null</c> <see cref="Json"/> instance</returns> public static Json ParseFile(string filePath, ParserRules rules = null) { if (PathHelpers.IsValidAsPath(filePath) && File.Exists(filePath)) { return(ParseText(File.ReadAllText(filePath), rules)); } else { Json jsonOutput = new Json(null); jsonOutput.AddError($"File path '{filePath ?? "<null>"}' does not exist on disk, or is an invalid path!"); return(jsonOutput); } }
private static Json RunParse(TrackedStringManager tracker, ParserRules rules) { Json output = new Json(tracker); try { if (tracker.Text == null) { output.AddError("Null source text provided!"); tracker.HasChanges = false; return(output); } JsonTextIndexer indexer = new JsonTextIndexer(tracker.Text, rules); // TODO: Handle case where root is document without braces( ie "item : value, item2 : value2") int indexOfFirstOpenBracket = indexer.NextAny(0, '{', '['); // ============ No Brackets =========== if (indexOfFirstOpenBracket == -1) { output.Data = new JsonValue(output.TextTracking, 0, indexer.NextAny(0, '}', ']'), false); tracker.HasChanges = false; return(output); } // ============ Has Brackets =========== char nextBracket = output.TextTracking.Text[indexOfFirstOpenBracket]; if (nextBracket == '{') { output.Data = new JsonDocument(indexer, output.TextTracking, indexOfFirstOpenBracket, out int endIndex); tracker.HasChanges = false; return(output); } else // if(nextBracket == '[') { output.Data = new JsonArray(indexer, output.TextTracking, indexOfFirstOpenBracket, out int endIndex); tracker.HasChanges = false; return(output); } } catch (Exception exc) { output.AddError(exc.ToString()); } return(output); }
public JsonTextIndexer(string text, ParserRules rules = null) { rules = rules ?? new ParserRules(); foreach (char separator in rules.AdditionalSeparatorChars) { m_separatorIndexTracker.Add(separator, new List <int>()); } var commentStartChars = new List <char>(rules.CommentIndicators.Select(c => c.Item1.First())); bool isBetweenQuoteStartAndEnd = false; string targetCommentEnd = null; for (int currCharTargetIndex = 0; currCharTargetIndex < text.Length; ++currCharTargetIndex) { // If we're waiting for the end of a comment, then skip text until it's found if (targetCommentEnd != null) { string subStr = text.Substring(currCharTargetIndex, targetCommentEnd.Length); if (subStr == targetCommentEnd) { currCharTargetIndex += targetCommentEnd.Length - 1; targetCommentEnd = null; } continue; } char charInQuestion = text[currCharTargetIndex]; // If we've started looking for a quote, skip text until end quote is found if (isBetweenQuoteStartAndEnd) { if (charInQuestion == QuoteChar) { isBetweenQuoteStartAndEnd = false; _StoreFoundSeparators(currCharTargetIndex, QuoteChar, m_separatorIndexTracker[QuoteChar]); } } else { // First, look for comments, if we're starting one of those that superceeds everything else for (int index = 0; index < commentStartChars.Count; ++index) { char commentStart = commentStartChars[index]; if (charInQuestion == commentStart) { string commentStr = rules.CommentIndicators[index].Item1; string subStr = text.Substring(currCharTargetIndex, commentStr.Length); if (subStr == commentStr) { targetCommentEnd = rules.CommentIndicators[index].Item2; break; } } } // Second look for separators, that's the main goal! if (targetCommentEnd == null) { foreach (var kvp in m_separatorIndexTracker) { if (kvp.Key == charInQuestion) { // Additionally, keep track of the separator is a quote, because in that case we need to ignore // everything until the end quote, so we need to go into quote searching mode. if (kvp.Key == QuoteChar) { isBetweenQuoteStartAndEnd = true; } _StoreFoundSeparators(currCharTargetIndex, charInQuestion, kvp.Value); break; } } } } } // Note: We're looping in order, thus all of our add calls will be putting items in index order // without having to do binary searches so we'll just call add void _StoreFoundSeparators(int _characterIndex, char _separator, List <int> _separatorIndexTracker) { m_separatorOccurenceTracker.Add(new FoundSeparator(_characterIndex, _separator)); _separatorIndexTracker.Add(_characterIndex); } }
/// <summary> /// Parses the text from the passed in <see cref="TrackedStringManager"/>, and returns a non-<c>null</c> <see cref="Json"/> instance. /// </summary> /// <param name="jsonText">Some json text.</param> /// <param name="rules">Parser rules</param> /// <returns>A non-<c>null</c> <see cref="Json"/> instance</returns> public static Json ParseText(TrackedStringManager source, ParserRules rules = null) { return(RunParse(source, rules)); }
/// <summary> /// Parses the passed in text, and returns a non-<c>null</c> <see cref="Json"/> instance. /// </summary> /// <param name="jsonText">Some json text.</param> /// <param name="rules">Parser rules</param> /// <returns>A non-<c>null</c> <see cref="Json"/> instance</returns> public static Json ParseText(string jsonText, ParserRules rules = null) { return(RunParse(new TrackedStringManager(jsonText), rules)); }
/// <summary> /// Parses the text from an existing <see cref="FileTextTracker"/> file, and returns a non-<c>null</c> <see cref="Json"/> instance. /// </summary> /// <param name="file">A pre-made <see cref="FileTextTracker"/> to parse the contents of. Note: Will act as the returned <see cref="Json"/> instnace's TextTracking.</param> /// <param name="rules">Parser rules</param> /// <returns>A non-<c>null</c> <see cref="Json"/> instance</returns> public static Json ParseFile(FileTextTracker file, ParserRules rules = null) { return(RunParse(file, rules)); }