{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} -------------------------------------------------------------------------------- -- See end of this file for licence information. -------------------------------------------------------------------------------- -- | -- Module : Namespace -- Copyright : (c) 2003, Graham Klyne, 2009 Vasili I Galchin, -- 2011, 2012, 2014 Douglas Burke -- License : GPL V2 -- -- Maintainer : Douglas Burke -- Stability : experimental -- Portability : CPP, OverloadedStrings -- -- This module defines algebraic datatypes for namespaces and scoped names. -- -- For these purposes, a namespace is a prefix and URI used to identify -- a namespace (cf. XML namespaces), and a scoped name is a name that -- is scoped by a specified namespace. -- -------------------------------------------------------------------------------- module Swish.Namespace ( Namespace , makeNamespace, makeNamespaceQName , getNamespacePrefix, getNamespaceURI, getNamespaceTuple -- , nullNamespace , ScopedName , getScopeNamespace, getScopeLocal , getScopePrefix, getScopeURI , getQName, getScopedNameURI , matchName , makeScopedName , makeQNameScopedName , makeURIScopedName , makeNSScopedName , nullScopedName , namespaceToBuilder ) where import Swish.QName (QName, LName, newQName, getLName, emptyLName, getQNameURI, getNamespace, getLocalName) import Data.Maybe (fromMaybe) #if (!defined(__GLASGOW_HASKELL__)) || (__GLASGOW_HASKELL__ < 710) import Data.Monoid (Monoid(..)) #endif import Data.Ord (comparing) import Data.String (IsString(..)) import Network.URI (URI(..), parseURIReference, nullURI) import qualified Data.Text as T import qualified Data.Text.Lazy.Builder as B ------------------------------------------------------------ -- Namespace, having a prefix and a URI ------------------------------------------------------------ -- |A NameSpace value consists of an optional prefix and a corresponding URI. -- data Namespace = Namespace (Maybe T.Text) URI -- data Namespace = Namespace (Maybe T.Text) !URI -- TODO: look at interning the URI -- | Returns the prefix stored in the name space. getNamespacePrefix :: Namespace -> Maybe T.Text getNamespacePrefix (Namespace p _) = p -- | Returns the URI stored in the name space. getNamespaceURI :: Namespace -> URI getNamespaceURI (Namespace _ u) = u -- | Convert the name space to a (prefix, URI) tuple. getNamespaceTuple :: Namespace -> (Maybe T.Text, URI) getNamespaceTuple (Namespace p u) = (p, u) -- | Equality is defined by the URI, not by the prefix -- (so the same URI with different prefixes will be -- considered to be equal). instance Eq Namespace where (Namespace _ u1) == (Namespace _ u2) = u1 == u2 instance Ord Namespace where -- using show for the URI is wasteful (Namespace a1 b1) `compare` (Namespace a2 b2) = (a1, show b1) `compare` (a2, show b2) instance Show Namespace where show (Namespace (Just p) u) = show p ++ ":<" ++ show u ++ ">" show (Namespace _ u) = "<" ++ show u ++ ">" -- | Create a name space from a URI and an optional prefix label. makeNamespace :: Maybe T.Text -- ^ optional prefix. -> URI -- ^ URI. -> Namespace makeNamespace = Namespace -- | Create a qualified name by combining the URI from -- the name space with a local component. makeNamespaceQName :: Namespace -- ^ The name space URI is used in the qualified name -> LName -- ^ local component of the qualified name (can be 'emptyLName') -> QName makeNamespaceQName (Namespace _ uri) = newQName uri {- nullNamespace :: Namespace nullNamespace = Namespace Nothing "" -} -- | Utility routine to create a \@prefix line (matching N3/Turtle) -- grammar for this namespace. -- namespaceToBuilder :: Namespace -> B.Builder namespaceToBuilder (Namespace pre uri) = mconcat $ map B.fromText [ "@prefix ", fromMaybe "" pre, ": <", T.pack (show uri), "> .\n"] ------------------------------------------------------------ -- ScopedName, made from a namespace and a local name ------------------------------------------------------------ -- | A full ScopedName value has a QName prefix, namespace URI -- and a local part. ScopedName values may omit the prefix -- (see 'Namespace') or the local part. -- -- Some applications may handle null namespace URIs as meaning -- the local part is relative to some base URI. -- data ScopedName = ScopedName !QName Namespace LName -- | Returns the local part. getScopeLocal :: ScopedName -> LName getScopeLocal (ScopedName _ _ l) = l -- | Returns the namespace. getScopeNamespace :: ScopedName -> Namespace getScopeNamespace (ScopedName _ ns _) = ns -- | Returns the prefix of the namespace, if set. getScopePrefix :: ScopedName -> Maybe T.Text getScopePrefix = getNamespacePrefix . getScopeNamespace -- | Returns the URI of the namespace. getScopeURI :: ScopedName -> URI getScopeURI = getNamespaceURI . getScopeNamespace -- | This is not total since it will fail if the input string is not a valid 'URI'. instance IsString ScopedName where fromString s = maybe (error ("Unable to convert " ++ s ++ " into a ScopedName")) makeURIScopedName (parseURIReference s) -- | Scoped names are equal if their corresponding 'QName' values are equal. instance Eq ScopedName where sn1 == sn2 = getQName sn1 == getQName sn2 -- | Scoped names are ordered by their 'QName' components. instance Ord ScopedName where compare = comparing getQName -- | If there is a namespace associated then the Show instance -- uses @prefix:local@, otherwise @<url>@. instance Show ScopedName where show (ScopedName qn n l) = case getNamespacePrefix n of Just pre -> T.unpack $ mconcat [pre, ":", getLName l] _ -> show qn -- "<" ++ show (getNamespaceURI n) ++ T.unpack l ++ ">" -- |Get the QName corresponding to a scoped name. getQName :: ScopedName -> QName getQName (ScopedName qn _ _) = qn -- |Get URI corresponding to a scoped name (using RDF conventions). getScopedNameURI :: ScopedName -> URI getScopedNameURI = getQNameURI . getQName -- |Test if supplied string matches the display form of a -- scoped name. matchName :: String -> ScopedName -> Bool matchName str nam = str == show nam -- |Construct a ScopedName. makeScopedName :: Maybe T.Text -- ^ prefix for the namespace -> URI -- ^ namespace -> LName -- ^ local name -> ScopedName makeScopedName pre nsuri local = ScopedName (newQName nsuri local) (Namespace pre nsuri) local -- |Construct a ScopedName from a QName. makeQNameScopedName :: Maybe T.Text -- ^ prefix -> QName -> ScopedName makeQNameScopedName pre qn = ScopedName qn (Namespace pre (getNamespace qn)) (getLocalName qn) -- could use qnameFromURI to find a local name if there is one. -- | Construct a ScopedName for a bare URI (the label is set to \"\"). makeURIScopedName :: URI -> ScopedName makeURIScopedName uri = makeScopedName Nothing uri emptyLName -- | Construct a ScopedName. makeNSScopedName :: Namespace -- ^ namespace -> LName -- ^ local component -> ScopedName makeNSScopedName ns local = ScopedName (newQName (getNamespaceURI ns) local) ns local -- | This should never appear as a valid name nullScopedName :: ScopedName nullScopedName = makeURIScopedName nullURI -------------------------------------------------------------------------------- -- -- Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin, -- 2011, 2012 Douglas Burke -- All rights reserved. -- -- This file is part of Swish. -- -- Swish is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- Swish is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Swish; if not, write to: -- The Free Software Foundation, Inc., -- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- --------------------------------------------------------------------------------