Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it possible to evaluate xpath expression on multiple files #1

Merged
merged 4 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed XpathRunner/Assets/avalonia-logo.ico
Binary file not shown.
Binary file added XpathRunner/Assets/deletebtn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 14 additions & 1 deletion XpathRunner/Service/DialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,24 @@
var files = await provider.OpenFilePickerAsync(new FilePickerOpenOptions()
{
Title = "Open Text File",
AllowMultiple = false
AllowMultiple = true,
FileTypeFilter = AllowedFileTypes()

});
fileList = files?.Select(file => file.TryGetLocalPath()).ToArray();

Check warning on line 26 in XpathRunner/Service/DialogService.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.

Check warning on line 26 in XpathRunner/Service/DialogService.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.

Check warning on line 26 in XpathRunner/Service/DialogService.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.


return fileList;
}

private static FilePickerFileType[] AllowedFileTypes()
{
return new[]
{
new FilePickerFileType("HTML or XML Files")
{
Patterns = new[] {"*.html", "*.htm", "*.xml"}
}
};
}
}
26 changes: 25 additions & 1 deletion XpathRunner/Service/XpathService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public class XpathService
{
public IList<string> ExtractHtmlContent(string filepath, string xpath)
{
if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(xpath))
return new List<string>();

var content = new List<string>();
var doc = new HtmlDocument();
doc.Load(filepath);
Expand All @@ -16,7 +19,28 @@ public IList<string> 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<string> ExtractHtmlContent(string[] filepaths, string xpath)
{
if (filepaths == null || filepaths.Length == 0 || string.IsNullOrEmpty(xpath))
return new List<string>();

var content = new List<string>();
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;
}
}
100 changes: 92 additions & 8 deletions XpathRunner/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -12,18 +18,20 @@
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<FileInfo>? _selectedFiles;
private string _selectedFileLabel;

public MainWindowViewModel()

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Non-nullable field '_filePath' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Non-nullable field '_xpathExpression' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Non-nullable field '_selectedFileLabel' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Non-nullable field '_filePath' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Non-nullable field '_xpathExpression' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Non-nullable field '_selectedFileLabel' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable field '_filePath' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable field '_xpathExpression' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 27 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable field '_selectedFileLabel' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
{
IsXpathResultsEmpty = true;
FilePickerCommand = new RelayCommand(async () =>
{
IsBusy = true;
var files = await _dialogService.ShowFolderBrowserDialogAsync();
FilePath = files?[0];

Check warning on line 34 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Possible null reference assignment.

Check warning on line 34 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Possible null reference assignment.

Check warning on line 34 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Possible null reference assignment.
IsBusy = false;
});

Expand All @@ -31,16 +39,36 @@
{
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<FileInfo>(RemoveFile);

SelectedFiles = new ObservableCollection<FileInfo>();
SelectedFiles.CollectionChanged += (sender, args) =>
{
if (args.Action == NotifyCollectionChangedAction.Add)
{
foreach (FileInfo file in args.NewItems)

Check warning on line 65 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 65 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Dereference of a possibly null reference.

Check warning on line 65 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Dereference of a possibly null reference.
{
FilePath = file.FullName;
}
UpdateSelectedFilesLabel();
}
};
}

#region Public properties
Expand Down Expand Up @@ -94,13 +122,69 @@
get => _xpathResultCount;
set => SetProperty(ref _xpathResultCount, value);
}

public ObservableCollection<FileInfo> FilesToProcess { get; } = new();

public string SelectedFilesLabel
{
get => _selectedFileLabel;
set => SetProperty(ref _selectedFileLabel, value);
}

#endregion

#region Commands

public ICommand FilePickerCommand { get; }
public ICommand GetXpathResultsCommand { get; }
public ICommand AddFilesFileCommand { get; }
public ICommand RemoveFileCommand { get; }

public ObservableCollection<FileInfo>? 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)

Check warning on line 155 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 155 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Dereference of a possibly null reference.

Check warning on line 155 in XpathRunner/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Dereference of a possibly null reference.
{
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
}
59 changes: 49 additions & 10 deletions XpathRunner/Views/MainView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<Grid Margin="50">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0">
<Button Margin="0 0 0 20" ClickMode="Press" Command="{Binding FilePickerCommand }"> Open HTML/XML file</Button>
<TextBox Text="{Binding FilePath}" IsVisible="{Binding IsFileSelected}" FontSize="15" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="7*" />
</Grid.ColumnDefinitions>

<StackPanel Grid.Column="0" Grid.Row="0" Grid.RowSpan="2">
<Button Margin="0 0 0 20" ClickMode="Press" Command="{Binding AddFilesFileCommand }"> Open HTML/XML files</Button>
<ScrollViewer MaxHeight="350" HorizontalScrollBarVisibility="Disabled">
<ListBox
SelectedItems="{Binding SelectedFiles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Background="Transparent" SelectionMode="Multiple" ItemsSource="{Binding FilesToProcess}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="1">
<Grid ColumnDefinitions="*, Auto">
<TextBlock Grid.Column="0" ToolTip.Tip="{Binding FullName}" Text="{Binding Name}"
TextWrapping="WrapWithOverflow" />
<Button Grid.Column="1"
Command="{Binding ViewModel.RemoveFileCommand, ElementName=mainView}"
CommandParameter="{Binding}"
VerticalAlignment="Top" HorizontalAlignment="Right">
<Button.ContentTemplate>
<DataTemplate>
<Image Margin="0" Width="15" Height="15" VerticalAlignment="Top"
HorizontalAlignment="Right" Source="/Assets/deletebtn.png" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</StackPanel>


<StackPanel Grid.Row="0" Grid.Column="1" Margin="10 0 0 0">
<Label Content="{Binding SelectedFilesLabel}" IsVisible="{Binding IsFileSelected}" FontSize="12" />
<Grid Margin="0 20 0 20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="18" Text="Xpath expression"/>
<TextBox Grid.Column="1" Text="{Binding XpathExpression}" FontSize="15"/>
<TextBlock VerticalAlignment="Center" Grid.Column="0" FontWeight="Bold" FontSize="15" Text="Xpath: "/>
<TextBox Grid.Column="1" Text="{Binding XpathExpression}" TextWrapping="Wrap" FontSize="15" MaxHeight="100"/>
<Button Grid.Column="2" Margin="10 0 0 0" ClickMode="Press" Command="{Binding GetXpathResultsCommand}">Search</Button>
</Grid>
<Button Margin="0 0 0 20" ClickMode="Press" Command="{Binding GetXpathResultsCommand}" >Search</Button>

</StackPanel>


<views:XpathResults Grid.Row="1" IsVisible="{Binding !IsXpathResultsEmpty}"/>
<StackPanel IsVisible="{Binding !IsXpathResultsEmpty}" HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal">
<views:XpathResults Margin="10 0 0 0" Grid.Row="1" Grid.Column="1" IsVisible="{Binding !IsXpathResultsEmpty}"/>
<StackPanel Grid.Row="2" Grid.Column="1" IsVisible="{Binding !IsXpathResultsEmpty}" HorizontalAlignment="Right" Orientation="Horizontal">
<Label Grid.Row="2" Content="Total : " FontSize="15"/>
<Label Grid.Row="2" Content="{Binding XpathResultsCount}" FontSize="15"/>
</StackPanel>
Expand Down
6 changes: 6 additions & 0 deletions XpathRunner/Views/MainView.axaml.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -16,4 +20,6 @@
{
InitializeComponent();
}

public MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext;

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Converting null literal or possible null value to non-nullable type.

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Possible null reference return.

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Converting null literal or possible null value to non-nullable type.

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Possible null reference return.

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Converting null literal or possible null value to non-nullable type.

Check warning on line 24 in XpathRunner/Views/MainView.axaml.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Possible null reference return.
}
Loading