z3950

package module
v0.0.0-...-0d5e2bd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 8 Imported by: 0

README

go-z3950

A native Go client library for the Z39.50 information retrieval protocol.

Z39.50 is a client-server protocol for searching and retrieving information from remote databases, commonly used in library systems and bibliographic databases. This library provides a clean, idiomatic Go API without C bindings.

Installation

go get github.com/jamesrf/go-z3950

Quick Start

package main

import (
    "fmt"
    "log"

    z3950 "github.com/jamesrf/go-z3950"
)

func main() {
    client, err := z3950.Dial("z3950.loc.gov", 7090)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    if err := client.Init(nil); err != nil {
        log.Fatal(err)
    }

    query := z3950.NewRPNQuery().Title("golang programming")
    records, err := client.SearchAndRetrieve("voyager", query, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d records\n", records.Total)
    for _, rec := range records.Records {
        fmt.Println(rec.AsString())
    }
}

Configuration

Options are passed to Dial:

client, err := z3950.Dial("catalog.example.com", 210,
    z3950.WithConnectionTimeout(30*time.Second),
    z3950.WithReadTimeout(10*time.Second),
    z3950.WithWriteTimeout(10*time.Second),
    z3950.WithProtocolVersion(protocol.ProtocolVersion3),
    z3950.WithPreferredMessageSize(1048576),
    z3950.WithAuthentication("user", "pass"),
    z3950.WithAuthenticationGroup("user", "pass", "group"),
    z3950.WithImplementationInfo("id", "name", "version"),
)

Query Building

Build RPN queries with the fluent API:

// Simple search
query := z3950.NewRPNQuery().Title("computer science")

// Boolean query
query := z3950.NewRPNQuery().
    Title("programming").
    Author("knuth").
    And()

// Custom attributes
query := z3950.NewRPNQuery().
    Term("golang", z3950.UseAttribute(4), z3950.StructureAttribute(2))

Error Types

The library provides domain-specific error types: ConnectionError, ProtocolError, InitError, SearchError, and PresentError.

Testing

go test ./...

License

MIT

References

Documentation

Overview

Package z3950 provides a native Go client for the Z39.50 protocol (ANSI/NISO Z39.50-2003).

Z39.50 is a client-server protocol for searching and retrieving information from remote databases, commonly used in library systems and bibliographic databases.

Example usage:

client, err := z3950.Dial("z3950.loc.gov", 7090)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

if err := client.Init(nil); err != nil {
    log.Fatal(err)
}

query := z3950.NewRPNQuery().Title("golang programming")
records, err := client.SearchAndRetrieve("voyager", query, nil)
if err != nil {
    log.Fatal(err)
}
for _, rec := range records.Records {
    fmt.Println(rec.AsString())
}

Index

Constants

View Source
const (
	OptionSearch                 = 0
	OptionPresent                = 1
	OptionDeleteResultSet        = 2
	OptionResourceReport         = 3
	OptionTriggerResourceControl = 4
	OptionResourceControl        = 5
	OptionAccessControl          = 6
	OptionScan                   = 7
	OptionSort                   = 8
	OptionExtendedServices       = 10
	OptionLevel1Segmentation     = 11
	OptionLevel2Segmentation     = 12
	OptionConcurrentOperations   = 13
	OptionNamedResultSets        = 14
)

Z39.50 capability option constants.

These are used with Client.HasOption and WithRequestedOptions to check or request specific server capabilities.

Variables

This section is empty.

Functions

func GetDiagnosticMessage

func GetDiagnosticMessage(code int) string

GetDiagnosticMessage returns a human-readable message for a diagnostic code

Types

type APDUType

type APDUType uint8

APDUType represents the type of Z39.50 APDU (Application Protocol Data Unit).

const (
	APDUTypeInitRequest      APDUType = 20
	APDUTypeInitResponse     APDUType = 21
	APDUTypeSearchRequest    APDUType = 22
	APDUTypeSearchResponse   APDUType = 23
	APDUTypePresentRequest   APDUType = 24
	APDUTypePresentResponse  APDUType = 25
	APDUTypeDeleteRequest    APDUType = 26
	APDUTypeDeleteResponse   APDUType = 27
	APDUTypeAccessControl    APDUType = 28
	APDUTypeResourceControl  APDUType = 29
	APDUTypeTriggerResource  APDUType = 30
	APDUTypeResourceReport   APDUType = 31
	APDUTypeScanRequest      APDUType = 35
	APDUTypeScanResponse     APDUType = 36
	APDUTypeSortRequest      APDUType = 43
	APDUTypeSortResponse     APDUType = 44
	APDUTypeSegment          APDUType = 45
	APDUTypeExtendedServices APDUType = 46
	APDUTypeClose            APDUType = 48
)

func (APDUType) String

func (t APDUType) String() string

String returns the string representation of an APDU type.

type Attribute

type Attribute struct {
	Type  int
	Value int
}

Attribute represents a search attribute (type + value pair) for the public API.

Common attribute types:

1 = Use        (what field to search: 4=title, 1003=author, 21=subject, 7=ISBN, etc.)
2 = Relation   (3=equal, 102=relevance, etc.)
3 = Position   (3=any position, 1=first in field)
4 = Structure  (1=phrase, 2=word, 6=word list)
5 = Truncation (1=right, 100=do not truncate)
6 = Completeness (1=incomplete, 2=complete)

func Attr

func Attr(attrType, attrValue int) Attribute

Attr creates an Attribute from a type=value pair, mirroring the @attr syntax.

Example:

z3950.Attr(1, 4)   // Use=Title     (equivalent to @attr 1=4)
z3950.Attr(2, 3)   // Relation=Equal
z3950.Attr(4, 1)   // Structure=Phrase

func Attrs

func Attrs(pairs ...int) []Attribute

Attrs is a convenience for building a slice of attributes from type/value pairs.

Arguments are pairs: type1, value1, type2, value2, ... It panics if an odd number of arguments is provided, since that indicates a programming error (mismatched pairs).

Example:

// @attr 1=4 @attr 4=1 "golang"
q := z3950.NewRPNQuery().Term("golang", z3950.Attrs(1, 4, 4, 1)...)

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents a Z39.50 client.

A Client is not safe for concurrent use. Callers must synchronize access if sharing a Client across goroutines.

func Dial

func Dial(host string, port int, opts ...Option) (*Client, error)

Dial establishes a connection to a Z39.50 server

The host and port specify the server address. Optional configuration can be provided through Option functions.

Example:

client, err := z3950.Dial("z3950.loc.gov", 7090)
if err != nil {
    return err
}
defer client.Close()

func (*Client) Close

func (c *Client) Close() error

Close closes the Z39.50 session and connection

This sends a Close APDU to the server and closes the TCP connection. It's safe to call Close() multiple times.

Example:

defer client.Close()

func (*Client) GetServerInfo

func (c *Client) GetServerInfo() *ServerInfo

GetServerInfo returns information about the connected server

This information is populated during the Init handshake and includes the server's implementation ID, name, and version.

func (*Client) HasOption

func (c *Client) HasOption(option int) bool

HasOption checks if the server supports a specific option/capability.

Common options include:

  • OptionSearch
  • OptionPresent
  • OptionScan
  • OptionSort
  • OptionNamedResultSets

func (*Client) Init

func (c *Client) Init(opts *InitOptions) error

Init initializes the Z39.50 session with the server

This must be called after Dial() and before any other operations. The Init handshake negotiates protocol version, capabilities, and authentication.

Example:

if err := client.Init(nil); err != nil {
    return err
}

func (*Client) IsInitialized

func (c *Client) IsInitialized() bool

IsInitialized returns true if the session has been successfully initialized

func (*Client) Present

func (c *Client) Present(resultSet string, start, count int, opts *PresentOptions) (*RecordSet, error)

Present retrieves records from a result set.

The resultSet parameter is the name returned by Search (defaults to "default"). start is 1-based, count is the number of records to retrieve.

Example:

records, err := client.Present("default", 1, 10, nil)

func (*Client) Search

func (c *Client) Search(dbName string, query Query, opts *SearchOptions) (*SearchResult, error)

Search executes a search query on the specified database.

The query parameter must implement the Query interface. Use NewRPNQuery() to build queries with the fluent API.

Example:

query := z3950.NewRPNQuery().Title("golang programming")
result, err := client.Search("voyager", query, nil)
fmt.Printf("Found %d records\n", result.Count)

func (*Client) SearchAndRetrieve

func (c *Client) SearchAndRetrieve(dbName string, query Query, opts *RetrieveOptions) (*RecordSet, error)

SearchAndRetrieve is a convenience method that searches and retrieves records in a single call.

Example:

query := z3950.NewRPNQuery().Title("golang programming")
records, err := client.SearchAndRetrieve("voyager", query, nil)
for _, record := range records.Records {
    fmt.Println(record.AsString())
}

type ConnectionError

type ConnectionError struct {
	Message string
	Err     error
}

ConnectionError represents a network connection error

func NewConnectionError

func NewConnectionError(message string, err error) *ConnectionError

NewConnectionError creates a new connection error

func (*ConnectionError) Error

func (e *ConnectionError) Error() string

func (*ConnectionError) Unwrap

func (e *ConnectionError) Unwrap() error

type Diagnostic

type Diagnostic struct {
	// DiagnosticSetID is the OID of the diagnostic set (e.g., "1.2.840.10003.4.1" for Bib-1)
	DiagnosticSetID string
	Code            int
	Message         string
	AdditionalInfo  string
}

Diagnostic represents a Z39.50 diagnostic message

Per the Z39.50 standard:

DefaultDiagFormat ::= SEQUENCE {
    diagnosticSetId  OBJECT IDENTIFIER,
    condition        INTEGER,
    addinfo          CHOICE { v2Addinfo VisibleString, v3Addinfo InternationalString }
}

func NewDiagnostic

func NewDiagnostic(code int, additionalInfo string) *Diagnostic

NewDiagnostic creates a new diagnostic

func (*Diagnostic) String

func (d *Diagnostic) String() string

String returns a string representation of the diagnostic

type InitError

type InitError struct {
	Message            string
	ServerMessage      string
	ImplementationID   string
	ImplementationName string
}

InitError represents an error during the Init handshake

func NewInitError

func NewInitError(message string) *InitError

NewInitError creates a new init error

func (*InitError) Error

func (e *InitError) Error() string

type InitOptions

type InitOptions struct {
	// Reference ID for the request
	ReferenceID []byte

	// Override default options
	Options *Options
}

InitOptions represents options specific to the Init operation

type Option

type Option func(*Options)

Option is a function that modifies Options

func WithAuthentication

func WithAuthentication(username, password string) Option

WithAuthentication sets authentication credentials

func WithAuthenticationGroup

func WithAuthenticationGroup(username, password, group string) Option

WithAuthenticationGroup sets authentication credentials with a group name

func WithConnectionTimeout

func WithConnectionTimeout(timeout time.Duration) Option

WithConnectionTimeout sets the connection timeout

func WithExceptionalRecordSize

func WithExceptionalRecordSize(size int) Option

WithExceptionalRecordSize sets the exceptional record size

func WithImplementationInfo

func WithImplementationInfo(id, name, version string) Option

WithImplementationInfo sets the implementation ID, name, and version

func WithPreferredMessageSize

func WithPreferredMessageSize(size int) Option

WithPreferredMessageSize sets the preferred message size

func WithPreferredRecordSyntax

func WithPreferredRecordSyntax(syntax RecordSyntax) Option

WithPreferredRecordSyntax sets the preferred record syntax

func WithProtocolVersion

func WithProtocolVersion(version ProtocolVersion) Option

WithProtocolVersion sets the protocol version

func WithReadTimeout

func WithReadTimeout(timeout time.Duration) Option

WithReadTimeout sets the read timeout

func WithRequestedOptions

func WithRequestedOptions(options []int) Option

WithRequestedOptions sets the requested options/capabilities

func WithWriteTimeout

func WithWriteTimeout(timeout time.Duration) Option

WithWriteTimeout sets the write timeout

type Options

type Options struct {
	// Connection timeout
	ConnectionTimeout time.Duration

	// Read timeout for receiving responses
	ReadTimeout time.Duration

	// Write timeout for sending requests
	WriteTimeout time.Duration

	// Protocol version to use (1, 2, or 3)
	ProtocolVersion ProtocolVersion

	// Preferred message size in bytes
	PreferredMessageSize int

	// Exceptional record size in bytes
	ExceptionalRecordSize int

	// Implementation ID to send to server
	ImplementationID string

	// Implementation name to send to server
	ImplementationName string

	// Implementation version to send to server
	ImplementationVersion string

	// Username for authentication (if required)
	Username string

	// Password for authentication (if required)
	Password string

	// Group name for authentication (if required)
	GroupName string

	// Options/capabilities to request (bit positions)
	RequestedOptions []int

	// Preferred record syntax (MARC21, XML, etc.)
	PreferredRecordSyntax RecordSyntax
}

Options represents configuration options for a Z39.50 client

func DefaultOptions

func DefaultOptions() *Options

DefaultOptions returns default options for a Z39.50 client

type PresentError

type PresentError struct {
	Message    string
	ResultSet  string
	Diagnostic *Diagnostic
}

PresentError represents an error during a present (record retrieval) operation

func NewPresentError

func NewPresentError(resultSet, message string) *PresentError

NewPresentError creates a new present error

func (*PresentError) Error

func (e *PresentError) Error() string

type PresentOptions

type PresentOptions struct {
	// Reference ID for the request
	ReferenceID []byte

	// Preferred record syntax
	RecordSyntax RecordSyntax

	// Element set name (brief, full, etc.)
	ElementSetName string
}

PresentOptions represents options specific to the Present operation

type ProtocolError

type ProtocolError struct {
	Message string
	APDU    APDUType
}

ProtocolError represents a Z39.50 protocol violation or error

func NewProtocolError

func NewProtocolError(message string) *ProtocolError

NewProtocolError creates a new protocol error

func NewProtocolErrorWithAPDU

func NewProtocolErrorWithAPDU(apduType APDUType, message string) *ProtocolError

NewProtocolErrorWithAPDU creates a new protocol error with APDU type

func (*ProtocolError) Error

func (e *ProtocolError) Error() string

type ProtocolVersion

type ProtocolVersion int

ProtocolVersion represents a Z39.50 protocol version.

Z39.50 defines three protocol versions; version 3 (Z39.50-2003) is the most recent and is used by default.

const (
	// ProtocolVersion1 is Z39.50 version 1 (1988).
	ProtocolVersion1 ProtocolVersion = 0
	// ProtocolVersion2 is Z39.50 version 2 (1992).
	ProtocolVersion2 ProtocolVersion = 1
	// ProtocolVersion3 is Z39.50 version 3 (2003), the current standard.
	ProtocolVersion3 ProtocolVersion = 2
)

type Query

type Query interface {
	// contains filtered or unexported methods
}

Query is the interface for all query types

type RPNBuilder

type RPNBuilder struct {
	// contains filtered or unexported fields
}

RPNBuilder provides a fluent API for building RPN (Type-1) queries.

Queries are built in reverse Polish notation. Add terms first, then combine them with boolean operators.

Example:

// Search for title "golang" AND author "donovan"
q := z3950.NewRPNQuery().
    Title("golang").
    Author("donovan").
    And()

// Search for title "golang" OR title "go programming"
q := z3950.NewRPNQuery().
    Title("golang").
    Title("go programming").
    Or()

func NewRPNQuery

func NewRPNQuery() *RPNBuilder

NewRPNQuery creates a new RPN query builder

func PQF

func PQF(pqf string) (*RPNBuilder, error)

PQF parses a PQF (Prefix Query Format) string into an RPNBuilder. This supports the same @attr syntax used by yaz-client.

Supported syntax:

@attr 1=4 "golang"                          // single term
@attr 1=4 @attr 4=1 "golang"               // multiple attrs on one term
@and @attr 1=4 "golang" @attr 1=1003 "pike" // boolean AND
@or @attr 1=4 "go" @attr 1=4 "golang"      // boolean OR
@not @attr 1=4 "go" @attr 1=21 "fiction"    // AND-NOT

Example:

q, err := z3950.PQF(`@attr 1=4 "golang programming"`)
records, err := client.SearchAndRetrieve("voyager", q, nil)

func (*RPNBuilder) And

func (b *RPNBuilder) And() *RPNBuilder

And combines the top two terms on the stack with AND

func (*RPNBuilder) AndNot

func (b *RPNBuilder) AndNot() *RPNBuilder

AndNot combines the top two terms on the stack with AND-NOT

func (*RPNBuilder) Author

func (b *RPNBuilder) Author(value string) *RPNBuilder

Author adds an author search term

func (*RPNBuilder) ISBN

func (b *RPNBuilder) ISBN(value string) *RPNBuilder

ISBN adds an ISBN search term

func (*RPNBuilder) ISSN

func (b *RPNBuilder) ISSN(value string) *RPNBuilder

ISSN adds an ISSN search term

func (*RPNBuilder) Keyword

func (b *RPNBuilder) Keyword(value string) *RPNBuilder

Keyword adds a keyword (any field) search term

func (*RPNBuilder) Or

func (b *RPNBuilder) Or() *RPNBuilder

Or combines the top two terms on the stack with OR

func (*RPNBuilder) Subject

func (b *RPNBuilder) Subject(value string) *RPNBuilder

Subject adds a subject search term

func (*RPNBuilder) Term

func (b *RPNBuilder) Term(value string, attrs ...Attribute) *RPNBuilder

Term adds a search term with custom attributes to the query stack

func (*RPNBuilder) Title

func (b *RPNBuilder) Title(value string) *RPNBuilder

Title adds a title search term

type Record

type Record struct {
	// Syntax is the record syntax OID (e.g., MARC21, XML, SUTRS)
	Syntax RecordSyntax
	// Data contains the raw record data
	Data []byte
	// DatabaseName is the database this record came from
	DatabaseName string
}

Record represents a single record retrieved from a Z39.50 server

func (*Record) AsMARC

func (r *Record) AsMARC() []byte

AsMARC returns the raw record data as a MARC byte slice. Returns nil if the record is not in MARC format.

func (*Record) AsString

func (r *Record) AsString() string

AsString returns the record data as a string, regardless of format. For MARC records, this provides a basic readable representation.

func (*Record) AsXML

func (r *Record) AsXML() string

AsXML returns the record data as an XML string. Returns empty string if the record is not in XML format.

func (*Record) String

func (r *Record) String() string

String returns a brief description of the record

type RecordSet

type RecordSet struct {
	// Records contains the retrieved records
	Records []*Record
	// Total is the total number of records matching the search
	Total int
	// NextPosition is the position of the next record to retrieve (1-based)
	NextPosition int
}

RecordSet represents a collection of records retrieved from a server

func (*RecordSet) Count

func (rs *RecordSet) Count() int

Count returns the number of records in this set

type RecordSyntax

type RecordSyntax string

RecordSyntax represents a Z39.50 record syntax OID.

Record syntaxes identify the format of retrieved records. The most commonly used syntax is MARC21 for bibliographic records.

const (
	// RecordSyntaxUSMARC is the USMARC record syntax OID (same as MARC21).
	RecordSyntaxUSMARC RecordSyntax = "1.2.840.10003.5.10"
	// RecordSyntaxMARC21 is the MARC21 record syntax OID.
	RecordSyntaxMARC21 RecordSyntax = "1.2.840.10003.5.10"
	// RecordSyntaxXML is the XML record syntax OID.
	RecordSyntaxXML RecordSyntax = "1.2.840.10003.5.109.10"
	// RecordSyntaxSUTRS is the SUTRS (Simple Unstructured Text Record Syntax) OID.
	RecordSyntaxSUTRS RecordSyntax = "1.2.840.10003.5.101"
	// RecordSyntaxOPAC is the OPAC record syntax OID.
	RecordSyntaxOPAC RecordSyntax = "1.2.840.10003.5.102"
	// RecordSyntaxGRS1 is the GRS-1 (Generic Record Syntax 1) OID.
	RecordSyntaxGRS1 RecordSyntax = "1.2.840.10003.5.105"
)

type RetrieveOptions

type RetrieveOptions struct {
	// Search options
	SearchOptions *SearchOptions

	// Maximum number of records to retrieve
	MaxRecords int

	// Starting position (1-based)
	StartPosition int

	// Present options
	PresentOptions *PresentOptions
}

RetrieveOptions represents options for the SearchAndRetrieve convenience method

func DefaultRetrieveOptions

func DefaultRetrieveOptions() *RetrieveOptions

DefaultRetrieveOptions returns default retrieve options

type SearchError

type SearchError struct {
	Message      string
	DatabaseName string
	Diagnostic   *Diagnostic
}

SearchError represents an error during a search operation

func NewSearchError

func NewSearchError(database, message string) *SearchError

NewSearchError creates a new search error

func (*SearchError) Error

func (e *SearchError) Error() string

type SearchOptions

type SearchOptions struct {
	// Reference ID for the request
	ReferenceID []byte

	// Small set upper bound
	SmallSetUpperBound int

	// Large set lower bound
	LargeSetLowerBound int

	// Medium set present number
	MediumSetPresentNumber int

	// Replace indicator (replace existing result set with same name)
	ReplaceIndicator bool

	// Result set name (defaults to "default")
	ResultSetName string

	// Preferred record syntax
	RecordSyntax RecordSyntax

	// Element set name
	ElementSetName string
}

SearchOptions represents options specific to the Search operation

func DefaultSearchOptions

func DefaultSearchOptions() *SearchOptions

DefaultSearchOptions returns default search options

type SearchResult

type SearchResult struct {
	// ResultSetName is the name of the result set created by the search
	ResultSetName string
	// Count is the total number of records matching the search
	Count int
	// Status indicates whether the search succeeded
	Status SearchStatus
	// Records contains any "piggyback" records returned inline with the search response.
	// Z39.50 servers may return records directly in the search response when the
	// result count falls within the small/medium set bounds.
	Records []*Record
	// Diagnostics contains any diagnostic messages from the server
	Diagnostics []*Diagnostic
}

SearchResult represents the result of a search operation

func (*SearchResult) String

func (sr *SearchResult) String() string

String returns a brief description of the search result

type SearchStatus

type SearchStatus int

SearchStatus represents the status of a search operation

const (
	// SearchStatusSuccess indicates the search completed successfully
	SearchStatusSuccess SearchStatus = 1
	// SearchStatusFailure indicates the search failed
	SearchStatusFailure SearchStatus = 0
)

func (SearchStatus) String

func (s SearchStatus) String() string

String returns the string representation of a search status

type ServerInfo

type ServerInfo struct {
	ImplementationID      string
	ImplementationName    string
	ImplementationVersion string
	ProtocolVersion       ProtocolVersion
	SupportedOptions      []int
}

ServerInfo contains information about the Z39.50 server

func (*ServerInfo) String

func (si *ServerInfo) String() string

String returns a string representation of the server info

Directories

Path Synopsis
search command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL