Skip to content
Open
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
24 changes: 16 additions & 8 deletions NHSISL.LibPostalClient/NHSISL.LibPostalClient.targets
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
<Project>

<ItemGroup>
<Headers Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net8.0\libpostal.h" />
<Headers Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net10.0\libpostal.h" />
<WindowsNativeFiles
Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net8.0\windows\libpostal-1.dll" />
Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net10.0\windows\libpostal-1.dll" />
<LinuxNativeFiles
Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net8.0\linux_x86_64\libpostal-1.so" />
Include="$(MSBuildThisFileDirectory)\..\contentFiles\any\net10.0\linux_x86_64\libpostal-1.so" />
</ItemGroup>

<PropertyGroup>
<LibPostalAutoDownload Condition="'$(LibPostalAutoDownload)' == ''">true</LibPostalAutoDownload>
</PropertyGroup>

<Target Name="CleanLibPostal" AfterTargets="Clean">
<RemoveDir Directories="$(TargetDir)\Data\libpostal"></RemoveDir>
<Delete Files="$(TargetDir)\LibpostalData.zip" />
<Delete Files="$(TargetDir)\LibpostalData.zip"
Condition="'$(LibPostalAutoDownload)' == 'true'" />
<Delete Files="$(TargetDir)\libpostal-1.dll" Condition="'$(OS)' == 'Windows_NT'" />
<Delete Files="$(TargetDir)\libpostal-1.so"
Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'" />
Expand All @@ -22,7 +27,7 @@
<DownloadFile
SourceUrl="https://github.com/NHSISL/LibPostalClient/releases/download/LibPostalData/LibpostalData.zip"
DestinationFolder="$(TargetDir)"
Condition="!Exists('$(TargetDir)\LibpostalData.zip') == 'True'" />
Condition="'$(LibPostalAutoDownload)' == 'true' AND !Exists('$(TargetDir)\LibpostalData.zip') == 'True'" />

</Target>

Expand All @@ -44,10 +49,13 @@
<Message Importance="high" Text="Writing to folder $(PublishDir)" />
<DownloadFile
SourceUrl="https://github.com/NHSISL/LibPostalClient/releases/download/LibPostalData/LibpostalData.zip"
DestinationFolder="$(PublishDir)" />
DestinationFolder="$(PublishDir)"
Condition="'$(LibPostalAutoDownload)' == 'true' AND !Exists('$(PublishDir)\LibpostalData.zip') == 'True'" />
<Unzip SourceFiles="$(PublishDir)\LibpostalData.zip" DestinationFolder="$(PublishDir)\Data"
OverwriteReadOnlyFiles="true" />
<Delete Files="$(PublishDir)\LibpostalData.zip" />
OverwriteReadOnlyFiles="true"
Condition="Exists('$(PublishDir)\LibpostalData.zip') == 'True'" />
<Delete Files="$(PublishDir)\LibpostalData.zip"
Condition="'$(LibPostalAutoDownload)' == 'true'" />
<Copy SourceFiles="@(WindowsNativeFiles)" DestinationFolder="$(PublishDir)" />
<Copy SourceFiles="@(LinuxNativeFiles)" DestinationFolder="$(PublishDir)" />
</Target>
Expand Down
137 changes: 137 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,140 @@ Libpostal can break down an address into its constituent components, such as str

## Address Normalization:
It can normalize addresses to a consistent format, reducing variations and inconsistencies that may exist in address data.

# Getting Started

## Install

```
dotnet add package NHSISL.LibPostalClient
```

> **The first build downloads roughly 800MB of libpostal training data** and unzips it into
> your output directory. This is expected, and it only happens when the data is not already
> present. See [Controlling the data download](#controlling-the-data-download) below if you
> need to manage this yourself.

## Parse an address

`ParseAddressAsync` breaks an address into labelled components.

```csharp
using NHSISL.LibPostalClient.Clients;
using NHSISL.LibPostalClient.Models.Brokers.LibPostal;

var dataDirectory = Path.Combine(AppContext.BaseDirectory, "Data");

var config = new LibPostalConfiguration
{
DataDirectory = dataDirectory,
ParserDataDirectory = dataDirectory,
LanguageClassifierDataDirectory = dataDirectory,
PaserOptions = new ParserOptions
{
Country = "gb",
Language = "en",
}
};

var client = new LibPostalClient(config);

List<KeyValuePair<string, string>> parsed =
await client.ParseAddressAsync("12 High Street, Little Houghton, Northamptonshire, AB1 2CD");

foreach (var component in parsed)
{
Console.WriteLine($"{component.Key}: {component.Value}");
}
```

Output:

```
house_number: 12
road: high street
city: little houghton
state_district: northamptonshire
postcode: ab1 2cd
```

The component keys are libpostal's parser labels — the full list is in the
[libpostal documentation](https://github.com/openvenues/libpostal#parser-labels).

## Expand an address

`ExpandAddressAsync` returns normalised variations of an address, which is useful for
comparing or de-duplicating addresses that are written differently.

```csharp
string[] expansions = await client.ExpandAddressAsync("12 High St, Northants");

foreach (string expansion in expansions)
{
Console.WriteLine(expansion);
}
```

Output:

```
12 high saint northants
12 high street northants
```

## Configuration

| Property | Description |
| --- | --- |
| `DataDirectory` | Folder holding the libpostal data files. |
| `ParserDataDirectory` | Folder holding the parser model. Usually the same as `DataDirectory`. |
| `LanguageClassifierDataDirectory` | Folder holding the language classifier model. Usually the same as `DataDirectory`. |
| `PaserOptions.Country` | Two letter country hint, for example `gb`. |
| `PaserOptions.Language` | Two letter language hint, for example `en`. |

All three directories normally point at the `Data` folder that the package unzips into your
build output, as shown in the example above.

> `PaserOptions` is spelled that way in the public API. It is a known typo that is kept for
> backwards compatibility.

## Controlling the data download

By default the package downloads `LibpostalData.zip` when it is not already present in the
output directory, and removes it on `Clean` so the next build fetches it again.

If you manage the data yourself — for example in CI, or in an enterprise build where the
files are already on disk — set the following in your project file:

```xml
<PropertyGroup>
<LibPostalAutoDownload>false</LibPostalAutoDownload>
</PropertyGroup>
```

With this set to `false`:

- the download is skipped on both build and publish
- `Clean` no longer deletes `LibpostalData.zip`

You are then responsible for making the libpostal data available in the directories you
point `LibPostalConfiguration` at.

## Using the client from a test project

The package copies the native libpostal libraries into the output directory using MSBuild
targets that ship in the package. These targets only run for projects that reference the
package **directly**.

If your test project reaches the client only through a `ProjectReference` to another
project, the native libraries will not be copied into the test output and you will see:

```
System.DllNotFoundException : Unable to load DLL 'libpostal-1'
```

Add the package reference to the test project as well:

```xml
<PackageReference Include="NHSISL.LibPostalClient" Version="..." />
```
Loading