diff --git a/XpathRunner/Assets/avalonia-logo.ico b/XpathRunner/Assets/avalonia-logo.ico deleted file mode 100644 index da8d49f..0000000 Binary files a/XpathRunner/Assets/avalonia-logo.ico and /dev/null differ diff --git a/XpathRunner/Assets/deletebtn.png b/XpathRunner/Assets/deletebtn.png new file mode 100644 index 0000000..08fb7ef Binary files /dev/null and b/XpathRunner/Assets/deletebtn.png differ diff --git a/XpathRunner/Service/DialogService.cs b/XpathRunner/Service/DialogService.cs index 462ea42..a8b0438 100644 --- a/XpathRunner/Service/DialogService.cs +++ b/XpathRunner/Service/DialogService.cs @@ -19,11 +19,24 @@ public class DialogService var files = await provider.OpenFilePickerAsync(new FilePickerOpenOptions() { Title = "Open Text File", - AllowMultiple = false + AllowMultiple = true, + FileTypeFilter = AllowedFileTypes() + }); fileList = files?.Select(file => file.TryGetLocalPath()).ToArray(); return fileList; } + + private static FilePickerFileType[] AllowedFileTypes() + { + return new[] + { + new FilePickerFileType("HTML or XML Files") + { + Patterns = new[] {"*.html", "*.htm", "*.xml"} + } + }; + } } \ No newline at end of file diff --git a/XpathRunner/Service/XpathService.cs b/XpathRunner/Service/XpathService.cs index c3b5f61..e6ed92a 100644 --- a/XpathRunner/Service/XpathService.cs +++ b/XpathRunner/Service/XpathService.cs @@ -7,6 +7,9 @@ public class XpathService { public IList ExtractHtmlContent(string filepath, string xpath) { + if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(xpath)) + return new List(); + var content = new List(); var doc = new HtmlDocument(); doc.Load(filepath); @@ -16,7 +19,28 @@ public IList ExtractHtmlContent(string filepath, string xpath) return content; foreach (var result in results) - content.Add(result.InnerText); + content.Add(result.InnerText.Trim()); + return content; + } + + public IList ExtractHtmlContent(string[] filepaths, string xpath) + { + if (filepaths == null || filepaths.Length == 0 || string.IsNullOrEmpty(xpath)) + return new List(); + + var content = new List(); + foreach (var filepath in filepaths) + { + var doc = new HtmlDocument(); + doc.Load(filepath); + + var results = doc.DocumentNode.SelectNodes(xpath); + if (results == null) + continue; + + foreach (var result in results) + content.Add(result.InnerText.Trim()); + } return content; } } \ No newline at end of file diff --git a/XpathRunner/ViewModels/MainWindowViewModel.cs b/XpathRunner/ViewModels/MainWindowViewModel.cs index 7630f54..2d00f1b 100644 --- a/XpathRunner/ViewModels/MainWindowViewModel.cs +++ b/XpathRunner/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,10 @@ -using System.Collections.ObjectModel; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Threading.Tasks; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -12,9 +18,11 @@ public class MainWindowViewModel : ObservableObject private readonly DialogService _dialogService = new(); private string _filePath; private bool _isFileSelected; - private string _xpathExpression; + private string _xpathExpression ; private bool _isXpathResultsEmpty; private int _xpathResultCount; + private ObservableCollection? _selectedFiles; + private string _selectedFileLabel; public MainWindowViewModel() { @@ -31,16 +39,36 @@ public MainWindowViewModel() { IsBusy = true; var xpathService = new XpathService(); - var results = xpathService.ExtractHtmlContent(FilePath, XpathExpression); - XpathResults.Clear(); - foreach (var result in results) + var filePaths = SelectedFiles?.Select(file => file.FullName).ToArray(); + if (filePaths != null) { - XpathResults.Add(result); + var results = xpathService.ExtractHtmlContent(filePaths, XpathExpression); + XpathResults.Clear(); + foreach (var result in results) + { + XpathResults.Add(result); + } + XpathResultsCount = XpathResults.Count; + IsXpathResultsEmpty = XpathResultsCount == 0; } - XpathResultsCount = XpathResults.Count; - IsXpathResultsEmpty = XpathResultsCount == 0; IsBusy = false; }); + + AddFilesFileCommand = new RelayCommand(async () => await AddFiles()); + RemoveFileCommand = new RelayCommand(RemoveFile); + + SelectedFiles = new ObservableCollection(); + SelectedFiles.CollectionChanged += (sender, args) => + { + if (args.Action == NotifyCollectionChangedAction.Add) + { + foreach (FileInfo file in args.NewItems) + { + FilePath = file.FullName; + } + UpdateSelectedFilesLabel(); + } + }; } #region Public properties @@ -94,6 +122,14 @@ public int XpathResultsCount get => _xpathResultCount; set => SetProperty(ref _xpathResultCount, value); } + + public ObservableCollection FilesToProcess { get; } = new(); + + public string SelectedFilesLabel + { + get => _selectedFileLabel; + set => SetProperty(ref _selectedFileLabel, value); + } #endregion @@ -101,6 +137,54 @@ public int XpathResultsCount public ICommand FilePickerCommand { get; } public ICommand GetXpathResultsCommand { get; } + public ICommand AddFilesFileCommand { get; } + public ICommand RemoveFileCommand { get; } + + public ObservableCollection? SelectedFiles + { + get => _selectedFiles; + set => SetProperty(ref _selectedFiles, value); + } + + #endregion + + #region Private methods + private async Task AddFiles() + { + var paths = await _dialogService.ShowFolderBrowserDialogAsync(); + foreach (string path in paths) + { + var fileInfo = new FileInfo(path); + bool isValidFile = fileInfo.Extension == ".html" || fileInfo.Extension == ".htm" || fileInfo.Extension == ".xml"; + if (isValidFile && FilesToProcess.All(file => file.FullName != fileInfo.FullName)) + { + FilesToProcess.Add(new FileInfo(path)); + } + + if (FilesToProcess.Count > 0) + { + FilePath = FilesToProcess[0].FullName; + } + UpdateSelectedFilesLabel(); + } + } + + private void RemoveFile(FileInfo? file) + { + if (file == null || !FilesToProcess.Contains(file)) return; + FilesToProcess.Remove(file); + } + private void UpdateSelectedFilesLabel() + { + if (SelectedFiles.Count == 1) + { + SelectedFilesLabel = $"Selected file : {FilePath}"; + } + else + { + SelectedFilesLabel = $"Number of selected files : {SelectedFiles.Count}"; + } + } #endregion } \ No newline at end of file diff --git a/XpathRunner/Views/MainView.axaml b/XpathRunner/Views/MainView.axaml index 758f90c..61e5acc 100644 --- a/XpathRunner/Views/MainView.axaml +++ b/XpathRunner/Views/MainView.axaml @@ -6,31 +6,70 @@ xmlns:views="clr-namespace:XpathRunner.Views" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:DataType="vm:MainWindowViewModel" + x:Name="mainView" x:Class="XpathRunner.Views.MainView"> - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/XpathRunner/Views/MainView.axaml.cs b/XpathRunner/Views/MainView.axaml.cs index 0289362..0f3c2aa 100644 --- a/XpathRunner/Views/MainView.axaml.cs +++ b/XpathRunner/Views/MainView.axaml.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Platform.Storage; using HtmlAgilityPack; +using XpathRunner.ViewModels; namespace XpathRunner.Views; @@ -16,4 +20,6 @@ public MainView() { InitializeComponent(); } + + public MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext; } \ No newline at end of file