--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
--- /dev/null
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = src include etc doc
+
+EXTRA_DIST= README LICENSE yazpp.m4 buildconf.sh
+
+dist-hook:
+ mkdir $(distdir)/win
+ cp $(srcdir)/win/makefile $(distdir)/win/
+ mkdir $(distdir)/debian
+ cp $(srcdir)/debian/control $(distdir)/debian
+ cp $(srcdir)/debian/changelog $(distdir)/debian
+ cp $(srcdir)/debian/rules $(distdir)/debian
+ cp $(srcdir)/debian/postinst $(distdir)/debian
+ cp $(srcdir)/debian/compat $(distdir)/debian
+ cp $(srcdir)/debian/*.install $(distdir)/debian
--- /dev/null
+YAZ proxy - A Z39.50/SRW/SRU proxy.
+
+$Id: README,v 1.1 2004-04-11 11:36:46 adam Exp $
+
+Introduction
+------------
+
+The proxy application and development library is covered by the
+GPL - see LICENSE.proxy for details.
+
+Documentation
+-------------
+
+The "doc" directory contains documentation in HTML and PDF.
+You can also read it online at http://www.indexdata.dk/yazproxy/
+
+Overview
+--------
+
+YAZ proxy builds a programmers' library libyazproxy.lib and the
+proxy application.
+
+Directory structure of the YAZ++ package:
+
+ -- src (C++ library)
+ -- include/yazproxy (C++ headers for proxy)
+ -- lib (compiled libraries)
+ -- win (Windows build files)
+ -- doc (DocBook-format documentation)
+ -- etc (Proxy config + XSLT files)
+
+About the proxy
+---------------
+
+For the proxy the actual target is determined in by the OtherInfo
+part of the InitRequest. We've defined an OID for this which we call
+PROXY. The OID is 1.2.840.10003.10.1000.81.1.
+
+ OtherInformation ::= [201] IMPLICIT SEQUENCE OF SEQUENCE{
+ category [1] IMPLICIT InfoCategory OPTIONAL,
+ information CHOICE{
+ characterInfo [2] IMPLICIT InternationalString,
+ binaryInfo [3] IMPLICIT OCTET STRING,
+ externallyDefinedInfo [4] IMPLICIT EXTERNAL,
+ oid [5] IMPLICIT OBJECT IDENTIFIER}}
+--
+ InfoCategory ::= SEQUENCE{
+ categoryTypeId [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+ categoryValue [2] IMPLICIT INTEGER}
+
+The InfoCategory is present with categoryTypeId set to the PROXY OID
+and categoryValue set to 0. The information in OtherInformation uses
+characterInfo to represent the target using the form target[:port][/db].
+
+For clients that don't set the PROXY OtherInformation, a default
+target can be specified using option -t for proxy.
+
+Example:
+ We start the proxy so that it listens on port 9000. The default
+ target is Bell Labs Library unless it is overridden by a client in
+ the InitRequest.
+
+ $ ./yaz-proxy -t z3950.bell-labs.com/books @:9000
+
+ The client is started and talks to the proxy without specifying
+ a target. Hence this client will talk to the Bell Labs server.
+
+ $ ./yaz-client localhost:9000
+
+ The client is started and it specifies the actual target itself.
+
+ $ ./yaz-client -p localhost:9000 bagel.indexdata.dk/gils
+
+ For ZAP the equivalent would be
+ proxy=localhost:9000
+ target=bagel.indexdata.dk/gils
+ Simple, huh!
+
--- /dev/null
+#!/bin/sh
+# $Id: buildconf.sh,v 1.1 2004-04-11 11:36:46 adam Exp $
+set -x
+dir=`aclocal --print-ac-dir`
+if [ -f $dir/yaz.m4 ]; then
+ aclocal
+else
+ aclocal -I .
+fi
+libtoolize --force
+automake -a
+automake -a
+autoconf
+if [ -f config.cache ]; then
+ rm config.cache
+fi
--- /dev/null
+AC_INIT(configure.in)
+AM_INIT_AUTOMAKE("yazproxy",0.8)
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_HEADER_STDC
+AM_DISABLE_SHARED
+AM_PROG_LIBTOOL
+
+YAZPP_INIT(threads,0.8)
+
+AC_CHECK_FUNCS(setrlimit getrlimit gettimeofday)
+dnl
+dnl ----- libXSLT
+AC_SUBST(XSLT_LIBS)
+AC_SUBST(XSLT_CFLAGS)
+xsltdir=yes
+AC_ARG_WITH(xslt, [ --with-xslt[=PREFIX] use libxslt in PREFIX],[xsltdir=$withval])
+if test "$xsltdir" = "yes"; then
+ for d in /usr /usr/local; do
+ if test -x $d/bin/xslt-config; then
+ xsltdir=$d
+ fi
+ done
+fi
+if test "$xsltdir" != "no"; then
+ AC_MSG_CHECKING(for libXSLT)
+ if test -x $xsltdir/bin/xslt-config; then
+ XSLT_LIBS=`$xsltdir/bin/xslt-config --libs`
+ XSLT_CFLAGS=`$xsltdir/bin/xslt-config --cflags`
+ XSLT_VER=`$xsltdir/bin/xslt-config --version`
+ AC_MSG_RESULT($XSLT_VER)
+ AC_DEFINE(HAVE_XSLT)
+ else
+ AC_MSG_RESULT(Not found)
+ fi
+fi
+
+dnl
+dnl ----- DOCBOOK DTD
+AC_SUBST(DTD_DIR)
+AC_ARG_WITH(dtd, [ --with-dtd[=DIR] use docbookx.dtd in DIR],
+[
+ if test -f "$withval/docbookx.dtd"; then
+ DTD_DIR=$withval
+ fi
+],[
+ AC_MSG_CHECKING(for docbookx.dtd)
+ for d in /usr/share/sgml/docbook/dtd/xml/4.1.2 \
+ /usr/share/sgml/docbook/xml-dtd-4.1.2* \
+ /usr/share/sgml/docbook/xml-dtd-4.1 \
+ /usr/share/sgml/docbook/dtd/xml/4.0 \
+ /usr/lib/sgml/dtd/docbook-xml
+ do
+ if test -f $d/docbookx.dtd; then
+ AC_MSG_RESULT($d)
+ DTD_DIR=$d
+ break
+ fi
+ done
+ if test -z "$DTD_DIR"; then
+ AC_MSG_RESULT(Not found)
+ fi
+])
+AC_SUBST(DSSSL_DIR)
+AC_ARG_WITH(dsssl,[ --with-dsssl[=DIR] use DSSSL in DIR/{html,print}/docbook.dsl],
+[
+ if test -f "$withval/html/docbook.dsl"; then
+ DSSSL_DIR=$withval
+ fi
+],[
+ AC_MSG_CHECKING(for docbook.dsl)
+ for d in /usr/share/sgml/docbook/stylesheet/dsssl/modular \
+ /usr/share/sgml/docbook/dsssl-stylesheets-1.* \
+ /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh
+ do
+ if test -f $d/html/docbook.dsl; then
+ AC_MSG_RESULT($d)
+ DSSSL_DIR=$d
+ break
+ fi
+ done
+ if test -z "$DSSSL_DIR"; then
+ AC_MSG_RESULT(Not found)
+ fi
+])
+dnl
+
+AC_SUBST(YAZPROXY_SRC_ROOT)
+AC_SUBST(YAZPROXY_BUILD_ROOT)
+YAZPROXY_SRC_ROOT=`cd ${srcdir}; pwd`
+YAZPROXY_BUILD_ROOT=`pwd`
+
+AC_OUTPUT([
+ Makefile
+ src/Makefile
+ include/Makefile
+ include/yazproxy/Makefile
+ doc/Makefile
+ doc/yazproxy.xml
+ doc/yazprint.dsl doc/yazphp.dsl doc/yazhtml.dsl
+ doc/tkl.xsl
+ etc/Makefile
+])
--- /dev/null
+## $Id: Makefile.am,v 1.1 2004-04-11 11:36:53 adam Exp $
+docdir=$(datadir)/doc/@PACKAGE@
+
+SUPPORTFILES = \
+ yazhtml.dsl.in \
+ yazphp.dsl.in \
+ yazprint.dsl.in \
+ tkl.xsl.in \
+ xml.dcl
+XMLFILES = \
+ introduction.xml \
+ installation.xml \
+ zoom.xml \
+ proxy.xml \
+ api.xml \
+ yaz-proxy-ref.xml \
+ yaz-proxy-man.sgml \
+ license.xml \
+ yaz++.xml.in
+
+TOP=yaz++.xml
+MANFILES=yaz-proxy.8
+HTMLFILES = \
+ api.html \
+ implementations.html \
+ installation.html \
+ introduction.html \
+ license.html \
+ other-optimizations.html \
+ otherinfo-encoding.html \
+ proxy-config-file.html \
+ proxy-keepalive.html \
+ proxy-target.html \
+ proxy-usage.html \
+ proxy.html \
+ query-cache.html \
+ query-validation.html \
+ record-cache.html \
+ record-validation.html \
+ windows.html \
+ yaz-proxy.html \
+ yaz.license.html \
+ yazpp.html \
+ zoom-connection.html \
+ zoom-exception.html \
+ zoom-query.html \
+ zoom-record.html \
+ zoom-resultset.html \
+ zoom.html
+
+doc_DATA = $(HTMLFILES) yaz++.pdf id.png yaz.css
+
+man_MANS = $(MANFILES)
+
+EXTRA_DIST = $(SUPPORTFILES) $(XMLFILES) $(doc_DATA) $(man_MANS)
+
+$(HTMLFILES): $(XMLFILES)
+ jade -E14 -D $(srcdir) -d yazhtml.dsl -t sgml $(srcdir)/xml.dcl $(TOP)
+
+yaz-proxy.8: yaz-proxy-man.sgml yaz-proxy-ref.xml
+ docbook2man $(srcdir)/yaz-proxy-man.sgml
+
+yazpp.php: $(XMLFILES)
+ jade -E14 -D $(srcdir) -d yazphp.dsl -t sgml $(srcdir)/xml.dcl $(TOP)
+
+yaz++.pdf: $(XMLFILES)
+ if test ! -f id.png ; then ln -s $(srcdir)/id.png .; fi
+ jade -E14 -D $(srcdir) -d yazprint.dsl -t tex $(srcdir)/xml.dcl $(TOP)
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+
+index.tkl: $(XMLFILES) tkl.xsl
+ xsltproc tkl.xsl $(TOP)
+
+clean-data-hook:
+ rm -f [0-9]* *.bak
+
--- /dev/null
+# Makefile.in generated by automake 1.7.9 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSSSL_DIR = @DSSSL_DIR@
+DTD_DIR = @DTD_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XSLT_CFLAGS = @XSLT_CFLAGS@
+XSLT_LIBS = @XSLT_LIBS@
+YAZINC = @YAZINC@
+YAZLALIB = @YAZLALIB@
+YAZLIB = @YAZLIB@
+YAZPP_BUILD_ROOT = @YAZPP_BUILD_ROOT@
+YAZPP_SRC_ROOT = @YAZPP_SRC_ROOT@
+YAZVERSION = @YAZVERSION@
+ZOOM_FALSE = @ZOOM_FALSE@
+ZOOM_TRUE = @ZOOM_TRUE@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+yazconfig = @yazconfig@
+docdir = $(datadir)/doc/@PACKAGE@
+
+SUPPORTFILES = \
+ yazhtml.dsl.in \
+ yazphp.dsl.in \
+ yazprint.dsl.in \
+ tkl.xsl.in \
+ xml.dcl
+
+XMLFILES = \
+ introduction.xml \
+ installation.xml \
+ zoom.xml \
+ proxy.xml \
+ api.xml \
+ yaz-proxy-ref.xml \
+ yaz-proxy-man.sgml \
+ license.xml \
+ yaz++.xml.in
+
+
+TOP = yaz++.xml
+MANFILES = yaz-proxy.8
+HTMLFILES = \
+ api.html \
+ implementations.html \
+ installation.html \
+ introduction.html \
+ license.html \
+ other-optimizations.html \
+ otherinfo-encoding.html \
+ proxy-config-file.html \
+ proxy-keepalive.html \
+ proxy-target.html \
+ proxy-usage.html \
+ proxy.html \
+ query-cache.html \
+ query-validation.html \
+ record-cache.html \
+ record-validation.html \
+ windows.html \
+ yaz-proxy.html \
+ yaz.license.html \
+ yazpp.html \
+ zoom-connection.html \
+ zoom-exception.html \
+ zoom-query.html \
+ zoom-record.html \
+ zoom-resultset.html \
+ zoom.html
+
+
+doc_DATA = $(HTMLFILES) yaz++.pdf id.png yaz.css
+
+man_MANS = $(MANFILES)
+
+EXTRA_DIST = $(SUPPORTFILES) $(XMLFILES) $(doc_DATA) $(man_MANS)
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = yaz++.xml yazprint.dsl yazphp.dsl yazhtml.dsl \
+ tkl.xsl
+DIST_SOURCES =
+
+NROFF = nroff
+MANS = $(man_MANS)
+DATA = $(doc_DATA)
+
+DIST_COMMON = $(srcdir)/Makefile.in Makefile.am tkl.xsl.in yaz++.xml.in \
+ yazhtml.dsl.in yazphp.dsl.in yazprint.dsl.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+yaz++.xml: $(top_builddir)/config.status yaz++.xml.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+yazprint.dsl: $(top_builddir)/config.status yazprint.dsl.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+yazphp.dsl: $(top_builddir)/config.status yazphp.dsl.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+yazhtml.dsl: $(top_builddir)/config.status yazhtml.dsl.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+tkl.xsl: $(top_builddir)/config.status tkl.xsl.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+man8dir = $(mandir)/man8
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+docDATA_INSTALL = $(INSTALL_DATA)
+install-docDATA: $(doc_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(docdir)
+ @list='$(doc_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(docDATA_INSTALL) $$d$$p $(DESTDIR)$(docdir)/$$f"; \
+ $(docDATA_INSTALL) $$d$$p $(DESTDIR)$(docdir)/$$f; \
+ done
+
+uninstall-docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(doc_DATA)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(docdir)/$$f"; \
+ rm -f $(DESTDIR)$(docdir)/$$f; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS) $(DATA)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir) $(DESTDIR)$(docdir)
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-docDATA install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-docDATA uninstall-info-am uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am info info-am install install-am install-data \
+ install-data-am install-docDATA install-exec install-exec-am \
+ install-info install-info-am install-man install-man8 \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ uninstall uninstall-am uninstall-docDATA uninstall-info-am \
+ uninstall-man uninstall-man8
+
+
+$(HTMLFILES): $(XMLFILES)
+ jade -E14 -D $(srcdir) -d yazhtml.dsl -t sgml $(srcdir)/xml.dcl $(TOP)
+
+yaz-proxy.8: yaz-proxy-man.sgml yaz-proxy-ref.xml
+ docbook2man $(srcdir)/yaz-proxy-man.sgml
+
+yazpp.php: $(XMLFILES)
+ jade -E14 -D $(srcdir) -d yazphp.dsl -t sgml $(srcdir)/xml.dcl $(TOP)
+
+yaz++.pdf: $(XMLFILES)
+ if test ! -f id.png ; then ln -s $(srcdir)/id.png .; fi
+ jade -E14 -D $(srcdir) -d yazprint.dsl -t tex $(srcdir)/xml.dcl $(TOP)
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+ pdfjadetex yaz++.tex >pdfjadetex.log 2>&1
+
+index.tkl: $(XMLFILES) tkl.xsl
+ xsltproc tkl.xsl $(TOP)
+
+clean-data-hook:
+ rm -f [0-9]* *.bak
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+<chapter id="installation">
+ <!-- $Id: installation.xml,v 1.1 2004-04-11 11:36:52 adam Exp $ -->
+ <title>Installation</title>
+ <para>
+ You need a C++ compiler to compile and use YAZ++.
+ The software was implemented using GCC so we know that works
+ well with YAZ++. From time to time the software has been
+ compiled on Windows using Visual C++. Other compilers should
+ work too. Let us know of portability problems, etc. with
+ your system.
+ </para>
+ <para>
+ YAZ++ is built on top of the
+ <ulink url="http://indexdata.dk/yaz/">YAZ</ulink>
+ toolkit.
+ You need to install that first.
+ For some platforms there are binary packages for YAZ.
+ </para>
+ <section id="unix">
+ <title>Building on Unix</title>
+ <para>On UNIX, the software is compiled as follows:
+ <screen>
+ $ ./configure
+ $ make
+ $ su
+ # make install
+ </screen>
+ </para>
+ <para>
+ You can supply options for the <literal>configure</literal> script.
+ The most useful ones are:
+ <variablelist>
+ <varlistentry>
+ <term><literal>--prefix </literal>directory</term>
+ <listitem><para>
+ Specifies installation prefix. By default
+ <literal>/usr/local</literal> is used.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>--with-yazconfig </literal>directory</term>
+ <listitem><para>
+ Specifies the location of <filename>yaz-config</filename>.
+ The <filename>yaz-config</filename> program is generated in
+ the source directory of YAZ as well as the binaries
+ directory when YAZ is installed (via make install).
+ </para>
+ <para>
+ If you don't supply this option, <literal>configure</literal> will
+ look for <filename>yaz-config</filename> in directories of the
+ <envar>PATH</envar> environment - which is nearly always
+ what you want.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>--with-xslt </literal>directory</term>
+ <listitem><para>
+ Specifies prefix for libxslt (and libxml2).
+ configure must be able to locate <command>xslt-config</command>
+ in PREFIX/bin. If this option is omitted, configure looks
+ for <command>xslt-config</command> in the current PATH.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ For the whole list of <literal>configure</literal> options, refer
+ to the help:
+ <literal>./configure --help</literal>.
+ </para>
+ <para>
+ Configure uses GCC's C/C++ compiler if available. To specify another
+ compiler, set <literal>CXX</literal>. To use other compiler flags,
+ specify <literal>CXXFLAGS</literal>. To use <literal>CC</literal>
+ with debugging you could use:
+ <screen>
+ CXXFLAGS="-g" CXX=CC ./configure
+ </screen>
+ </para>
+ <para>
+ This is what you have after successful compilation:
+ <variablelist>
+ <varlistentry>
+ <term><literal>proxy/yaz-proxy</literal></term>
+ <listitem><para>
+ The YAZ <link linkend="proxy">Z39.50 Proxy</link>.
+ This program gets installed in your binaries directory
+ (<parameter>prefix</parameter><literal>/bin</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>src/libyazcpp.la</literal></term>
+ <listitem><para>
+ The YAZ++ library.
+ This library gets installed in your libraries directory
+ (<parameter>prefix</parameter><literal>/lib</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>src/libzoomcpp.la</literal></term>
+ <listitem><para>
+ The <link linkend="zoom">ZOOM-C++</link> library.
+ This library gets installed in your libraries directory
+ (<parameter>prefix</parameter><literal>/lib</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>proxy/libyazproxy.la</literal></term>
+ <listitem><para>
+ The YAZ proxy library. This library gets installed in
+ your libraries directory
+ (<parameter>prefix</parameter><literal>/lib</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>include/yaz++/*.h</literal></term>
+ <listitem><para>
+ Various C++ header files, which you'll need for YAZ++
+ development. All these are installed in your header files area
+ (<parameter>prefix</parameter><literal>/include/yaz++</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>yaz++-config</literal></term>
+ <listitem><para>
+ A Bourne shell-script utility that returns the values of the
+ <envar>CFLAGS</envar> and <envar>LIBS</envar>
+ environment variables
+ needed in order to compile your applications with the YAZ++
+ library. This script gets installed in your binaries directory
+ (<parameter>prefix</parameter><literal>/bin</literal>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>zoom/zclient</literal></term>
+ <listitem><para>
+ ZOOM C++ demonstration client that uses the ZOOM C++ classes.
+ This client does not get installed in the system directories.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>src/yaz-my-client</literal></term>
+ <listitem><para>
+ YAZ C++ demonstration client. This client does not
+ get installed in the system directories.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>src/yaz-my-server</literal></term>
+ <listitem><para>
+ YAZ C++ demonstration server. This server does not
+ get installed in the system directories.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </section>
+ <section id="windows">
+ <title>Building on Windows</title>
+ <para>
+ YAZ++ is shipped with "makefiles" for the NMAKE tool that comes
+ with <ulink url="http://msdn.microsoft.com/vstudio/">
+ Microsoft Visual Studio</ulink>.
+ Version 6 and .NET has been tested. We expect that YAZ++ compiles
+ with version 5 as well.
+ </para>
+ <para>
+ Start a command prompt and switch the sub directory
+ <filename>WIN</filename> where the file <filename>makefile</filename>
+ is located. Customize the installation by editing the
+ <filename>makefile</filename> file (for example by using notepad).
+
+ The following summarizes the most important settings in that file:
+
+ <variablelist>
+ <varlistentry><term><literal>DEBUG</literal></term>
+ <listitem><para>
+ If set to 1, the software is
+ compiled with debugging libraries (code generation is
+ multi-threaded debug DLL).
+ If set to 0, the software is compiled with release libraries
+ (code generation is multi-threaded DLL).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>HAVE_XSLT</literal>,
+ <literal>LIBXSLT_DIR</literal></term>
+ <listitem>
+ <para>
+ If <literal>HAVE_LIBXSLT</literal> is set to 1, the proxy is compiled
+ with XSLT and XML support. In this configuration, set
+ <literal>LIBXSLT_DIR</literal> to the
+ <ulink url="http://www.xmlsoft.org/">libxslt</ulink> source
+ directory.
+ </para>
+
+ <note>
+ <para>
+ If you enable libXSLT you have to enable libxml2 and its
+ sub components zlib and iconv as well.
+ </para>
+ </note>
+
+ <para>
+ Windows versions of libxslt, libxml2, zlib and iconv can be found
+ <ulink url="http://www.zlatkovic.com/libxml.en.html">
+ here</ulink>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>HAVE_ICONV</literal>,
+ <literal>ICONV_DIR</literal></term>
+ <listitem><para>
+ If <literal>HAVE_ICONV</literal> is set to 1, the proxy is
+ compiled with iconv support. In this configuration, set
+ <literal>ICONV_DIR</literal> to the iconv source directory.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>HAVE_LIBXML2</literal>,
+ <literal>LIBXML2_DIR</literal></term>
+ <listitem>
+ <para>
+ If <literal>HAVE_LIBXML2</literal> is set to 1, the proxy is compiled
+ with XML support. In this configuration, set
+ <literal>LIBXML2_DIR</literal> to the
+ <ulink url="http://www.xmlsoft.org/">libxml2</ulink> source directory
+ and
+ <literal>ZLIB_DIR</literal> to the zlib directory.
+ </para>
+
+ <note>
+ <para>
+ YAZ++ is not using ZLIB. But libxml2 is.
+ </para>
+ </note>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+ <para>
+ When satisfied with the settings in the makefile, type
+ <screen>
+ nmake
+ </screen>
+ </para>
+ <tip>
+ <para>
+ If the <filename>nmake</filename> command is not found on your system
+ you probably haven't defined the environment variables required to
+ use that tool. To fix that, find and run the batch file
+ <filename>vcvars32.bat</filename>. You need to run it from within
+ the command prompt or set the environment variables "globally";
+ otherwise it doesn't work.
+ </para>
+ </tip>
+ <para>
+ If you wish to recompile YAZ++ - for example if you modify
+ settings in the <filename>makefile</filename> you can delete
+ object files, etc by running.
+ <screen>
+ nmake clean
+ </screen>
+ </para>
+ <para>
+ The following files are generated upon successful compilation:
+
+ <variablelist>
+ <varlistentry><term><filename>bin/yazpp.dll</filename></term>
+ <listitem><para>
+ YAZ++ DLL . Includes ZOOM C++ as well.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term><filename>lib/yaz.lib</filename></term>
+ <listitem><para>
+ Import library for <filename>yazpp.dll</filename>.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term><filename>bin/yazproxy.dll</filename></term>
+ <listitem><para>
+ YAZ proxy DLL.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term><filename>lib/yazproxy.lib</filename></term>
+ <listitem><para>
+ Import library for <filename>yazproxy.dll</filename>.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term><filename>bin/yaz-proxy.exe</filename></term>
+ <listitem><para>
+ YAZ proxy. It's a WIN32 console application.
+ See <xref linkend="proxy"/> for more information.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term><filename>bin/zclient.exe</filename></term>
+ <listitem><para>
+ ZOOM C++ demo client. A simple WIN32 console application.
+ </para></listitem></varlistentry>
+
+ </variablelist>
+
+ </para>
+
+ </section>
+ </chapter>
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document: "yaz++.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
--- /dev/null
+<!-- $Id: introduction.xml,v 1.1 2004-04-11 11:36:52 adam Exp $ -->
+ <chapter id="introduction"><title>Introduction</title>
+ <para>
+ <ulink url="http://www.indexdata.dk/yazplusplus/">YAZ++</ulink>
+ is a C++ layer for YAZ and implements the ANSI Z39.50
+ protocol for information retrieval (client and server side).
+ While YAZ itself can be used from both C and C++ it is limited by the
+ common denominator C.
+ </para>
+ <para>
+ The YAZ++ packages also features a ZOOM interface for C++ (
+ <ulink url="(http://zoom.z3950.org/bind/cplusplus/">ZOOM C++</ulink>).
+ </para>
+ <para>
+ Later versions (0.7+) of YAZ++ also supports SRW/SRU.
+ </para>
+ <para>
+ This package also contains a proxy application and proxy developer
+ library.
+ The proxy application can be used to debug existing Z39.50
+ implementations, optimize Z39.50 operation (by caching and other
+ mechanisms), and offer a SRW/SRU service.
+ </para>
+
+ <section>
+ <title>Licensing</title>
+ <para>
+ The proxy application and the proxy library is covered by the
+ <link linkend="gpl">GPL</link>.
+ The remaning parts: the ZOOM-C++ library and the YAZ++ library is covered
+ by the <link linkend="yaz.license">YAZ license</link>.
+ </para>
+ </section>
+ </chapter>
+
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document:"yaz++.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
--- /dev/null
+<!-- $Id: license.xml,v 1.1 2004-04-11 11:36:52 adam Exp $ -->
+ <appendix id="license"><title>License</title>
+
+ <section id="gpl"><title>GPL</title>
+
+ <para>
+ YAZ Proxy,
+ Copyright © 1999-2004 Index Data ApS.
+ </para>
+
+ <para>
+ YAZ Proxy 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, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ YAZ Proxy 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.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public License
+ along with YAZ Proxy; see the file LICENSE.proxy. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ </para>
+
+ <section><title>GNU General Public License</title>
+ <screen>
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+ </screen>
+ </section>
+ </section>
+
+ <section id="yaz.license"><title>YAZ License</title>
+
+ <para>
+ Copyright © 1999-2004 Index Data Aps and Mike Taylor.
+ </para>
+
+ <para>
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation, in whole or in part, for any
+ purpose, is hereby granted, provided that:
+ </para>
+
+ <para>
+ 1. This copyright and permission notice appear in all copies of the
+ software and its documentation. Notices of copyright or attribution
+ which appear at the beginning of any file must remain unchanged.
+ </para>
+
+ <para>
+ 2. The names of Index Data or the individual authors may not be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+ </para>
+
+ <para>
+ THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ OF THIS SOFTWARE.
+ </para>
+ </section>
+ </appendix>
+
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document: "yaz++.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
--- /dev/null
+ <chapter id="proxy">
+ <title>The YAZ Proxy</title>
+ <para>
+ The YAZ proxy is a transparent SRW/SRU/Z39.50-to-Z39.50 gateway.
+ That is, it is a SRW/SRU/Z39.50 server which has as its back-end a
+ Z39.50 client that forwards requests on to another server (known as
+ the <firstterm>backend target</firstterm>.)
+ </para>
+ <para>
+ -- All config directives --
+ -- SRW/SRU ..
+ -- Example config
+ -- Mention XSLT conversion
+ </para>
+ <para>
+ The YAZ Proxy is useful for debugging SRW/SRU/Z39.50 software, logging
+ APDUs, redirecting Z39.50 packages through firewalls, etc.
+ Furthermore, it offers facilities that often
+ boost performance for connectionless Z39.50 clients such
+ as web gateways.
+ </para>
+ <para>
+ Unlike most other server software, the proxy runs single-threaded,
+ single-process. Every I/O operation
+ is non-blocking so it is very lightweight and extremely fast.
+ It does not store any state information on the hard drive,
+ except any log files you ask for.
+ </para>
+
+ <section id="proxy-example">
+ <title>Example: Using the Proxy to Log APDUs</title>
+ <para>
+ Suppose you use a commercial Z39.50 client for which you do not
+ have source code, and it's not behaving how you think it should
+ when running against some specific server that you have no control
+ over. One way to diagnose the problem is to find out what packets
+ (APDUs) are being sent and received, but not all client
+ applications have facilities to do APDU logging.
+ </para>
+ <para>
+ No problem. Run the proxy on a friendly machine, get it to log
+ APDUs, and point the errant client at the proxy instead of
+ directly at the server that's causing it problems.
+ </para>
+ <para>
+ Suppose the server is running on <literal>foo.bar.com</literal>,
+ port 18398. Run the proxy on the machine of your choice, say
+ <literal>your.company.com</literal> like this:
+ </para>
+ <screen>
+ yaz-proxy -a - -t tcp:foo.bar.com:18398 tcp:@:9000
+ </screen>
+ <para>
+ (The <literal>-a -</literal> option requests APDU logging on
+ standard output, <literal>-t tcp:foo.bar.com:18398</literal>
+ specifies where the backend target is, and
+ <literal>tcp:@:9000</literal> tells the proxy to listen on port
+ 9000 and accept connections from any machine.)
+ </para>
+ <para>
+ Now change your client application's configuration so that instead
+ of connecting to <literal>foo.bar.com</literal> port 18398, it
+ connects to <literal>your.company.com</literal> port 9000, and
+ start it up. It will work exactly as usual, but all the packets
+ will be sent via the proxy, which will generate a log like this:
+ </para>
+ <screen><![CDATA[
+ decode choice
+ initRequest {
+ referenceId OCTETSTRING(len=4) 69 6E 69 74
+ protocolVersion BITSTRING(len=1)
+ options BITSTRING(len=2)
+ preferredMessageSize 1048576
+ maximumRecordSize 1048576
+ implementationId 'Mike Taylor (id=169)'
+ implementationName 'Net::Z3950.pm (Perl)'
+ implementationVersion '0.31'
+ }
+ encode choice
+ initResponse {
+ referenceId OCTETSTRING(len=4) 69 6E 69 74
+ protocolVersion BITSTRING(len=1)
+ options BITSTRING(len=2)
+ preferredMessageSize 1048576
+ maximumRecordSize 1048576
+ result TRUE
+ implementationId '81'
+ implementationName 'GFS/YAZ / Zebra Information Server'
+ implementationVersion 'YAZ 1.9.1 / Zebra 1.3.3'
+ }
+ decode choice
+ searchRequest {
+ referenceId OCTETSTRING(len=1) 30
+ smallSetUpperBound 0
+ largeSetLowerBound 1
+ mediumSetPresentNumber 0
+ replaceIndicator TRUE
+ resultSetName 'default'
+ databaseNames {
+ 'gils'
+ }
+ {
+ smallSetElementSetNames choice
+ generic 'F'
+ }
+ {
+ mediumSetElementSetNames choice
+ generic 'B'
+ }
+ preferredRecordSyntax OID: 1 2 840 10003 5 10
+ {
+ query choice
+ type_1 {
+ attributeSetId OID: 1 2 840 10003 3 1
+ RPNStructure choice
+ {
+ simple choice
+ attributesPlusTerm {
+ attributes {
+ }
+ term choice
+ general OCTETSTRING(len=7) 6D 69 6E 65 72 61 6C
+ }
+ }
+ }
+ }
+ }
+]]>
+ </screen>
+ </section>
+
+ <section id="proxy-target">
+ <title>Specifying the Backend Target</title>
+ <para>
+ When the proxy receives a Z39.50 Initialize Request from a Z39.50
+ client, it determines the backend target by the following rules:
+ <orderedlist>
+ <listitem>
+ <para>If the <literal>InitializeRequest</literal> PDU from the
+ client includes an
+ <link linkend="otherinfo-encoding"><literal>otherInfo</literal></link>
+ element with OID
+ <literal>1.2.840.10003.10.1000.81.1</literal>, then the
+ contents of that element specify the target to be used, in the
+ usual YAZ address format (typically
+ <literal>tcp:<parameter>hostname</parameter>:<parameter>port</parameter></literal>)
+ as described in
+ <ulink url="http://www.indexdata.dk/yaz/doc/comstack.addresses.tkl"
+ >the Addresses section of the YAZ manual</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Otherwise, the Proxy uses the default target, if one was
+ specified on the command-line with the <literal>-t</literal>
+ option. A default target can also be specified in the
+ XML Config file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Otherwise, the proxy closes the connection with
+ the client.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </section>
+ <section id="proxy-keepalive">
+ <title>Keep-alive Facility</title>
+ <para>
+ The keep-alive is a facility where the proxy keeps the connection to the
+ backend - even if the client closes the connection to the proxy.
+ </para>
+ <para>
+ If a new or another client connects to the proxy again and requests the
+ same backend it will be reassigned to this backend. In this case, the
+ proxy sends an initialize response directly to the client and an
+ initialize handshake with the backend is omitted.
+ </para>
+ <para>
+ When a client reconnects, query and record caching works better, if the
+ proxy assigns it to the same backend as before. And the result set
+ (if any) is re-used. To achieve this, Index Data defined a session
+ cookie which identifies the backend session.
+ </para>
+ <para>
+ The cookie is defined by the client and is sent as part of the
+ Initialize Request and passed in an
+ <link linkend="otherinfo-encoding"><literal>otherInfo</literal></link>
+ element with OID <literal>1.2.840.10003.10.1000.81.2</literal>.
+ </para>
+ <para>
+ Clients that do not send a cookie as part of the initialize request
+ may still better performance, since the init handshake is saved.
+ </para>
+ </section>
+
+ <section id="query-cache">
+ <title>Query Caching</title>
+ <para>
+ Simple stateless clients often send identical Z39.50 searches
+ in a relatively short period of time (e.g. in order to produce a
+ results-list page, the next page,
+ a single full-record, etc). And for many targets, it's
+ much more expensive to produce a new result set than to
+ reuse an existing one.
+ </para>
+ <para>
+ The proxy tries to solve that by remembering the last query for each
+ backend target, so that if an identical query is received next, it
+ is turned into Present Requests rather than new Search Requests.
+ </para>
+ <note>
+ <para>
+ In a future we release will will probably allows for
+ an arbitrary-sized cache for targets supporting named result sets.
+ </para>
+ </note>
+ <para>
+ You can enable/disable query caching using option -o.
+ </para>
+ </section>
+
+ <section id="record-cache">
+ <title>Record Caching</title>
+ <para>
+ As an option, the proxy may also cache result set records for the
+ last search.
+ The proxy takes into account the Record Syntax and CompSpec.
+ The CompSpec includes simple element set names as well.
+ By default the cache is 200000 bytes per session.
+ </para>
+ </section>
+
+ <section id="query-validation">
+ <title>Query Validation</title>
+ <para>
+ The Proxy may also be configured to trap particular attributes in
+ Type-1 queries and send Bib-1 diagnostics back to the client without
+ even consulting the backend target. This facility may be useful if
+ a target does not properly issue diagnostics when unsupported attributes
+ are send to it.
+ </para>
+ </section>
+
+ <section id="record-validation">
+ <title>Record Syntax Validation</title>
+ <para>
+ The proxy may be configured to accept, reject or convert records.
+ When accepted, the target passes search/present requests to the
+ backend target under the assumption that the target can honor the
+ request (In fact it may not do that). When a record is rejected because
+ the record syntax is "unsupported" the proxy returns a diagnostic to the
+ client. Finally, the proxy may convert records.
+ </para>
+ <para>
+ The proxy can convert from MARC to MARCXML and thereby offer an
+ XML version of any MARC record as long as it is ISO2709 encoded.
+ If the proxy is compiled with libXSLT support it can also
+ perform XSLT on XML.
+ </para>
+ </section>
+
+ <section id="other-optimizations">
+ <title>Other Optimizations</title>
+ <para>
+ We've had some plans to support global caching of result set records,
+ but this has not yet been implemented.
+ </para>
+ </section>
+
+ <section id="proxy-config-file">
+ <title>Proxy Configuration File</title>
+ <para>
+ The Proxy may read a configuration file using option
+ <literal>-c</literal> followed by the filename of a config file.
+ </para>
+ <para>
+ The config file is XML based. The YAZ proxy must be compiled
+ with <ulink url="http://www.xmlsoft.org/">libxml2</ulink> and
+ <ulink url="http://xmlsoft.org/XSLT/">libXSLT</ulink> support in
+ order for the config file facility to be enabled.
+ </para>
+ <tip>
+ <para>To check for a config file to be well-formed, the yaz-proxy may
+ be invoked without specifying a listening port, i.e.
+ <screen>
+ yaz-proxy -c myconfig.xml
+ </screen>
+ If this does not produce errors, the file is well-formed.
+ </para>
+ </tip>
+ <section id="proxy-config-header">
+ <title>Proxy Configuration Header</title>
+ <para>
+ The proxy config file must have a root element called
+ <literal>proxy</literal>. All information except an optional XML
+ header must be stored within the <literal>proxy</literal> element.
+ </para>
+ <screen>
+ <?xml version="1.0"?>
+ <proxy>
+ <!-- content here .. -->
+ </proxy>
+ </screen>
+ </section>
+ <section id="proxy-config-target">
+ <title>Configuration: target</title>
+ <para>
+ The element <literal>target</literal> which may be repeated zero
+ or more times with parent element <literal>proxy</literal> contains
+ information about each backend target.
+ The <literal>target</literal> element have two attributes:
+ <literal>name</literal> which holds the logical name of the backend
+ target (required) and <literal>default</literal> (optional) which
+ (when given) specifies that the backend target is the default target -
+ equivalent to command line option <literal>-t</literal>.
+ </para>
+ <para>
+ <screen>
+ <?xml version="1.0"?>
+ <proxy>
+ <target name="server1" default="1">
+ <!-- description of server1 .. -->
+ </target>
+ <target name="server2">
+ <!-- description of server2 .. -->
+ </target>
+ </proxy>
+ </screen>
+ </para>
+ </section>
+ <section id="proxy-config-url">
+ <title>Configuration:url</title>
+ <para>
+ The <literal>url</literal> which may be repeated one or more times
+ should be the child of the <literal>target</literal> element.
+ The CDATA of <literal>url</literal> is the Z-URL of the backend.
+ </para>
+ <para>
+ Multiple <literal>url</literal> element may be used. In that case, then
+ a client initiates a session, the proxy chooses the URL with the lowest
+ number of active sessions, thereby distributing the load. It is
+ assumed that each URL represents the same database (data).
+ </para>
+ </section>
+ <section id="proxy-config-keepalive">
+ <title>Configuration: keepalive</title>
+ <para>The <literal>keepalive</literal> element holds information about
+ the keepalive Z39.50 sessions. Keepalive sessions are proxy-to-backend
+ sessions that is no longer associated with a client session.
+ </para>
+ <para>The <literal>keepalive</literal> element which is the child of
+ the <literal>target</literal>holds two elements:
+ <literal>bandwidth</literal> and <literal>pdu</literal>.
+ The <literal>bandwidth</literal> is the maximum total bytes
+ transferred to/from the target. If a target session exceeds this
+ limit, it is shut down (and no longer kept alive).
+ The <literal>pdu</literal> is the maximum number of requests sent
+ to the target. If a target session exceeds this limit, it is
+ shut down. The idea of these two limits is that avoid very long
+ sessions that use resources in a backend (that leaks!).
+ </para>
+ <para>
+ The following sets maximum number of bytes transferred in a
+ target session to 1 MB and maxinum of requests to 400.
+ <screen>
+ <keepalive>
+ <bandwidth>1048576</bandwidth>
+ <retrieve>400</retrieve>
+ </keepalive>
+ </screen>
+ </para>
+ </section>
+ <section id="proxy-config-limit">
+ <title>Configuration: limit</title>
+ <para>
+ The <literal>limit</literal> section specifies bandwidth/pdu requests
+ limits for an active session.
+ The proxy records bandwidth/pdu requests during the last 60 seconds
+ (1 minute). The <literal>limit</literal> may include the
+ elements <literal>bandwidth</literal>, <literal>pdu</literal>,
+ and <literal>retrieve</literal>. The <literal>bandwidth</literal>
+ measures the number of bytes transferred within the last minute.
+ The <literal>pdu</literal> is the number of requests in the last
+ minute. The <literal>retrieve</literal> holds the maximum records to
+ be retrieved in one Present Request.
+ </para>
+ <para>
+ If a bandwidth/pdu limit is reached the proxy will postpone the
+ requests to the target and wait one or more seconds. The idea of the
+ limit is to ensure that clients that downloads hundreds or thousands of
+ records do not hurt other users.
+ </para>
+ <para>
+ The following sets maximum number of bytes transferred per minute to
+ 500Kbytes and maximum number of requests to 40.
+ <screen>
+ <limit>
+ <bandwidth>524288</bandwidth>
+ <retrieve>40</retrieve>
+ </limit>
+ </screen>
+ </para>
+ <note>
+ <para>
+ Typically the limits for keepalive are much higher than
+ those for session minute average.
+ </para>
+ </note>
+ </section>
+
+ <section id="proxy-config-attribute">
+ <title>Configuration: attribute</title>
+ <para>
+ The <literal>attribute</literal> element specifies accept or reject
+ or a particular attribute type, value pair.
+ Well-behaving targets will reject unsupported attributes on their
+ own. This feature is useful for targets that do not gracefully
+ handle unsupported attributes.
+ </para>
+ <para>
+ Attribute elements may be repeated. The proxy inspects the attribute
+ specifications in the order as specified in the configuration file.
+ When a given attribute specification matches a given attribute list
+ in a query, the proxy takes appropriate action (reject, accept).
+ </para>
+ <para>
+ If no attribute specifications matches the attribute list in a query,
+ it is accepted.
+ </para>
+ <para>
+ The <literal>attribute</literal> element has two required attributes:
+ <literal>type</literal> which is the Attribute Type-1 type, and
+ <literal>value</literal> which is the Attribute Type-1 value.
+ The special value/type <literal>*</literal> matches any attribute
+ type/value. A value may also be specified as a list with each
+ value separated by comma, a value may also be specified as a
+ list: low value - dash - high value.
+ </para>
+ <para>
+ If attribute <literal>error</literal> is given, that holds a
+ Bib-1 diagnostic which is sent to the client if the particular
+ type, value is part of a query.
+ </para>
+ <para>
+ If attribute <literal>error</literal> is not given, the attribute
+ type, value is accepted and passed to the backend target.
+ </para>
+ <para>
+ A target that supports use attributes 1,4, 1000 through 1003 and
+ no other use attributes, could use the following rules:
+ <screen>
+ <attribute type="1" value="1,4,1000-1003">
+ <attribute type="1" value="*" error="114"/>
+ </screen>
+ </para>
+ </section>
+
+ <section id="proxy-config-syntax">
+ <title>Configuration: syntax</title>
+ <para>
+ The <literal>syntax</literal> element specifies accept or reject
+ or a particular record syntax request from the client.
+ </para>
+ <para>
+ The <literal>syntax</literal> has one required attribute:
+ <literal>type</literal> which is the Preferred Record Syntax.
+ </para>
+ <para>
+ If attribute <literal>error</literal> is given, that holds a
+ Bib-1 diagnostic which is sent to the client if the particular
+ record syntax is part of a present - or search request.
+ </para>
+ <para>
+ If attribute <literal>error</literal> is not given, the record syntax
+ is accepted and passed to the backend target.
+ </para>
+ <para>
+ If attribute <literal>marcxml</literal> is given, the proxy will
+ perform MARC21 to MARCXML conversion. In this case the
+ <literal>type</literal> should be XML. The proxy will use
+ preferred record syntax USMARC/MARC21 against the backend target.
+ </para>
+ <para>To accept USMARC and offer MARCXML XML records but reject
+ all other requests the following configuration could be used:
+ <screen>
+ <proxy>
+ <target name="mytarget">
+ <syntax type="usmarc"/>
+ <syntax type="xml" marcxml="1"/>
+ <syntax type="*" error="238"/>
+ </target>
+ </proxy>
+ </screen>
+ </para>
+ </section>
+
+ <section id="proxy-config-target-timeout">
+ <title>Configuration: target-timeout</title>
+ <para>
+ The element <literal>target-timeout</literal> is the child of element
+ <literal>target</literal> and specifies the amount in seconds before
+ a target session is shut down.
+ </para>
+ <para>
+ This can also be specified on the command line by using option
+ <literal>-T</literal>. Refer to <xref linkend="proxy-usage"/>.
+ </para>
+ </section>
+
+ <section id="proxy-config-client-timeout">
+ <title>Configuration: client-timeout</title>
+ <para>
+ The element <literal>client-timeout</literal> is the child of element
+ <literal>target</literal> and specifies the amount in seconds before
+ a client session is shut down.
+ </para>
+ <para>
+ This can also be specified on the command line by using option
+ <literal>-i</literal>. Refer to <xref linkend="proxy-usage"/>.
+ </para>
+ </section>
+
+ <section id="proxy-config-preinit">
+ <title>Configuration: preinit</title>
+ <para>
+ The element <literal>preinit</literal> is the child of element
+ <literal>target</literal> and specifies the number of spare
+ connection to a target. By default no spare connection are
+ created by the proxy. If the proxy uses a target exclusive or
+ a lot, the preinit session will ensure that target sessions
+ have been made before the client makes a connection and will therefore
+ reduce the connect-init handshake dramatically. Never set this to
+ more than 5.
+ </para>
+ </section>
+
+ <section id="proxy-config-max-clients">
+ <title>Configuration: max-clients</title>
+ <para>
+ The element <literal>max-clients</literal> is the child of element
+ <literal>proxy</literal> and specifies the total number of
+ allowed connections to targets (all targets). If this limit
+ is reached the proxy will close the least recently used connection.
+ </para>
+ <para>
+ Note, that many Unix systems impose a system on the number of
+ open files allowed in a single process, typically in the
+ range 256 (Solaris) to 1024 (Linux).
+ The proxy uses 2 sockets per session + a few files
+ for logging. As a rule of thumb, ensure that 2*max-clients + 5
+ can be opened by the proxy process.
+ </para>
+ <tip>
+ <para>
+ Using the <ulink url="http://www.gnu.org/software/bash/bash.html">
+ bash</ulink> shell, you can set the limit with
+ <literal>ulimit -n</literal><replaceable>no</replaceable>.
+ Use <literal>ulimit -a</literal> to display limits.
+ </para>
+ </tip>
+ </section>
+
+ <section id="proxy-config-log">
+ <title>Configuration: log</title>
+ <para>
+ The element <literal>log</literal> is the child of element
+ <literal>proxy</literal> and specifies what to be logged by the
+ proxy.
+ </para>
+ <para>
+ Specify the log file with command-line option <literal>-l</literal>.
+ </para>
+ <para>
+ The text of the <literal>log</literal> element is a sequence of
+ options separated by white space. See the table below:
+ <table frame="top"><title>Logging options</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*" colname="option"/>
+ <colspec colwidth="2*" colname="description"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>client-apdu</literal></entry>
+ <entry>
+ Log APDUs as reported by YAZ for the
+ communication between the client and the proxy.
+ This facility is equivalent to the APDU logging that
+ happens when using option <literal>-a</literal>, however
+ this tells the proxy to log in the same file as given
+ by <literal>-l</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>server-apdu</literal></entry>
+ <entry>
+ Log APDUs as reported by YAZ for the
+ communication between the proxy and the server (backend).
+ </entry>
+ </row>
+ <row>
+ <entry><literal>clients-requests</literal></entry>
+ <entry>
+ Log a brief description about requests transferred between
+ the client and the proxy. The name of the request and the size
+ of the APDU is logged.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>server-requests</literal></entry>
+ <entry>
+ Log a brief description about requests transferred between
+ the proxy and the server (backend). The name of the request
+ and the size of the APDU is logged.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ To log communication in details between the proxy and the backend, th
+ following configuration could be used:
+ <screen><![CDATA[
+ <target name="mytarget">
+ <log>server-apdu server-requests</log>
+ </target>
+]]>
+ </screen>
+ </para>
+ </section>
+
+ </section>
+ <section id="proxy-usage">
+ <title>Proxy Usage</title>
+ <para>
+ </para>
+ <refentry id="yaz-proxy">
+ &yaz-proxy-ref;
+ </refentry>
+ </section>
+ <section id="otherinfo-encoding"><title>OtherInformation Encoding</title>
+ <para>
+ The proxy uses the OtherInformation definition to carry
+ information about the target address and cookie.
+ </para>
+ <screen>
+ OtherInformation ::= [201] IMPLICIT SEQUENCE OF SEQUENCE{
+ category [1] IMPLICIT InfoCategory OPTIONAL,
+ information CHOICE{
+ characterInfo [2] IMPLICIT InternationalString,
+ binaryInfo [3] IMPLICIT OCTET STRING,
+ externallyDefinedInfo [4] IMPLICIT EXTERNAL,
+ oid [5] IMPLICIT OBJECT IDENTIFIER}}
+--
+ InfoCategory ::= SEQUENCE{
+ categoryTypeId [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+ categoryValue [2] IMPLICIT INTEGER}
+ </screen>
+ <para>
+ The <literal>categoryTypeId</literal> is either
+ OID 1.2.840.10003.10.1000.81.1, 1.2.840.10003.10.1000.81.2
+ for proxy target and proxy cookie respectively. The
+ integer element <literal>category</literal> is set to 0.
+ The value proxy and cookie is stored in element
+ <literal>characterInfo</literal> of the <literal>information</literal>
+ choice.
+ </para>
+ </section>
+ </chapter>
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document: "yaz++.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
+
--- /dev/null
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+ <xsl:include href="/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/xhtml/chunk.xsl"/>
+
+ <xsl:variable name="use.id.as.filename">1</xsl:variable>
+ <xsl:variable name="html.ext">.tkl</xsl:variable>
+ <xsl:variable name="navig.showtitles">0</xsl:variable>
+ <xsl:param name="chunker.output.omit-xml-declaration" select="'yes'"/>
+
+<xsl:template name="chunk-element-content">
+ <xsl:param name="prev"/>
+ <xsl:param name="next"/>
+
+ <document>
+ <title>
+ <xsl:apply-templates select="." mode="object.title.markup"/>
+ </title>
+ <nonews>1</nonews>
+ <body>
+ <xsl:call-template name="body.attributes"/>
+ <xsl:call-template name="user.header.navigation"/>
+
+ <xsl:call-template name="header.navigation">
+ <xsl:with-param name="prev" select="$prev"/>
+ <xsl:with-param name="next" select="$next"/>
+ </xsl:call-template>
+
+ <xsl:call-template name="user.header.content"/>
+
+ <xsl:apply-imports/>
+
+ <xsl:call-template name="user.footer.content"/>
+
+ <xsl:call-template name="footer.navigation">
+ <xsl:with-param name="prev" select="$prev"/>
+ <xsl:with-param name="next" select="$next"/>
+ </xsl:call-template>
+
+ <xsl:call-template name="user.footer.navigation"/>
+ </body>
+ </document>
+</xsl:template>
+
+</xsl:stylesheet>
+
+
--- /dev/null
+<!SGML -- SGML Declaration for valid XML documents --
+ "ISO 8879:1986 (WWW)"
+
+ CHARSET
+ BASESET
+ "ISO Registration Number 176//CHARSET
+ ISO/IEC 10646-1:1993 UCS-4 with implementation
+ level 3//ESC 2/5 2/15 4/6"
+ DESCSET
+ 0 9 UNUSED
+ 9 2 9
+ 11 2 UNUSED
+ 13 1 13
+ 14 18 UNUSED
+ 32 95 32
+ 127 1 UNUSED
+ 128 32 UNUSED
+ -- use this instead of the official declaration because SP only
+ supports 16-bit characters --
+ 160 65374 160
+ 65534 2 UNUSED
+ -- 55296 2048 UNUSED
+ 57344 8190 57344
+ 65534 2 UNUSED
+ 65536 1048576 65536 --
+ CAPACITY NONE
+
+ SCOPE DOCUMENT
+
+ SYNTAX
+ SHUNCHAR NONE
+ BASESET "ISO Registration Number 176//CHARSET
+ ISO/IEC 10646-1:1993 UCS-4 with implementation
+ level 3//ESC 2/5 2/15 4/6"
+ DESCSET
+ 0 1114112 0
+ FUNCTION
+ RE 13
+ RS 10
+ SPACE 32
+ TAB SEPCHAR 9
+
+ NAMING
+ LCNMSTRT ""
+ UCNMSTRT ""
+ NAMESTRT
+ 58 95 192-214 216-246 248-305 308-318 321-328
+ 330-382 384-451 461-496 500-501 506-535 592-680
+ 699-705 902 904-906 908 910-929 931-974 976-982
+ 986 988 990 992 994-1011 1025-1036 1038-1103
+ 1105-1116 1118-1153 1168-1220 1223-1224
+ 1227-1228 1232-1259 1262-1269 1272-1273
+ 1329-1366 1369 1377-1414 1488-1514 1520-1522
+ 1569-1594 1601-1610 1649-1719 1722-1726
+ 1728-1742 1744-1747 1749 1765-1766 2309-2361
+ 2365 2392-2401 2437-2444 2447-2448 2451-2472
+ 2474-2480 2482 2486-2489 2524-2525 2527-2529
+ 2544-2545 2565-2570 2575-2576 2579-2600
+ 2602-2608 2610-2611 2613-2614 2616-2617
+ 2649-2652 2654 2674-2676 2693-2699 2701
+ 2703-2705 2707-2728 2730-2736 2738-2739
+ 2741-2745 2749 2784 2821-2828 2831-2832
+ 2835-2856 2858-2864 2866-2867 2870-2873 2877
+ 2908-2909 2911-2913 2949-2954 2958-2960
+ 2962-2965 2969-2970 2972 2974-2975 2979-2980
+ 2984-2986 2990-2997 2999-3001 3077-3084
+ 3086-3088 3090-3112 3114-3123 3125-3129
+ 3168-3169 3205-3212 3214-3216 3218-3240
+ 3242-3251 3253-3257 3294 3296-3297 3333-3340
+ 3342-3344 3346-3368 3370-3385 3424-3425
+ 3585-3630 3632 3634-3635 3648-3653 3713-3714
+ 3716 3719-3720 3722 3725 3732-3735 3737-3743
+ 3745-3747 3749 3751 3754-3755 3757-3758 3760
+ 3762-3763 3773 3776-3780 3904-3911 3913-3945
+ 4256-4293 4304-4342 4352 4354-4355 4357-4359
+ 4361 4363-4364 4366-4370 4412 4414 4416 4428
+ 4430 4432 4436-4437 4441 4447-4449 4451 4453
+ 4455 4457 4461-4462 4466-4467 4469 4510 4520
+ 4523 4526-4527 4535-4536 4538 4540-4546 4587
+ 4592 4601 7680-7835 7840-7929 7936-7957
+ 7960-7965 7968-8005 8008-8013 8016-8023 8025
+ 8027 8029 8031-8061 8064-8116 8118-8124 8126
+ 8130-8132 8134-8140 8144-8147 8150-8155
+ 8160-8172 8178-8180 8182-8188 8486 8490-8491
+ 8494 8576-8578 12295 12321-12329 12353-12436
+ 12449-12538 12549-12588 19968-40869 44032-55203
+
+ LCNMCHAR ""
+ UCNMCHAR ""
+ NAMECHAR
+ 45-46 183 720-721 768-837 864-865 903 1155-1158
+ 1425-1441 1443-1465 1467-1469 1471 1473-1474
+ 1476 1600 1611-1618 1632-1641 1648 1750-1764
+ 1767-1768 1770-1773 1776-1785 2305-2307 2364
+ 2366-2381 2385-2388 2402-2403 2406-2415
+ 2433-2435 2492 2494-2500 2503-2504 2507-2509
+ 2519 2530-2531 2534-2543 2562 2620 2622-2626
+ 2631-2632 2635-2637 2662-2673 2689-2691 2748
+ 2750-2757 2759-2761 2763-2765 2790-2799
+ 2817-2819 2876 2878-2883 2887-2888 2891-2893
+ 2902-2903 2918-2927 2946-2947 3006-3010
+ 3014-3016 3018-3021 3031 3047-3055 3073-3075
+ 3134-3140 3142-3144 3146-3149 3157-3158
+ 3174-3183 3202-3203 3262-3268 3270-3272
+ 3274-3277 3285-3286 3302-3311 3330-3331
+ 3390-3395 3398-3400 3402-3405 3415 3430-3439
+ 3633 3636-3642 3654-3662 3664-3673 3761
+ 3764-3769 3771-3772 3782 3784-3789 3792-3801
+ 3864-3865 3872-3881 3893 3895 3897 3902-3903
+ 3953-3972 3974-3979 3984-3989 3991 3993-4013
+ 4017-4023 4025 8400-8412 8417 12293 12330-12335
+ 12337-12341 12441-12442 12445-12446 12540-12542
+
+ NAMECASE
+ GENERAL NO
+ ENTITY NO
+
+ DELIM
+ GENERAL SGMLREF
+ HCRO "&#x" -- 38 is the number for ampersand --
+ NESTC "/"
+ NET ">"
+ PIC "?>"
+ SHORTREF NONE
+
+ NAMES
+ SGMLREF
+
+ QUANTITY NONE
+
+ ENTITIES
+ "amp" 38
+ "lt" 60
+ "gt" 62
+ "quot" 34
+ "apos" 39
+
+ FEATURES
+ MINIMIZE
+ DATATAG NO
+ OMITTAG NO
+ RANK NO
+ SHORTTAG
+ STARTTAG
+ EMPTY NO
+ UNCLOSED NO
+ NETENABL IMMEDNET
+ ENDTAG
+ EMPTY NO
+ UNCLOSED NO
+ ATTRIB
+ DEFAULT YES
+ OMITNAME NO
+ VALUE NO
+ EMPTYNRM YES
+ IMPLYDEF
+ ATTLIST NO
+ DOCTYPE NO
+ ELEMENT NO
+ ENTITY NO
+ NOTATION NO
+ LINK
+ SIMPLE NO
+ IMPLICIT NO
+ EXPLICIT NO
+ OTHER
+ CONCUR NO
+ SUBDOC NO
+ FORMAL NO
+ URN NO
+ KEEPRSRE YES
+ VALIDITY TYPE
+ ENTITIES
+ REF ANY
+ INTEGRAL YES
+ APPINFO NONE
+ SEEALSO "ISO 8879:1986//NOTATION
+ Extensible Markup Language (XML) 1.0//EN"
+>
--- /dev/null
+<refmeta>
+ <refentrytitle>yaz-proxy</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+ <refname>yaz-proxy</refname>
+ <refpurpose>The YAZ toolkit's transparent Z39.50 proxy</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>yaz-proxy</command>
+ <arg choice="opt">-a <replaceable>filename</replaceable></arg>
+ <arg choice="opt">-l <replaceable>filename</replaceable></arg>
+ <arg choice="opt">-m <replaceable>num</replaceable></arg>
+ <arg choice="opt">-v <replaceable>level</replaceable></arg>
+ <arg choice="opt">-t <replaceable>target</replaceable></arg>
+ <arg choice="opt">-U <replaceable>auth</replaceable></arg>
+ <arg choice="opt">-o <replaceable>level</replaceable></arg>
+ <arg choice="opt">-i <replaceable>seconds</replaceable></arg>
+ <arg choice="opt">-T <replaceable>seconds</replaceable></arg>
+ <arg choice="opt">-p <replaceable>pidfile</replaceable></arg>
+ <arg choice="opt">-u <replaceable>userid</replaceable></arg>
+ <arg choice="opt">-c <replaceable>config</replaceable></arg>
+ <arg choice="req"><replaceable>host</replaceable>:<replaceable>port</replaceable></arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+ <para>
+ <command>yaz-proxy</command> is a Z39.50 optimizing proxy daemon.
+ The listening port must be specified on the command-line.
+ <command>inetd</command> operation is not supported.
+ The <replaceable>host</replaceable>:<replaceable>port</replaceable>
+ argument specifies host address to listen to, and the port to
+ listen on. Use the host <literal>@</literal>
+ to listen for connections coming from any address.
+ </para>
+ <para>
+ <command>yaz-proxy</command> can be configured using command-line
+ options or a configuration file.
+ Configuration file options override values specified
+ on the command-line.
+ </para>
+ <para>
+ <command>yaz-proxy</command> rereads its configuration file and
+ reopens log files when it receives the hangup signal, SIGHUP.
+ </para>
+</refsect1>
+<refsect1><title>OPTIONS</title>
+ <variablelist>
+ <varlistentry><term>-a <replaceable>filename</replaceable></term>
+ <listitem><para>
+ Specifies the name of a file to which to write a log of the
+ APDUs (protocol packets) that pass through the proxy. The
+ special filename <literal>-</literal> may be used to indicate
+ standard output.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-l <replaceable>filename</replaceable></term>
+ <listitem><para>
+ Specifies the name of a file to which to write a log of the
+ YAZ proxy activity. This uses the logging facility as provided
+ by the YAZ toolkit. If this options is omitted, the output
+ directed to stderr.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-m <replaceable>num</replaceable></term>
+ <listitem><para>
+ Specifies the maximum number of connections to be cached
+ [default 50].
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-v <replaceable>level</replaceable></term>
+ <listitem><para>
+ Sets the logging level. <replaceable>level</replaceable> is
+ a comma-separated list of members of the set
+ {<literal>fatal</literal>,<literal>debug</literal>,<literal>warn</literal>,<literal>log</literal>,<literal>malloc</literal>,<literal>all</literal>,<literal>none</literal>}.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-t <replaceable>target</replaceable></term>
+ <listitem><para>
+ Specifies the default backend target to use when a client
+ connects that does not explicitly specify a target in its
+ <literal>initRequest</literal>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-U <replaceable>auth</replaceable></term>
+ <listitem><para>
+ Specifies authentication info to be sent to the backend target.
+ This is useful if you happen to have an internal target that
+ requires authentication, or if the client software does not allow
+ you to set it.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-o <replaceable>level</replaceable></term>
+ <listitem><para>
+ Sets level for optimization. Use zero to disable; non-zero
+ to enable. Handling for this is not fully implemented;
+ we will probably use a bit mask to enable/disable specific
+ features. By default optimization is enabled (value 1).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-i <replaceable>seconds</replaceable></term>
+ <listitem><para>
+ Specifies in seconds the idle time for communication between
+ client and proxy. If a connection is inactive for this long
+ it will be closed. Default: 600 seconds (10 minutes).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-T <replaceable>seconds</replaceable></term>
+ <listitem><para>
+ Specifies in seconds the idle time for communication between
+ proxy and backend target.
+ If a connection is inactive for this long
+ it will be closed. Default: 600 seconds (10 minutes).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-p <replaceable>pidfile</replaceable></term>
+ <listitem><para>
+ When specified, yaz-proxy will create <replaceable>pidfile</replaceable>
+ with the process ID of the proxy. The pidfile will be generated
+ before the process changes identity (see option <literal>-u</literal>).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-u <replaceable>userid</replaceable></term>
+ <listitem><para>
+ When specified, yaz-proxy will change identity to the user ID
+ specified, just after the proxy has started listening to a
+ possibly privileged port and after the PID file has been created
+ if specified by option <literal>-u</literal>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry><term>-c <replaceable>config</replaceable></term>
+ <listitem><para>
+ Specifies config filename. Configuration is in XML
+ and is only supported if the YAZ proxy is compiled with
+ libxml2.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+<refsect1>
+ <title>EXAMPLES</title>
+ <para>
+ The following command starts the proxy, listening on port
+ 9000, with its default backend target set to the Library of
+ Congress bibliographic server:
+ </para>
+ <screen>
+ $ yaz-proxy -t z3950.loc.gov:7090 @:9000
+ </screen>
+ <para>
+ The LOC target is sometimes very slow. You can connect to
+ it using yaz-client as follows:
+ </para>
+ <screen>
+ $ yaz-client localhost:9000/voyager
+ Connecting...Ok.
+ Sent initrequest.
+ Connection accepted by target.
+ ID : 34
+ Name : Voyager LMS - Z39.50 Server
+ Version: 1.13
+ Options: search present
+ Elapsed: 7.131197
+ Z> f computer
+ Sent searchRequest.
+ Received SearchResponse.
+ Search was a success.
+ Number of hits: 10000
+ records returned: 0
+ Elapsed: 6.695174
+ Z> f computer
+ Sent searchRequest.
+ Received SearchResponse.
+ Search was a success.
+ Number of hits: 10000
+ records returned: 0
+ Elapsed: 0.001417
+ </screen>
+ <para>
+ In this test, the second search was more than 4000 times faster
+ than the first, because the proxy cached the result of the first
+ search and noticed that the second was the same.
+ </para>
+ <para>
+ The YAZ command-line client,
+ <command>yaz-client</command>,
+ allows you to set the proxy address by specifying option -p. In
+ that case, the actual backend target is specified as part of the
+ Initialize Request.
+ </para>
+ <para>Suppose you have a proxy running on localhost,
+ port 9000 and wish to connect to Index Data's test target at
+ <literal>indexdata.dk:210/gils</literal> you could use:
+ <screen>
+ yaz-client -p localhost:9000 indexdata.dk:210/gils
+ </screen>
+ Since port 210 is the default, the port can be omitted:
+ <screen>
+ yaz-client -p localhost:9000 indexdata.dk/gils
+ </screen>
+ </para>
+</refsect1>
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document: "proxy.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
--- /dev/null
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/html/docbook.dsl"
+ CDATA DSSSL>
+]>
+<!--
+ $Id: yazhtml.dsl.in,v 1.1 2004-04-11 11:36:53 adam Exp $
+-->
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+(define %use-id-as-filename% #t)
+(define %output-dir% "html")
+(define %html-ext% ".html")
+(define %stylesheet% "yaz.css")
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="docbook.dsl">
+</style-sheet>
+
+<!--
+Local Variables:
+mode: scheme
+End:
+-->
--- /dev/null
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/html/docbook.dsl"
+ CDATA DSSSL>
+]>
+<!--
+ $Id: yazphp.dsl.in,v 1.1 2004-04-11 11:36:53 adam Exp $
+-->
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+(define %use-id-as-filename% #t)
+(define %output-dir% "php")
+(define %html-ext% ".php")
+(define %shade-verbatim% #t)
+
+(define newline "\U-000D")
+
+(define (html-document title-sosofo body-sosofo)
+ (let* (;; Let's look these up once, so that we can avoid calculating
+ ;; them over and over again.
+ (prev (prev-chunk-element))
+ (next (next-chunk-element))
+ (prevm (prev-major-component-chunk-element))
+ (nextm (next-major-component-chunk-element))
+ (navlist (list prev next prevm nextm))
+
+ ;; Let's make it possible to control the output even in the
+ ;; nochunks case. Note: in the nochunks case, (chunk?) will
+ ;; return #t for only the root element.
+ (make-entity? (and (or (not nochunks) rootchunk)
+ (chunk?)))
+
+ (make-head? (or make-entity?
+ (and nochunks
+ (node-list=? (current-node)
+ (sgml-root-element)))))
+ (doc-sosofo
+ (if make-head?
+ (make sequence
+ (make formatting-instruction data:
+ (string-append "<" "?php "
+ newline
+ "require \"../../id_common.inc\";"
+ newline
+ "id_header(\""
+ )
+ )
+ title-sosofo
+ (make formatting-instruction data:
+ (string-append "\");"
+ newline
+ "?" ">"
+ )
+ )
+ (header-navigation (current-node) navlist)
+ body-sosofo
+ (footer-navigation (current-node) navlist)
+ (make formatting-instruction data:
+ (string-append "<" "?php id_footer() ?>")
+ )
+ )
+ body-sosofo
+ )
+ )
+ )
+ (if make-entity?
+ (make entity
+ system-id: (html-entity-file (html-file))
+ (if %html-pubid%
+ (make document-type
+ name: "HTML"
+ public-id: %html-pubid%)
+ (empty-sosofo))
+ doc-sosofo)
+ (if (node-list=? (current-node) (sgml-root-element))
+ (make sequence
+ (if %html-pubid%
+ (make document-type
+ name: "HTML"
+ public-id: %html-pubid%)
+ (empty-sosofo))
+ doc-sosofo)
+ doc-sosofo)
+ )
+ )
+ )
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="docbook.dsl">
+</style-sheet>
+
+<!--
+Local Variables:
+mode: scheme
+End:
+-->
--- /dev/null
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/print/docbook.dsl"
+ CDATA DSSSL>
+]>
+<!--
+ $Id: yazprint.dsl.in,v 1.1 2004-04-11 11:36:53 adam Exp $
+-->
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="docbook.dsl">
+</style-sheet>
+
+<!--
+Local Variables:
+mode: scheme
+End:
+-->
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "@DTD_DIR@/docbookx.dtd" [
+ <!ENTITY chap-introduction SYSTEM "introduction.xml">
+ <!ENTITY chap-installation SYSTEM "installation.xml">
+ <!ENTITY chap-proxy SYSTEM "proxy.xml">
+ <!ENTITY yaz-proxy-ref SYSTEM "yaz-proxy-ref.xml">
+ <!ENTITY app-license SYSTEM "license.xml">
+]>
+<!-- $Id: yazproxy.xml.in,v 1.1 2004-04-11 11:36:52 adam Exp $ -->
+<book id="yazpp">
+ <bookinfo>
+ <title>YAZ++ User's Guide and Reference</title>
+ <authorgroup>
+ <author><firstname>Mike</firstname><surname>Taylor</surname></author>
+ <author><firstname>Adam</firstname><surname>Dickmeiss</surname></author>
+ </authorgroup>
+ <copyright>
+ <year>1999</year>
+ <year>2000</year>
+ <year>2001</year>
+ <year>2002</year>
+ <year>2003</year>
+ <year>2004</year>
+ <holder>Index Data Aps and Mike Taylor</holder>
+ </copyright>
+ <abstract>
+ <simpara>
+ <ulink url="http://www.indexdata.dk/yazproxy/">YAZ proxy</ulink>
+ is a powerful general purpose Z39.50/SRW/SRU proxy.
+ </simpara>
+ <simpara>
+ This manual covers version @VERSION@.
+ </simpara>
+ <simpara>
+ CVS ID: $Id: yazproxy.xml.in,v 1.1 2004-04-11 11:36:52 adam Exp $
+ </simpara>
+ <simpara>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="id.png" format="PNG"/>
+ </imageobject>
+ </inlinemediaobject>
+ </simpara>
+ </abstract>
+ </bookinfo>
+
+ &chap-introduction;
+ &chap-installation;
+ &chap-proxy;
+ &chap-api;
+ &app-license;
+</book>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-local-catalogs: nil
+sgml-namecase-general:t
+End:
+-->
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:marc="http://www.loc.gov/MARC21/slim"
+ xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ exclude-result-prefixes="marc oai_dc">
+ <xsl:import href="MARC21slimUtils.xsl"/>
+ <xsl:output method="xml" indent="yes"/>
+<!-- modification log
+ NT 01/04: added collection level element
+ and removed attributes
+
+-->
+ <xsl:template match="/">
+ <xsl:choose>
+ <xsl:when test="marc:collection">
+ <!-- nt fix 1/04 -->
+ <dc:dcCollection>
+ <xsl:for-each select="marc:collection">
+ <oai_dc:dc xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+ <xsl:apply-templates select="marc:record"/>
+ </oai_dc:dc>
+ </xsl:for-each>
+ </dc:dcCollection>
+ </xsl:when>
+ <xsl:otherwise>
+ <oai_dc:dc xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+ <xsl:apply-templates select="marc:record"/>
+ </oai_dc:dc>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="marc:record">
+ <xsl:variable name="leader" select="marc:leader"/>
+ <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+ <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+ <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>
+
+ <xsl:for-each select="marc:datafield[@tag=245]">
+ <dc:title>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abfghk</xsl:with-param>
+ </xsl:call-template>
+ </dc:title>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=100]|marc:datafield[@tag=110]|marc:datafield[@tag=111]|marc:datafield[@tag=700]|marc:datafield[@tag=710]|marc:datafield[@tag=711]|marc:datafield[@tag=720]">
+ <dc:creator>
+ <xsl:value-of select="normalize-space(.)"/>
+ </dc:creator>
+ </xsl:for-each>
+
+ <dc:type>
+ <xsl:if test="$leader7='c'">
+ <!-- nt fix 1/04 -->
+ <!--<xsl:attribute name="collection">yes</xsl:attribute>-->
+ <xsl:text>collection</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+ <!-- nt fix 1/04 -->
+ <!--<xsl:attribute name="manuscript">yes</xsl:attribute> -->
+ <xsl:text>manuscript</xsl:text>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+ <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+ <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+ <xsl:when test="$leader6='i' or $leader6='j'">sound recording</xsl:when>
+ <xsl:when test="$leader6='k'">still image</xsl:when>
+ <xsl:when test="$leader6='g'">moving image</xsl:when>
+ <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+ <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+ <xsl:when test="$leader6='p'">mixed material</xsl:when>
+ </xsl:choose>
+ </dc:type>
+
+ <xsl:for-each select="marc:datafield[@tag=655]">
+ <dc:type>
+ <xsl:value-of select="normalize-space(.)"/>
+ </dc:type>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]">
+ <dc:publisher>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </dc:publisher>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='c']">
+ <dc:date>
+ <xsl:value-of select="."/>
+ </dc:date>
+ </xsl:for-each>
+
+ <dc:language>
+ <xsl:value-of select="substring($controlField008,36,3)"/>
+ </dc:language>
+
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q']">
+ <dc:format>
+ <xsl:value-of select="."/>
+ </dc:format>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=520]">
+ <dc:description>
+ <!-- nt fix 01/04 -->
+ <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+ </dc:description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=521]">
+ <dc:description>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </dc:description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[500<@tag][@tag<=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
+ <dc:description>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </dc:description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=600]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=610]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=611]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=630]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=650]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=653]">
+ <dc:subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </dc:subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=752]">
+ <dc:coverage>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </dc:coverage>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=530]">
+ <!-- nt 01/04 attribute fix -->
+ <dc:relation>
+ <!--<xsl:attribute name="type">original</xsl:attribute>-->
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdu</xsl:with-param>
+ </xsl:call-template>
+ </dc:relation>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]|marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=770]|marc:datafield[@tag=772]|marc:datafield[@tag=773]|marc:datafield[@tag=774]|marc:datafield[@tag=775]|marc:datafield[@tag=776]|marc:datafield[@tag=777]|marc:datafield[@tag=780]|marc:datafield[@tag=785]|marc:datafield[@tag=786]|marc:datafield[@tag=787]">
+ <dc:relation>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ot</xsl:with-param>
+ </xsl:call-template>
+ </dc:relation>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856]">
+ <dc:identifier>
+ <xsl:value-of select="marc:subfield[@code='u']"/>
+ </dc:identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=506]">
+ <dc:rights>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </dc:rights>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=540]">
+ <dc:rights>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </dc:rights>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<xsl:stylesheet version="1.0" xmlns:xlink="http://www.w3.org/TR/xlink" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns="http://www.loc.gov/mods/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">\r
+ <xsl:include href="MARC21slimUtils.xsl"/>\r
+ <xsl:output method="xml" indent="yes"/>\r
+ \r
+ <xsl:template match="/">\r
+ <collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/mods/ http://www.loc.gov/standards/marcxml/schema/mods.xsd">\r
+ <xsl:apply-templates/>\r
+ </collection>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:record">\r
+ <mods>\r
+ <xsl:variable name="leader" select="marc:leader"/>\r
+ <xsl:variable name="leader6" select="substring($leader,7,1)"/>\r
+ <xsl:variable name="leader7" select="substring($leader,8,1)"/>\r
+ <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>\r
+\r
+ <xsl:variable name="typeOf008">\r
+ <xsl:choose>\r
+ <xsl:when test="$leader6='a'">\r
+ <xsl:choose>\r
+ <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>\r
+ <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when> \r
+ </xsl:choose>\r
+ </xsl:when>\r
+ <xsl:when test="$leader6='t'">BK</xsl:when>\r
+ <xsl:when test="$leader6='p'">MM</xsl:when>\r
+ <xsl:when test="$leader6='m'">CF</xsl:when> \r
+ <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when> \r
+ <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when> \r
+ <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'">MU</xsl:when> \r
+ </xsl:choose>\r
+ </xsl:variable>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=245]">\r
+ <titleInfo>\r
+ <xsl:variable name="title">\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abfghk</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:variable>\r
+ <xsl:choose>\r
+ <xsl:when test="@ind2>0">\r
+ <nonSort>\r
+ <xsl:value-of select="substring($title,1,@ind2)"/>\r
+ </nonSort>\r
+ <title>\r
+ <xsl:value-of select="substring($title,@ind2+1)"/>\r
+ </title>\r
+ </xsl:when>\r
+ <xsl:otherwise>\r
+ <title>\r
+ <xsl:value-of select="$title"/>\r
+ </title>\r
+ </xsl:otherwise>\r
+ </xsl:choose>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=210]">\r
+ <titleInfo type="abbreviated">\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ </titleInfo>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=242]">\r
+ <titleInfo type="translated">\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abh</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=246]">\r
+ <titleInfo type="alternative">\r
+ <xsl:for-each select="marc:subfield[@code='i']">\r
+ <xsl:attribute name="displayLabel">\r
+ <xsl:value-of select="text()"/>\r
+ </xsl:attribute>\r
+ </xsl:for-each>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abfh</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/> \r
+ </titleInfo>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=130]|marc:datafield[@tag=240]|marc:datafield[@tag=730][@ind2!=2]">\r
+ <titleInfo type="uniform">\r
+ <title>\r
+ <xsl:variable name="str">\r
+ <xsl:for-each select="marc:subfield">\r
+ <xsl:if test="(contains('adfhklmor',@code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">\r
+ <xsl:value-of select="text()"/><xsl:text> </xsl:text>\r
+ </xsl:if>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>\r
+ </title>\r
+ <xsl:call-template name="part"/> \r
+ </titleInfo>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=740][@ind2!=2]">\r
+ <titleInfo type="alternative">\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ah</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/> \r
+ </titleInfo>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=100]">\r
+ <name type="personal">\r
+ <xsl:call-template name="nameABCDQ"/>\r
+ <xsl:call-template name="affiliation"/>\r
+ <role>creator</role>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=110]">\r
+ <name type="corporate">\r
+ <xsl:call-template name="nameABCDN"/>\r
+ <role>creator</role>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=111]">\r
+ <name type="conference">\r
+ <xsl:call-template name="nameACDEQ"/>\r
+ <role>creator</role>\r
+ <xsl:for-each select="marc:subfield[@code='4']">\r
+ <role><xsl:value-of select="."/></role>\r
+ </xsl:for-each>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=700][not(marc:subfield[@code='t'])]">\r
+ <name type="personal">\r
+ <xsl:call-template name="nameABCDQ"/>\r
+ <xsl:call-template name="affiliation"/>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=710][not(marc:subfield[@code='t'])]">\r
+ <name type="corporate">\r
+ <xsl:call-template name="nameABCDN"/>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=711][not(marc:subfield[@code='t'])]">\r
+ <name type="conference">\r
+ <xsl:call-template name="nameACDEQ"/>\r
+ <xsl:for-each select="marc:subfield[@code='4']">\r
+ <role><xsl:value-of select="."/></role>\r
+ </xsl:for-each>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=720][not(marc:subfield[@code='t'])]">\r
+ <name>\r
+ <xsl:if test="@ind1=1">\r
+ <xsl:attribute name="type">personal</xsl:attribute>\r
+ </xsl:if>\r
+ <namePart>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </namePart>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ </xsl:for-each>\r
+\r
+ <typeOfResource> \r
+ <xsl:if test="$leader7='c'">\r
+ <xsl:attribute name="collection">yes</xsl:attribute>\r
+ </xsl:if>\r
+ <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">\r
+ <xsl:attribute name="manuscript">yes</xsl:attribute>\r
+ </xsl:if>\r
+\r
+ <xsl:choose>\r
+ <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>\r
+ <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>\r
+ <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>\r
+ <xsl:when test="$leader6='i' or $leader6='j'">sound recording</xsl:when>\r
+ <xsl:when test="$leader6='k'">still image</xsl:when>\r
+ <xsl:when test="$leader6='g'">moving image</xsl:when>\r
+ <xsl:when test="$leader6='r'">three dimensional object</xsl:when>\r
+ <xsl:when test="$leader6='m'">software, multimedia</xsl:when>\r
+ <xsl:when test="$leader6='p'">mixed material</xsl:when>\r
+ </xsl:choose>\r
+ </typeOfResource>\r
+\r
+ <xsl:if test="substring($controlField008,26,1)='d'">\r
+ <genre authority="marc">globe</genre>\r
+ </xsl:if>\r
+ \r
+ <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">\r
+ <genre authority="marc">remote sensing image</genre>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='MP'">\r
+ <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">\r
+ <genre authority="marc">map</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">\r
+ <genre authority="marc">atlas</genre>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='SE'">\r
+ <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-21='d'">\r
+ <genre authority="marc">database</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-21='l'"> \r
+ <genre authority="marc">loose-leaf</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-21='m'">\r
+ <genre authority="marc">series</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-21='n'">\r
+ <genre authority="marc">newspaper</genre> \r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-21='p'">\r
+ <genre authority="marc">periodical</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-21='w'">\r
+ <genre authority="marc">web site</genre>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">\r
+ <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="contains($controlField008-24,'a')">\r
+ <genre authority="marc">abstract or summary</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'b')">\r
+ <genre authority="marc">bibliography</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'c')">\r
+ <genre authority="marc">catalog</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'d')">\r
+ <genre authority="marc">dictionary</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'e')">\r
+ <genre authority="marc">encyclopedia</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'f')">\r
+ <genre authority="marc">handbook</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'g')">\r
+ <genre authority="marc">legal article</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'i')">\r
+ <genre authority="marc">index</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'k')">\r
+ <genre authority="marc">discography</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'l')">\r
+ <genre authority="marc">legislation</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'m')">\r
+ <genre authority="marc">theses</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'n')">\r
+ <genre authority="marc">survey of literature</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'o')">\r
+ <genre authority="marc">review</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'p')">\r
+ <genre authority="marc">programmed text</genre>\r
+ </xsl:when> \r
+ <xsl:when test="contains($controlField008-24,'q')">\r
+ <genre authority="marc">filmography</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'r')">\r
+ <genre authority="marc">directory</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'s')">\r
+ <genre authority="marc">statistics</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'t')">\r
+ <genre authority="marc">technical report</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'v')">\r
+ <genre authority="marc">legal case and case notes</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'w')">\r
+ <genre authority="marc">law report or digest</genre>\r
+ </xsl:when>\r
+ <xsl:when test="contains($controlField008-24,'z')">\r
+ <genre authority="marc">treaty</genre>\r
+ </xsl:when> \r
+ </xsl:choose>\r
+ <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-29='1'">\r
+ <genre authority="marc">conference publication</genre>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='CF'">\r
+ <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-26='a'">\r
+ <genre authority="marc">numeric data</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-26='e'">\r
+ <genre authority="marc">database</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-26='f'">\r
+ <genre authority="marc">font</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-26='g'">\r
+ <genre authority="marc">game</genre>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='BK'">\r
+ <xsl:if test="substring($controlField008,25,1)='j'">\r
+ <genre authority="marc">patent</genre>\r
+ </xsl:if>\r
+ <xsl:if test="substring($controlField008,31,1)='1'">\r
+ <genre authority="marc">festschrift</genre>\r
+ </xsl:if>\r
+\r
+ <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"/>\r
+ <xsl:if test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">\r
+ <genre authority="marc">biography</genre>\r
+ </xsl:if>\r
+\r
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-33='e'">\r
+ <genre authority="marc">essay</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='d'">\r
+ <genre authority="marc">drama</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='c'">\r
+ <genre authority="marc">comic strip</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='l'">\r
+ <genre authority="marc">fiction</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='h'">\r
+ <genre authority="marc">humor, satire</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='i'">\r
+ <genre authority="marc">letter</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='f'">\r
+ <genre authority="marc">novel</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='j'">\r
+ <genre authority="marc">short story</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='s'">\r
+ <genre authority="marc">speech</genre>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='MU'">\r
+ <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"/>\r
+ <xsl:if test="contains($controlField008-30-31,'b')">\r
+ <genre authority="marc">biography</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'c')">\r
+ <genre authority="marc">conference publication</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'d')">\r
+ <genre authority="marc">drama</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'e')">\r
+ <genre authority="marc">essay</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'f')">\r
+ <genre authority="marc">fiction</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'o')">\r
+ <genre authority="marc">folktale</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'h')">\r
+ <genre authority="marc">history</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'k')">\r
+ <genre authority="marc">humor, satire</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'m')">\r
+ <genre authority="marc">memoir</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'p')">\r
+ <genre authority="marc">poetry</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'r')">\r
+ <genre authority="marc">rehersal</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'g')">\r
+ <genre authority="marc">reporting</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'s')">\r
+ <genre authority="marc">sound</genre>\r
+ </xsl:if>\r
+ <xsl:if test="contains($controlField008-30-31,'l')">\r
+ <genre authority="marc">speech</genre>\r
+ </xsl:if>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$typeOf008='VM'">\r
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-33='a'">\r
+ <genre authority="marc">art original</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='b'">\r
+ <genre authority="marc">kit</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='c'">\r
+ <genre authority="marc">art reproduction</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='d'">\r
+ <genre authority="marc">diorama</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='f'">\r
+ <genre authority="marc">filmstrip</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='g'">\r
+ <genre authority="marc">legal article</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='i'">\r
+ <genre authority="marc">picture</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='k'">\r
+ <genre authority="marc">graphic</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='l'">\r
+ <genre authority="marc">technical drawing</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='m'">\r
+ <genre authority="marc">motion picture</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='n'">\r
+ <genre authority="marc">chart</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='o'">\r
+ <genre authority="marc">flash card</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='p'">\r
+ <genre authority="marc">microscope slide</genre>\r
+ </xsl:when> \r
+ <xsl:when test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">\r
+ <genre authority="marc">model</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='r'">\r
+ <genre authority="marc">realia</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='s'">\r
+ <genre authority="marc">slide</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='t'">\r
+ <genre authority="marc">transparency</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='v'">\r
+ <genre authority="marc">videorecording</genre>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-33='w'">\r
+ <genre authority="marc">toy</genre>\r
+ </xsl:when> \r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=655]">\r
+ <genre authority="marc">\r
+ <xsl:attribute name="authority">\r
+ <xsl:value-of select="marc:subfield[@code='2']"/>\r
+ </xsl:attribute>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abvxyz</xsl:with-param>\r
+ <xsl:with-param name="delimeter">-</xsl:with-param>\r
+ </xsl:call-template>\r
+ </genre>\r
+ </xsl:for-each>\r
+\r
+ <publicationInfo>\r
+ <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"/>\r
+ \r
+ <xsl:if test="translate($MARCpublicationCode,'|','')">\r
+ <placeCode authority="marc">\r
+ <xsl:value-of select="$MARCpublicationCode"/>\r
+ </placeCode>\r
+ </xsl:if>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">\r
+ <placeCode authority="iso3166">\r
+ <xsl:value-of select="."/>\r
+ </placeCode>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a' or @code='b' or @code='c' or @code='g']">\r
+ <xsl:choose>\r
+ <xsl:when test="@code='a'">\r
+ <place>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </place>\r
+ </xsl:when>\r
+ <xsl:when test="@code='b'">\r
+ <publisher>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </publisher>\r
+ </xsl:when>\r
+ <xsl:when test="@code='c'">\r
+ <dateIssued>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </dateIssued>\r
+ </xsl:when>\r
+ <xsl:when test="@code='g'">\r
+ <dateCreated>\r
+ <xsl:value-of select="."/>\r
+ </dateCreated> \r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:for-each>\r
+\r
+ <xsl:variable name="dataField260c">\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"/>\r
+ </xsl:call-template>\r
+ </xsl:variable>\r
+\r
+ <xsl:variable name="controlField008-7-10" select="normalize-space(substring($controlField008, 8, 4))"/>\r
+ <xsl:variable name="controlField008-11-14" select="normalize-space(substring($controlField008, 12, 4))"/>\r
+ <xsl:variable name="controlField008-6" select="normalize-space(substring($controlField008, 7, 1))"/>\r
+ \r
+ <xsl:if test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">\r
+ <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">\r
+ <dateIssued encoding="marc">\r
+ <xsl:value-of select="$controlField008-7-10"/>\r
+ </dateIssued>\r
+ </xsl:if>\r
+ </xsl:if>\r
+ \r
+ <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">\r
+ <xsl:if test="$controlField008-7-10">\r
+ <dateIssued encoding="marc" point="start">\r
+ <xsl:value-of select="$controlField008-7-10"/>\r
+ </dateIssued>\r
+ </xsl:if>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">\r
+ <xsl:if test="$controlField008-11-14">\r
+ <dateIssued encoding="marc" point="end">\r
+ <xsl:value-of select="$controlField008-11-14"/>\r
+ </dateIssued>\r
+ </xsl:if>\r
+ </xsl:if>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">\r
+ <dateCaptured encoding="iso8601">\r
+ <xsl:value-of select="."/>\r
+ </dateCaptured>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">\r
+ <dateCaptured encoding="iso8601" point="start">\r
+ <xsl:value-of select="."/>\r
+ </dateCaptured>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">\r
+ <dateCaptured encoding="iso8601" point="end">\r
+ <xsl:value-of select="."/>\r
+ </dateCaptured>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">\r
+ <edition>\r
+ <xsl:value-of select="."/>\r
+ </edition>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:leader">\r
+ <issuance>\r
+ <xsl:choose>\r
+ <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">monographic</xsl:when>\r
+ <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">continuing</xsl:when> \r
+ </xsl:choose>\r
+ </issuance>\r
+ </xsl:for-each> \r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">\r
+ <frequency>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </frequency>\r
+ </xsl:for-each> \r
+ </publicationInfo>\r
+\r
+\r
+ <xsl:for-each select="marc:controlfield[@tag=041]">\r
+ <xsl:for-each select="marc:subfield[@code='a' or @code='d' or @code='e']">\r
+ <language>\r
+ <xsl:choose>\r
+ <xsl:when test="../marc:subfield[@code='2']">\r
+ <xsl:attribute name="authority">rfc3066</xsl:attribute>\r
+ </xsl:when>\r
+ <xsl:otherwise>\r
+ <xsl:attribute name="authority">iso639-2b</xsl:attribute> \r
+ </xsl:otherwise>\r
+ </xsl:choose>\r
+ <xsl:value-of select="text()"/>\r
+ </language>\r
+ </xsl:for-each>\r
+ </xsl:for-each> \r
+\r
+ <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"/>\r
+ <xsl:if test="$controlField008-35-37">\r
+ <language authority="iso639-2b">\r
+ <xsl:value-of select="substring($controlField008,36,3)"/>\r
+ </language>\r
+ </xsl:if>\r
+\r
+ <xsl:variable name="physicalDescription">\r
+ <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a' or substring(.,12,1)='b']">\r
+ <digitalOrigin>reformatted digital</digitalOrigin>\r
+ </xsl:if>\r
+\r
+ <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"/>\r
+ <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>\r
+\r
+ <xsl:variable name="check008-23">\r
+ <xsl:if test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">\r
+ <xsl:value-of select="true()"/>\r
+ </xsl:if>\r
+ </xsl:variable>\r
+\r
+ <xsl:variable name="check008-29">\r
+ <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">\r
+ <xsl:value-of select="true()"/>\r
+ </xsl:if>\r
+ </xsl:variable>\r
+\r
+ <xsl:choose>\r
+ <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">\r
+ <form><controlled>braille</controlled></form>\r
+ </xsl:when>\r
+ <xsl:when test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">\r
+ <form><controlled>electronic</controlled></form>\r
+ </xsl:when>\r
+ <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">\r
+ <form><controlled>microfiche</controlled></form>\r
+ </xsl:when>\r
+ <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">\r
+ <form><controlled>microfilm</controlled></form>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">\r
+ <internetMediaType>\r
+ <xsl:value-of select="."/>\r
+ </internetMediaType>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">\r
+ <form>\r
+ <unControlled>\r
+ <xsl:value-of select="."/>\r
+ </unControlled>\r
+ </form>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=300]">\r
+ <extent>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abce</xsl:with-param>\r
+ </xsl:call-template>\r
+ </extent>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+\r
+ <xsl:if test="string-length(normalize-space($physicalDescription))">\r
+ <physicalDescription>\r
+ <xsl:copy-of select="$physicalDescription"/>\r
+ </physicalDescription>\r
+ </xsl:if>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=520]">\r
+ <abstract>\r
+ <xsl:call-template name="uri"/>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </abstract>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=505]">\r
+ <tableOfContents>\r
+ <xsl:call-template name="uri"/>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">agrt</xsl:with-param>\r
+ </xsl:call-template>\r
+ </tableOfContents>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=521]">\r
+ <targetAudience>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </targetAudience>\r
+ </xsl:for-each>\r
+\r
+ <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">\r
+ <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$controlField008-22='d'">\r
+ <targetAudience>adolescent</targetAudience>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-22='e'">\r
+ <targetAudience>adult</targetAudience>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-22='g'">\r
+ <targetAudience>general</targetAudience>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">\r
+ <targetAudience>juvenile</targetAudience>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-22='a'">\r
+ <targetAudience>preschool</targetAudience>\r
+ </xsl:when>\r
+ <xsl:when test="$controlField008-22='f'">\r
+ <targetAudience>specialized</targetAudience>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:if>\r
+\r
+ <!-- Not in mapping but in conversion -->\r
+ <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">\r
+ <note type="statement of responsibility">\r
+ <xsl:value-of select="."/>\r
+ </note>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=500]">\r
+ <note>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ <xsl:call-template name="uri"/>\r
+ </note>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=511]">\r
+ <note type="performers">\r
+ <xsl:call-template name="uri"/>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </note>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=518]">\r
+ <note type="venue">\r
+ <xsl:call-template name="uri"/>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </note>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=506 or @tag=507 or @tag=508 or @tag=510 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=530 or @tag=533 or @tag=534 or @tag=535 or @tag=536 or @tag=538 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=583 or @tag=584 or @tag=585 or @tag=586]">\r
+ <note>\r
+ <xsl:call-template name="uri"/>\r
+ <xsl:variable name="str">\r
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">\r
+ <xsl:value-of select="."/><xsl:text> </xsl:text>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>\r
+ </note>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">\r
+ <cartographics>\r
+ <coordinates>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">defg</xsl:with-param>\r
+ </xsl:call-template>\r
+ </coordinates>\r
+ </cartographics>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=255]">\r
+ <cartographics>\r
+ <xsl:for-each select="marc:subfield[@code='c']">\r
+ <coordinates>\r
+ <xsl:value-of select="."/>\r
+ </coordinates>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <scale>\r
+ <xsl:value-of select="."/>\r
+ </scale>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <projection>\r
+ <xsl:value-of select="."/>\r
+ </projection> \r
+ </xsl:for-each>\r
+ </cartographics>\r
+ </xsl:for-each>\r
+\r
+ <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"/>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=752]">\r
+ <subject>\r
+ <hierarchicalGeographic>\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <country>\r
+ <xsl:value-of select="."/>\r
+ </country>\r
+ </xsl:for-each> \r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <state>\r
+ <xsl:value-of select="."/>\r
+ </state>\r
+ </xsl:for-each> \r
+ <xsl:for-each select="marc:subfield[@code='c']">\r
+ <county>\r
+ <xsl:value-of select="."/>\r
+ </county>\r
+ </xsl:for-each> \r
+ <xsl:for-each select="marc:subfield[@code='d']">\r
+ <city>\r
+ <xsl:value-of select="."/>\r
+ </city>\r
+ </xsl:for-each> \r
+ </hierarchicalGeographic>\r
+ </subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=050]">\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <classification authority="lcc">\r
+ <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"/>\r
+ <xsl:text> </xsl:text>\r
+ <xsl:value-of select="text()"/>\r
+ </classification>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">\r
+ <classification authority="lcc">\r
+ <xsl:value-of select="text()"/>\r
+ </classification>\r
+ </xsl:for-each>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=082]">\r
+ <classification authority="ddc">\r
+ <xsl:if test="marc:subfield[@code='2']">\r
+ <xsl:attribute name="edition">\r
+ <xsl:value-of select="marc:subfield[@code='2']"/>\r
+ </xsl:attribute>\r
+ </xsl:if>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=080]">\r
+ <classification authority="udc">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abx</xsl:with-param>\r
+ </xsl:call-template>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=060]">\r
+ <classification authority="nlm">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">\r
+ <classification authority="sudocs">\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">\r
+ <classification authority="candoc">\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=086]">\r
+ <classification>\r
+ <xsl:attribute name="authority">\r
+ <xsl:value-of select="marc:subfield[@code='2']"/>\r
+ </xsl:attribute> \r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=084]">\r
+ <classification>\r
+ <xsl:attribute name="authority">\r
+ <xsl:value-of select="marc:subfield[@code='2']"/>\r
+ </xsl:attribute>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </classification>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=440]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">av</xsl:with-param>\r
+ </xsl:call-template>\r
+ <xsl:call-template name="part"/>\r
+ </title>\r
+ </titleInfo>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">av</xsl:with-param>\r
+ </xsl:call-template>\r
+ <xsl:call-template name="part"/>\r
+ </title>\r
+ </titleInfo>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=534]">\r
+ <relatedItem type="original">\r
+ <xsl:call-template name="relatedTitle"/>\r
+ <xsl:call-template name="relatedName"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ <xsl:for-each select="marc:subfield[@code='z']">\r
+ <identifier type="isbn">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+ <xsl:call-template name="relatedNote"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">\r
+ <relatedItem>\r
+ <xsl:call-template name="constituentOrRelatedType"/>\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">g</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ <name type="personal">\r
+ <namePart>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">abcq</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">g</xsl:with-param>\r
+ </xsl:call-template> \r
+ </namePart>\r
+ <xsl:call-template name="nameDate"/>\r
+ <xsl:for-each select="marc:subfield[@code='e']">\r
+ <role>\r
+ <xsl:value-of select="."/>\r
+ </role>\r
+ </xsl:for-each>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">\r
+ <relatedItem>\r
+ <xsl:call-template name="constituentOrRelatedType"/>\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">dg</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="relatedPart"/>\r
+ </titleInfo>\r
+ <name type="corporate">\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <xsl:variable name="tempNamePart">\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">c</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">dgn</xsl:with-param>\r
+ </xsl:call-template> \r
+ </xsl:variable>\r
+ <xsl:if test="normalize-space($tempNamePart)">\r
+ <namePart>\r
+ <xsl:value-of select="$tempNamePart"/>\r
+ </namePart>\r
+ </xsl:if>\r
+ <xsl:for-each select="marc:subfield[@code='e']">\r
+ <role>\r
+ <xsl:value-of select="."/>\r
+ </role>\r
+ </xsl:for-each>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">\r
+ <relatedItem>\r
+ <xsl:call-template name="constituentOrRelatedType"/>\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">g</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="relatedPart"/>\r
+ </titleInfo>\r
+ <name type="conference">\r
+ <namePart>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">aqdc</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">gn</xsl:with-param>\r
+ </xsl:call-template> \r
+ </namePart>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">\r
+ <relatedItem>\r
+ <xsl:call-template name="constituentOrRelatedType"/>\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ <xsl:call-template name="relatedForm"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">\r
+ <relatedItem>\r
+ <xsl:call-template name="constituentOrRelatedType"/>\r
+ <titleInfo>\r
+ <title> \r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ <xsl:call-template name="relatedForm"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">\r
+ <relatedItem type="series">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=775]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">\r
+ <relatedItem type="related">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">\r
+ <relatedItem type="constituent">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">\r
+ <relatedItem type="host">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=776]">\r
+ <relatedItem type="reproduction">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=780]">\r
+ <relatedItem type="preceding">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=785]">\r
+ <relatedItem type="succeeding">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=786]">\r
+ <relatedItem type="original">\r
+ <xsl:call-template name="relatedItem76X-78X"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=800]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">g</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ <name type="personal">\r
+ <namePart>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString">\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">abcq</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">g</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ <xsl:call-template name="nameDate"/>\r
+ <xsl:for-each select="marc:subfield[@code='e']">\r
+ <role>\r
+ <xsl:value-of select="."/>\r
+ </role>\r
+ </xsl:for-each>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ </relatedItem>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=810]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">dg</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="relatedPart"/>\r
+ </titleInfo>\r
+ <name type="corporate">\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <namePart>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">c</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">dgn</xsl:with-param>\r
+ </xsl:call-template> \r
+ </namePart>\r
+ <xsl:for-each select="marc:subfield[@code='e']">\r
+ <role>\r
+ <xsl:value-of select="."/>\r
+ </role>\r
+ </xsl:for-each>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=811]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">g</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="relatedPart"/>\r
+ </titleInfo>\r
+ <name type="conference">\r
+ <namePart>\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="anyCodes">aqdc</xsl:with-param>\r
+ <xsl:with-param name="axis">t</xsl:with-param>\r
+ <xsl:with-param name="beforeCodes">gn</xsl:with-param>\r
+ </xsl:call-template> \r
+ </namePart>\r
+ </name>\r
+ <xsl:call-template name="relatedForm"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=830]">\r
+ <relatedItem type="series">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>\r
+ </xsl:call-template>\r
+ </title>\r
+ <xsl:call-template name="part"/>\r
+ </titleInfo>\r
+ <xsl:call-template name="relatedForm"/>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=856][@ind2=2]/marc:subfield[@code='q']">\r
+ <relatedItem>\r
+ <internetMediaType>\r
+ <xsl:value-of select="."/>\r
+ </internetMediaType>\r
+ </relatedItem> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=020]/marc:subfield[@code='a']">\r
+ <identifier type="isbn">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=0]/marc:subfield[@code='a']">\r
+ <identifier type="isrc">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=2]/marc:subfield[@code='a']">\r
+ <identifier type="ismn">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=022]/marc:subfield[@code='a']">\r
+ <identifier type="issn">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=010]/marc:subfield[@code='a']">\r
+ <identifier type="lccn">\r
+ <xsl:value-of select="normalize-space(text())"/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=028]">\r
+ <identifier>\r
+ <xsl:attribute name="type">\r
+ <xsl:choose>\r
+ <xsl:when test="@ind1=0">issue number</xsl:when>\r
+ <xsl:when test="@ind1=1">matrix number</xsl:when>\r
+ <xsl:when test="@ind1=2">music plate</xsl:when>\r
+ <xsl:when test="@ind1=3">music publisher</xsl:when>\r
+ <xsl:when test="@ind1=4">videorecording identifier</xsl:when>\r
+ </xsl:choose>\r
+ </xsl:attribute>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </identifier>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=4]">\r
+ <identifier type="sici">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='u']">\r
+ <identifier>\r
+ <xsl:attribute name="type">\r
+ <xsl:choose>\r
+ <xsl:when test="starts-with(.,'urn:doi') or starts-with(.,'doi:')">doi</xsl:when>\r
+ <xsl:otherwise>uri</xsl:otherwise>\r
+ </xsl:choose>\r
+ </xsl:attribute>\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]/marc:subfield[@code='a']">\r
+ <identifier type="upc">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=852]">\r
+ <location>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abj</xsl:with-param>\r
+ </xsl:call-template>\r
+ </location>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=506]">\r
+ <accessCondition type="restrictionOnAccess">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcd35</xsl:with-param>\r
+ </xsl:call-template>\r
+ </accessCondition>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=540]">\r
+ <accessCondition type="useAndReproduction">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcde35</xsl:with-param>\r
+ </xsl:call-template>\r
+ </accessCondition>\r
+ </xsl:for-each>\r
+\r
+ <recordInfo>\r
+ <xsl:for-each select="marc:datafield[@tag=040]">\r
+ <recordContentSource>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </recordContentSource>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:controlfield[@tag=008]">\r
+ <recordCreationDate encoding="marc">\r
+ <xsl:value-of select="substring(.,1,6)"/>\r
+ </recordCreationDate>\r
+ </xsl:for-each> \r
+ \r
+ <xsl:for-each select="marc:controlfield[@tag=005]">\r
+ <recordChangeDate encoding="iso8601">\r
+ <xsl:value-of select="."/>\r
+ </recordChangeDate>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:controlfield[@tag=001]">\r
+ <recordIdentifier>\r
+ <xsl:if test="../marc:controlfield[@tag=003]">\r
+ <xsl:attribute name="source">\r
+ <xsl:value-of select="../marc:controlfield[@tag=003]"/>\r
+ </xsl:attribute>\r
+ </xsl:if>\r
+ <xsl:value-of select="."/>\r
+ </recordIdentifier>\r
+ </xsl:for-each>\r
+ </recordInfo>\r
+ </mods>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="displayForm">\r
+ <xsl:for-each select="marc:subfield[@code='c']">\r
+ <displayForm>\r
+ <xsl:value-of select="."/>\r
+ </displayForm>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="affiliation">\r
+ <xsl:for-each select="marc:subfield[@code='u']">\r
+ <affiliation>\r
+ <xsl:value-of select="."/>\r
+ </affiliation>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="uri">\r
+ <xsl:for-each select="marc:subfield[@code='u']">\r
+ <xsl:attribute name="xlink:href">\r
+ <xsl:value-of select="."/>\r
+ </xsl:attribute>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="role">\r
+ <xsl:choose>\r
+ <xsl:when test="marc:subfield[@code='e']">\r
+ <role><xsl:value-of select="marc:subfield[@code='e']"/></role>\r
+ </xsl:when>\r
+ <xsl:when test="marc:subfield[@code='4']">\r
+ <xsl:for-each select="marc:subfield[@code='4']">\r
+ <role><xsl:value-of select="text()"/></role>\r
+ </xsl:for-each>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="part">\r
+ <xsl:variable name="partNumber">\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="axis">n</xsl:with-param>\r
+ <xsl:with-param name="anyCodes">n</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">fghkdlmor</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:variable>\r
+ <xsl:variable name="partName">\r
+ <xsl:call-template name="specialSubfieldSelect">\r
+ <xsl:with-param name="axis">p</xsl:with-param>\r
+ <xsl:with-param name="anyCodes">p</xsl:with-param>\r
+ <xsl:with-param name="afterCodes">fghkdlmor</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:variable>\r
+ <xsl:if test="string-length(normalize-space($partNumber))">\r
+ <partNumber>\r
+ <xsl:value-of select="$partNumber"/>\r
+ </partNumber>\r
+ </xsl:if>\r
+ <xsl:if test="string-length(normalize-space($partName))">\r
+ <partName>\r
+ <xsl:value-of select="$partName"/>\r
+ </partName>\r
+ </xsl:if>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedPart">\r
+ <xsl:for-each select="marc:subfield[@code='n'][preceding-sibling::marc:subfield[@code='t']]">\r
+ <partNumber>\r
+ <xsl:value-of select="."/>\r
+ </partNumber>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='p']">\r
+ <partName>\r
+ <xsl:value-of select="."/>\r
+ </partName>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedName">\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <name>\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </name>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedForm">\r
+ <xsl:for-each select="marc:subfield[@code='h']">\r
+ <physicalDescription>\r
+ <form>\r
+ <unControlled>\r
+ <xsl:value-of select="."/>\r
+ </unControlled>\r
+ </form>\r
+ </physicalDescription>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedExtent">\r
+ <xsl:for-each select="marc:subfield[@code='h']">\r
+ <physicalDescription>\r
+ <extent>\r
+ <xsl:value-of select="."/>\r
+ </extent>\r
+ </physicalDescription>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedNote">\r
+ <xsl:for-each select="marc:subfield[@code='n']">\r
+ <note>\r
+ <xsl:value-of select="."/>\r
+ </note>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedIdentifierISSN">\r
+ <xsl:for-each select="marc:subfield[@code='x']">\r
+ <identifier type="issn">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedIdentifierLocal">\r
+ <xsl:for-each select="marc:subfield[@code='w']">\r
+ <identifier type="local">\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedIdentifier">\r
+ <xsl:for-each select="marc:subfield[@code='o']">\r
+ <identifier>\r
+ <xsl:value-of select="."/>\r
+ </identifier>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedItem76X-78X">\r
+ <xsl:call-template name="relatedTitle76X-78X"/>\r
+ <xsl:call-template name="relatedName"/>\r
+ <xsl:call-template name="relatedExtent"/>\r
+ <xsl:call-template name="relatedIdentifier"/>\r
+ <xsl:call-template name="relatedIdentifierISSN"/>\r
+ <xsl:call-template name="relatedIdentifierLocal"/>\r
+ <xsl:call-template name="relatedNote"/>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="subjectGeographicZ">\r
+ <geographic>\r
+ <xsl:value-of select="."/>\r
+ </geographic> \r
+ </xsl:template>\r
+\r
+ <xsl:template name="subjectTemporalY">\r
+ <temporal>\r
+ <xsl:value-of select="."/>\r
+ </temporal> \r
+ </xsl:template>\r
+\r
+ <xsl:template name="subjectTopic">\r
+ <topic>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </topic>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="nameABCDN">\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <namePart>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </namePart> \r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart> \r
+ </xsl:for-each>\r
+ <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">\r
+ <namePart>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">cdn</xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ </xsl:if>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="nameABCDQ">\r
+ <namePart>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ <xsl:call-template name="nameDate"/>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="nameACDEQ">\r
+ <namePart>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">acdeq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="constituentOrRelatedType">\r
+ <xsl:attribute name="type">\r
+ <xsl:choose>\r
+ <xsl:when test="@ind2=2">constituent</xsl:when>\r
+ <xsl:otherwise>related</xsl:otherwise>\r
+ </xsl:choose>\r
+ </xsl:attribute>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedTitle">\r
+ <xsl:for-each select="marc:subfield[@code='t']">\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:value-of select="."/>\r
+ </title>\r
+ </titleInfo>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="relatedTitle76X-78X">\r
+ <titleInfo>\r
+ <xsl:for-each select="marc:subfield[@code='t']">\r
+ <title>\r
+ <xsl:value-of select="."/>\r
+ </title>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='g']">\r
+ <partNumber>\r
+ <xsl:value-of select="."/>\r
+ </partNumber>\r
+ </xsl:for-each>\r
+ </titleInfo>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="nameDate">\r
+ <xsl:for-each select="marc:subfield[@code='d']">\r
+ <namePart type="date">\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="."/>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="subjectAuthority">\r
+ <xsl:attribute name="authority">\r
+ <xsl:choose>\r
+ <xsl:when test="@ind2=0">lcsh</xsl:when>\r
+ <xsl:when test="@ind2=1">lcshac</xsl:when>\r
+ <xsl:when test="@ind2=2">mesh</xsl:when>\r
+ <xsl:when test="@ind2=3">csh</xsl:when>\r
+ <xsl:when test="@ind2=5">nal</xsl:when>\r
+ <xsl:when test="@ind2=6">rvm</xsl:when>\r
+ <xsl:when test="@ind2=7"><xsl:value-of select="marc:subfield[@code='2']"/></xsl:when>\r
+ </xsl:choose>\r
+ </xsl:attribute>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="subjectAnyOrder">\r
+ <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">\r
+ <xsl:choose>\r
+ <xsl:when test="@code='v'">\r
+ <xsl:call-template name="subjectTopic"/>\r
+ </xsl:when>\r
+ <xsl:when test="@code='x'">\r
+ <xsl:call-template name="subjectTopic"/>\r
+ </xsl:when>\r
+ <xsl:when test="@code='y'">\r
+ <xsl:call-template name="subjectTemporalY"/>\r
+ </xsl:when>\r
+ <xsl:when test="@code='z'">\r
+ <xsl:call-template name="subjectGeographicZ"/>\r
+ </xsl:when>\r
+ </xsl:choose>\r
+ </xsl:for-each>\r
+ </xsl:template>\r
+\r
+<!-- <xsl:template name="subfieldSelect">\r
+ <xsl:param name="codes"/>\r
+ <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>\r
+ <xsl:variable name="str">\r
+ <xsl:for-each select="marc:subfield">\r
+ <xsl:if test="contains($codes, @code)">\r
+ <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>\r
+ </xsl:if>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+ <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>\r
+ </xsl:template>\r
+-->\r
+\r
+ <xsl:template name="specialSubfieldSelect">\r
+ <xsl:param name="anyCodes"/>\r
+ <xsl:param name="axis"/>\r
+ <xsl:param name="beforeCodes"/>\r
+ <xsl:param name="afterCodes"/>\r
+ <xsl:variable name="str">\r
+ <xsl:for-each select="marc:subfield">\r
+ <xsl:if test="contains($anyCodes, @code) or (contains($beforeCodes,@code) and following-sibling::marc:subfield[@code=$axis]) or (contains($afterCodes,@code) and preceding-sibling::marc:subfield[@code=$axis])">\r
+ <xsl:value-of select="text()"/><xsl:text> </xsl:text>\r
+ </xsl:if>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=600]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <name type="personal">\r
+ <namePart>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ <xsl:call-template name="nameDate"/>\r
+ <xsl:call-template name="affiliation"/>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=610]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <name type="corporate">\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <xsl:for-each select="marc:subfield[@code='b']">\r
+ <namePart>\r
+ <xsl:value-of select="."/>\r
+ </namePart>\r
+ </xsl:for-each>\r
+ <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">\r
+ <namePart>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">cdnp</xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ </xsl:if>\r
+ <xsl:call-template name="role"/>\r
+ </name>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=611]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <name type="conference">\r
+ <namePart>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdeqnp</xsl:with-param>\r
+ </xsl:call-template>\r
+ </namePart>\r
+ <xsl:for-each select="marc:subfield[@code='4']">\r
+ <role>\r
+ <xsl:value-of select="."/>\r
+ </role>\r
+ </xsl:for-each>\r
+ </name>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=630]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <titleInfo>\r
+ <title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">adfhklor</xsl:with-param>\r
+ </xsl:call-template>\r
+ <xsl:call-template name="part"/> \r
+ </title>\r
+ </titleInfo>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=650]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <topic>\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcd</xsl:with-param>\r
+ </xsl:call-template>\r
+ </xsl:with-param>\r
+ </xsl:call-template>\r
+ </topic>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+\r
+ <xsl:template match="marc:datafield[@tag=651]">\r
+ <subject>\r
+ <xsl:call-template name="subjectAuthority"/>\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <geographic>\r
+ <xsl:value-of select="."/>\r
+ </geographic> \r
+ </xsl:for-each>\r
+ <xsl:call-template name="subjectAnyOrder"/>\r
+ </subject>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:datafield[@tag=653]">\r
+ <subject>\r
+ <xsl:for-each select="marc:subfield[@code='a']">\r
+ <topic>\r
+ <xsl:value-of select="."/>\r
+ </topic> \r
+ </xsl:for-each>\r
+ </subject>\r
+ </xsl:template>\r
+</xsl:stylesheet><!-- Stylus Studio meta-information - (c)1998-2002 eXcelon Corp.\r
+<metaInformation>\r
+<scenarios ><scenario default="yes" name="modstst2" userelativepaths="yes" externalpreview="no" url="..\..\..\..\..\..\marcxml\modstst2.xml" htmlbaseurl="" outputurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="modstest" userelativepaths="yes" externalpreview="no" url="..\..\..\..\..\..\marcxml\modstest.xml" htmlbaseurl="" outputurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="Scenario1" userelativepaths="yes" externalpreview="no" url="..\..\..\..\..\..\marcxml\t.xml" htmlbaseurl="" outputurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/></scenarios><MapperInfo srcSchemaPath="" srcSchemaRoot="" srcSchemaPathIsRelative="yes" srcSchemaInterpretAsXML="no" destSchemaPath="" destSchemaRoot="" destSchemaPathIsRelative="yes" destSchemaInterpretAsXML="no"/>\r
+</metaInformation>\r
+-->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:marc="http://www.loc.gov/MARC21/slim"
+ xmlns="http://www.loc.gov/mods/v3"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">
+ <xsl:include href="MARC21slimUtils.xsl"/>
+ <xsl:output method="xml" indent="yes"/>
+
+<!--
+
+Revision 1.5 2003/10/02 16:18:58 ntra
+MODS2 to MODS3 updates, language unstacking and
+de-duping, chopPunctuation expanded
+
+Revision 1.3 2003/04/03 00:07:19 ntra
+Revision 1.3 Additional Changes not related to MODS Version 2.0 by ntra
+
+Revision 1.2 2003/03/24 19:37:42 ckeith
+Added Log Comment
+
+-->
+ <xsl:template match="/">
+ <xsl:choose>
+ <xsl:when test="marc:collection">
+ <modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-0.xsd">
+ <xsl:for-each select="marc:collection/marc:record">
+ <mods version="3.0">
+ <xsl:call-template name="marcRecord"/>
+ </mods>
+ </xsl:for-each>
+ </modsCollection>
+ </xsl:when>
+ <xsl:otherwise>
+ <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-0.xsd">
+ <xsl:for-each select="marc:record">
+ <xsl:call-template name="marcRecord"/>
+ </xsl:for-each>
+ </mods>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="marcRecord">
+ <xsl:variable name="leader" select="marc:leader"/>
+ <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+ <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+ <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>
+ <xsl:variable name="typeOf008">
+ <xsl:choose>
+ <xsl:when test="$leader6='a'">
+ <xsl:choose>
+ <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
+ <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="$leader6='t'">BK</xsl:when>
+ <xsl:when test="$leader6='p'">MM</xsl:when>
+ <xsl:when test="$leader6='m'">CF</xsl:when>
+ <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
+ <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
+ <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'">MU</xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:for-each select="marc:datafield[@tag=245]">
+ <titleInfo>
+ <xsl:variable name="title">
+ <xsl:choose>
+ <xsl:when test="marc:subfield[@code='b']">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">b</xsl:with-param>
+ <xsl:with-param name="beforeCodes">afghk</xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abfghk</xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="titleChop">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="$title"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@ind2>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1,@ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop,@ind2+1)"/>
+ </title>
+ </xsl:when>
+ <xsl:otherwise>
+ <title>
+ <xsl:value-of select="$titleChop"/>
+ </title>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="marc:subfield[@code='b']">
+ <subTitle>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">b</xsl:with-param>
+ <xsl:with-param name="anyCodes">b</xsl:with-param>
+ <xsl:with-param name="afterCodes">afghk</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </subTitle>
+ </xsl:if>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=210]">
+ <titleInfo type="abbreviated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=242]">
+ <titleInfo type="translated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <!-- 1/04 removed $h -->
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=246]">
+ <titleInfo type="alternative">
+ <xsl:for-each select="marc:subfield[@code='i']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="text()"/>
+ </xsl:attribute>
+ </xsl:for-each>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <!-- 1/04 removed $h -->
+ <xsl:with-param name="codes">abf</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=130]|marc:datafield[@tag=240]|marc:datafield[@tag=730][@ind2!=2]">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="(contains('adfhklmor',@code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
+ <xsl:value-of select="text()"/>
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=740][@ind2!=2]">
+ <titleInfo type="alternative">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ah</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=100]">
+ <name type="personal">
+ <xsl:call-template name="nameABCDQ"/>
+ <xsl:call-template name="affiliation"/>
+ <role>
+ <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+ </role>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=110]">
+ <name type="corporate">
+ <xsl:call-template name="nameABCDN"/>
+ <role>
+ <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+ </role>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=111]">
+ <name type="conference">
+ <xsl:call-template name="nameACDEQ"/>
+ <role>
+ <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+ </role>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=700][not(marc:subfield[@code='t'])]">
+ <name type="personal">
+ <xsl:call-template name="nameABCDQ"/>
+ <xsl:call-template name="affiliation"/>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=710][not(marc:subfield[@code='t'])]">
+ <name type="corporate">
+ <xsl:call-template name="nameABCDN"/>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=711][not(marc:subfield[@code='t'])]">
+ <name type="conference">
+ <xsl:call-template name="nameACDEQ"/>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=720][not(marc:subfield[@code='t'])]">
+ <name>
+ <xsl:if test="@ind1=1">
+ <xsl:attribute name="type"><xsl:text>personal</xsl:text></xsl:attribute>
+ </xsl:if>
+ <namePart>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </namePart>
+ <xsl:call-template name="role"/>
+ </name>
+ </xsl:for-each>
+
+ <typeOfResource>
+ <xsl:if test="$leader7='c'">
+ <xsl:attribute name="collection">yes</xsl:attribute>
+ </xsl:if>
+ <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+ <xsl:attribute name="manuscript">yes</xsl:attribute>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+ <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+ <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+ <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
+ <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
+ <xsl:when test="$leader6='k'">still image</xsl:when>
+ <xsl:when test="$leader6='g'">moving image</xsl:when>
+ <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+ <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+ <xsl:when test="$leader6='p'">mixed material</xsl:when>
+ </xsl:choose>
+ </typeOfResource>
+
+ <xsl:if test="substring($controlField008,26,1)='d'">
+ <genre authority="marc">globe</genre>
+ </xsl:if>
+
+ <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+ <genre authority="marc">remote sensing image</genre>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='MP'">
+ <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+ <genre authority="marc">map</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+ <genre authority="marc">atlas</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='SE'">
+ <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-21='d'">
+ <genre authority="marc">database</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='l'">
+ <genre authority="marc">loose-leaf</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='m'">
+ <genre authority="marc">series</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='n'">
+ <genre authority="marc">newspaper</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='p'">
+ <genre authority="marc">periodical</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='w'">
+ <genre authority="marc">web site</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
+ <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"/>
+ <xsl:choose>
+ <xsl:when test="contains($controlField008-24,'a')">
+ <genre authority="marc">abstract or summary</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'b')">
+ <genre authority="marc">bibliography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'c')">
+ <genre authority="marc">catalog</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'d')">
+ <genre authority="marc">dictionary</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'e')">
+ <genre authority="marc">encyclopedia</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'f')">
+ <genre authority="marc">handbook</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'g')">
+ <genre authority="marc">legal article</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'i')">
+ <genre authority="marc">index</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'k')">
+ <genre authority="marc">discography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'l')">
+ <genre authority="marc">legislation</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'m')">
+ <genre authority="marc">theses</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'n')">
+ <genre authority="marc">survey of literature</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'o')">
+ <genre authority="marc">review</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'p')">
+ <genre authority="marc">programmed text</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'q')">
+ <genre authority="marc">filmography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'r')">
+ <genre authority="marc">directory</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'s')">
+ <genre authority="marc">statistics</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'t')">
+ <genre authority="marc">technical report</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'v')">
+ <genre authority="marc">legal case and case notes</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'w')">
+ <genre authority="marc">law report or digest</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'z')">
+ <genre authority="marc">treaty</genre>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-29='1'">
+ <genre authority="marc">conference publication</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='CF'">
+ <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-26='a'">
+ <genre authority="marc">numeric data</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='e'">
+ <genre authority="marc">database</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='f'">
+ <genre authority="marc">font</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='g'">
+ <genre authority="marc">game</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='BK'">
+ <xsl:if test="substring($controlField008,25,1)='j'">
+ <genre authority="marc">patent</genre>
+ </xsl:if>
+ <xsl:if test="substring($controlField008,31,1)='1'">
+ <genre authority="marc">festschrift</genre>
+ </xsl:if>
+
+ <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"/>
+ <xsl:if test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
+ <genre authority="marc">biography</genre>
+ </xsl:if>
+
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-33='e'">
+ <genre authority="marc">essay</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='d'">
+ <genre authority="marc">drama</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='c'">
+ <genre authority="marc">comic strip</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='l'">
+ <genre authority="marc">fiction</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='h'">
+ <genre authority="marc">humor, satire</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='i'">
+ <genre authority="marc">letter</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='f'">
+ <genre authority="marc">novel</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='j'">
+ <genre authority="marc">short story</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='s'">
+ <genre authority="marc">speech</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='MU'">
+ <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"/>
+ <xsl:if test="contains($controlField008-30-31,'b')">
+ <genre authority="marc">biography</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'c')">
+ <genre authority="marc">conference publication</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'d')">
+ <genre authority="marc">drama</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'e')">
+ <genre authority="marc">essay</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'f')">
+ <genre authority="marc">fiction</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'o')">
+ <genre authority="marc">folktale</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'h')">
+ <genre authority="marc">history</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'k')">
+ <genre authority="marc">humor, satire</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'m')">
+ <genre authority="marc">memoir</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'p')">
+ <genre authority="marc">poetry</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'r')">
+ <genre authority="marc">rehersal</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'g')">
+ <genre authority="marc">reporting</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'s')">
+ <genre authority="marc">sound</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'l')">
+ <genre authority="marc">speech</genre>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$typeOf008='VM'">
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-33='a'">
+ <genre authority="marc">art original</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='b'">
+ <genre authority="marc">kit</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='c'">
+ <genre authority="marc">art reproduction</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='d'">
+ <genre authority="marc">diorama</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='f'">
+ <genre authority="marc">filmstrip</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='g'">
+ <genre authority="marc">legal article</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='i'">
+ <genre authority="marc">picture</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='k'">
+ <genre authority="marc">graphic</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='l'">
+ <genre authority="marc">technical drawing</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='m'">
+ <genre authority="marc">motion picture</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='n'">
+ <genre authority="marc">chart</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='o'">
+ <genre authority="marc">flash card</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='p'">
+ <genre authority="marc">microscope slide</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+ <genre authority="marc">model</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='r'">
+ <genre authority="marc">realia</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='s'">
+ <genre authority="marc">slide</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='t'">
+ <genre authority="marc">transparency</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='v'">
+ <genre authority="marc">videorecording</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='w'">
+ <genre authority="marc">toy</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=655]">
+ <genre authority="marc">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:attribute>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abvxyz</xsl:with-param>
+ <xsl:with-param name="delimeter">-</xsl:with-param>
+ </xsl:call-template>
+ </genre>
+ </xsl:for-each>
+
+ <originInfo>
+ <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"/>
+
+ <xsl:if test="translate($MARCpublicationCode,'|','')">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">marccountry</xsl:attribute>
+ <xsl:value-of select="$MARCpublicationCode"/>
+ </placeTerm>
+ </place>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">iso3166</xsl:attribute>
+ <xsl:value-of select="."/>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">text</xsl:attribute>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
+ <dateValid point="start">
+ <xsl:value-of select="."/>
+ </dateValid>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
+ <dateValid point="end">
+ <xsl:value-of select="."/>
+ </dateValid>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
+ <dateModified>
+ <xsl:value-of select="."/>
+ </dateModified>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
+ <xsl:choose>
+ <xsl:when test="@code='b'">
+ <publisher>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </publisher>
+ </xsl:when>
+ <xsl:when test="@code='c'">
+ <dateIssued>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </dateIssued>
+ </xsl:when>
+ <xsl:when test="@code='g'">
+ <dateCreated>
+ <xsl:value-of select="."/>
+ </dateCreated>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <xsl:variable name="dataField260c">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="controlField008-7-10" select="normalize-space(substring($controlField008, 8, 4))"/>
+ <xsl:variable name="controlField008-11-14" select="normalize-space(substring($controlField008, 12, 4))"/>
+ <xsl:variable name="controlField008-6" select="normalize-space(substring($controlField008, 7, 1))"/>
+
+ <xsl:if test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
+ <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
+ <dateIssued encoding="marc">
+ <xsl:value-of select="$controlField008-7-10"/>
+ </dateIssued>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+ <xsl:if test="$controlField008-7-10">
+ <dateIssued encoding="marc" point="start">
+ <xsl:value-of select="$controlField008-7-10"/>
+ </dateIssued>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+ <xsl:if test="$controlField008-11-14">
+ <dateIssued encoding="marc" point="end">
+ <xsl:value-of select="$controlField008-11-14"/>
+ </dateIssued>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$controlField008-6='q'">
+ <xsl:if test="$controlField008-7-10">
+ <dateIssued encoding="marc" point="start" qualifier="questionable">
+ <xsl:value-of select="$controlField008-7-10"/>
+ </dateIssued>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$controlField008-6='q'">
+ <xsl:if test="$controlField008-11-14">
+ <dateIssued encoding="marc" point="end" qualifier="questionable">
+ <xsl:value-of select="$controlField008-11-14"/>
+ </dateIssued>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:if test="$controlField008-6='t'">
+ <xsl:if test="$controlField008-11-14">
+ <copyrightDate encoding="marc">
+ <xsl:value-of select="$controlField008-11-14"/>
+ </copyrightDate>
+ </xsl:if>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
+ <dateCaptured encoding="iso8601">
+ <xsl:value-of select="."/>
+ </dateCaptured>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
+ <dateCaptured encoding="iso8601" point="start">
+ <xsl:value-of select="."/>
+ </dateCaptured>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
+ <dateCaptured encoding="iso8601" point="end">
+ <xsl:value-of select="."/>
+ </dateCaptured>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
+ <edition>
+ <xsl:value-of select="."/>
+ </edition>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:leader">
+ <issuance>
+ <xsl:choose>
+ <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">monographic</xsl:when>
+ <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">continuing</xsl:when>
+ </xsl:choose>
+ </issuance>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
+ <frequency>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </frequency>
+ </xsl:for-each>
+ </originInfo>
+ <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"/>
+ <xsl:if test="$controlField008-35-37">
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="substring($controlField008,36,3)"/>
+ </languageTerm>
+ </language>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=041]">
+ <xsl:variable name="langCodes">
+ <xsl:copy-of select="marc:subfield[@code='a'or @code='d' or @code='e' or @code='2']"/>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="$langCodes/child::*[@code='2']='rfc3066'">
+ <xsl:call-template name="rfcLanguages">
+ <xsl:with-param name="langCodes"><xsl:copy-of select="$langCodes"/></xsl:with-param>
+ <xsl:with-param name="nodeNum"><xsl:value-of select="1"/></xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:text></xsl:text>
+ </xsl:with-param>
+ <xsl:with-param name="controlField008-35-37">
+ <xsl:value-of select="$controlField008-35-37"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="allLanguages">
+ <xsl:value-of select="$langCodes"/>
+ </xsl:variable>
+ <xsl:variable name="currentLanguage">
+ <xsl:value-of select="substring($allLanguages,1,3)"/>
+ </xsl:variable>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($allLanguages,1,3)"/>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of select="substring($allLanguages,4,string-length($allLanguages)-3)"/>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:if test="$controlField008-35-37">
+ <xsl:value-of select="substring($controlField008,36,3)"/>
+ </xsl:if>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <xsl:variable name="physicalDescription">
+ <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a' or substring(.,12,1)='b']">
+ <digitalOrigin>reformatted digital</digitalOrigin>
+ </xsl:if>
+
+ <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"/>
+ <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
+
+ <xsl:variable name="check008-23">
+ <xsl:if test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
+ <xsl:value-of select="true()"/>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="check008-29">
+ <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
+ <xsl:value-of select="true()"/>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
+ <form authority="marcform">braille</form>
+ </xsl:when>
+ <xsl:when test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
+ <form authority="marcform">print</form>
+ </xsl:when>
+ <xsl:when test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
+ <form authority="marcform">electronic</form>
+ </xsl:when>
+ <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
+ <form authority="marcform">microfiche</form>
+ </xsl:when>
+ <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
+ <form authority="marcform">microfilm</form>
+ </xsl:when>
+ </xsl:choose>
+ <!-- 1/04 fix -->
+ <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
+ <form authority='gmd'>
+ <xsl:call-template name="chopBrackets">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </form>
+ </xsl:if>
+ <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
+ <form authority='gmd'>
+ <xsl:call-template name="chopBrackets">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </form>
+ </xsl:if>
+ <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
+ <form authority='gmd'>
+ <xsl:call-template name="chopBrackets">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </form>
+ </xsl:if>
+ <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
+ <xsl:choose>
+ <xsl:when test="substring(text(),14,1)='a'">
+ <reformattingQuality>access</reformattingQuality>
+ </xsl:when>
+ <xsl:when test="substring(text(),14,1)='p'">
+ <reformattingQuality>preservation</reformattingQuality>
+ </xsl:when>
+ <xsl:when test="substring(text(),14,1)='r'">
+ <reformattingQuality>replacement</reformattingQuality>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
+ <internetMediaType>
+ <xsl:value-of select="."/>
+ </internetMediaType>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
+ <form><xsl:value-of select="."/></form>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=300]">
+ <extent>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abce</xsl:with-param>
+ </xsl:call-template>
+ </extent>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:if test="string-length(normalize-space($physicalDescription))">
+ <physicalDescription>
+ <xsl:copy-of select="$physicalDescription"/>
+ </physicalDescription>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=520]">
+ <abstract>
+ <xsl:call-template name="uri"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </abstract>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=505]">
+ <tableOfContents>
+ <xsl:call-template name="uri"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">agrt</xsl:with-param>
+ </xsl:call-template>
+ </tableOfContents>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=521]">
+ <targetAudience>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </targetAudience>
+ </xsl:for-each>
+
+ <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
+ <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-22='d'">
+ <targetAudience>adolescent</targetAudience>
+ </xsl:when>
+ <xsl:when test="$controlField008-22='e'">
+ <targetAudience>adult</targetAudience>
+ </xsl:when>
+ <xsl:when test="$controlField008-22='g'">
+ <targetAudience>general</targetAudience>
+ </xsl:when>
+ <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
+ <targetAudience>juvenile</targetAudience>
+ </xsl:when>
+ <xsl:when test="$controlField008-22='a'">
+ <targetAudience>preschool</targetAudience>
+ </xsl:when>
+ <xsl:when test="$controlField008-22='f'">
+ <targetAudience>specialized</targetAudience>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
+ <note type="statement of responsibility">
+ <xsl:value-of select="."/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=500]">
+ <note>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ <xsl:call-template name="uri"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=511]">
+ <note type="performers">
+ <xsl:call-template name="uri"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=518]">
+ <note type="venue">
+ <xsl:call-template name="uri"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=506 or @tag=507 or @tag=508 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=530 or @tag=533 or @tag=534 or @tag=535 or @tag=536 or @tag=538 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=583 or @tag=584 or @tag=585 or @tag=586]">
+ <note>
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
+ <subject>
+ <cartographics>
+ <coordinates>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">defg</xsl:with-param>
+ </xsl:call-template>
+ </coordinates>
+ </cartographics>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=043]">
+ <subject>
+ <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+ <geographicCode>
+ <xsl:attribute name="authority">
+ <xsl:if test="@code='a'">
+ <xsl:text>marcgac</xsl:text>
+ </xsl:if>
+ <xsl:if test="@code='b'">
+ <xsl:value-of select="following-sibling::marc:subfield[@code=2]"/>
+ </xsl:if>
+ <xsl:if test="@code='c'">
+ <xsl:text>iso3166</xsl:text>
+ </xsl:if>
+ </xsl:attribute>
+ <xsl:value-of select="self::marc:subfield"/>
+ </geographicCode>
+ </xsl:for-each>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=255]">
+ <subject>
+ <cartographics>
+ <xsl:for-each select="marc:subfield[@code='c']">
+ <coordinates>
+ <xsl:value-of select="."/>
+ </coordinates>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <scale>
+ <xsl:value-of select="."/>
+ </scale>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <projection>
+ <xsl:value-of select="."/>
+ </projection>
+ </xsl:for-each>
+ </cartographics>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"/>
+
+ <xsl:apply-templates select="marc:datafield[@tag=656]"/>
+
+ <xsl:for-each select="marc:datafield[@tag=752]">
+ <subject>
+ <hierarchicalGeographic>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <country>
+ <xsl:value-of select="."/>
+ </country>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <state>
+ <xsl:value-of select="."/>
+ </state>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='c']">
+ <county>
+ <xsl:value-of select="."/>
+ </county>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <city>
+ <xsl:value-of select="."/>
+ </city>
+ </xsl:for-each>
+ </hierarchicalGeographic>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
+ <subject>
+ <xsl:choose>
+ <xsl:when test="@ind1=2">
+ <temporal encoding="iso8601" point="start">
+ <xsl:value-of select="marc:subfield[@code='b'][1]"/>
+ </temporal>
+ <temporal encoding="iso8601" point="end">
+ <xsl:value-of select="marc:subfield[@code='b'][2]"/>
+ </temporal>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <temporal encoding="iso8601">
+ <xsl:value-of select="."/>
+ </temporal>
+ </xsl:for-each>
+ </xsl:otherwise>
+ </xsl:choose>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=050]">
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <classification authority="lcc">
+ <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="text()"/>
+ </classification>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
+ <classification authority="lcc">
+ <xsl:value-of select="text()"/>
+ </classification>
+ </xsl:for-each>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=082]">
+ <classification authority="ddc">
+ <xsl:if test="marc:subfield[@code='2']">
+ <xsl:attribute name="edition">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=080]">
+ <classification authority="udc">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abx</xsl:with-param>
+ </xsl:call-template>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=060]">
+ <classification authority="nlm">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
+ <classification authority="sudocs">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
+ <classification authority="candoc">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=086]">
+ <classification>
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:attribute>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=084]">
+ <classification>
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:attribute>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </classification>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=440]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">av</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">av</xsl:with-param>
+ </xsl:call-template> \
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=510]">
+ <relatedItem type="isReferencedBy">
+ <note>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcx3</xsl:with-param>
+ </xsl:call-template>
+ </note>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=534]">
+ <relatedItem type="original">
+ <xsl:call-template name="relatedTitle"/>
+ <xsl:call-template name="relatedName"/>
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <originInfo>
+ <xsl:for-each select="marc:subfield[@code='c']">
+ <publisher>
+ <xsl:value-of select="."/>
+ </publisher>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <edition>
+ <xsl:value-of select="."/>
+ </edition>
+ </xsl:for-each>
+ </originInfo>
+ </xsl:if>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ <xsl:for-each select="marc:subfield[@code='z']">
+ <identifier type="isbn">
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ <xsl:call-template name="relatedNote"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <name type="personal">
+ <namePart>
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">aq</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"/>
+ <xsl:call-template name="nameDate"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">dg</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="relatedPartNumName"/>
+ </titleInfo>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:variable name="tempNamePart">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">c</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="normalize-space($tempNamePart)">
+ <namePart>
+ <xsl:value-of select="$tempNamePart"/>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="relatedPartNumName"/>
+ </titleInfo>
+ <name type="conference">
+ <namePart>
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <xsl:call-template name="relatedForm"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
+ <relatedItem type="series">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
+ <relatedItem>
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=775]">
+ <relatedItem type="otherVersion">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
+ <relatedItem type="constituent">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
+ <relatedItem type="host">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=776]">
+ <relatedItem type="otherFormat">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=780]">
+ <relatedItem type="preceding">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=785]">
+ <relatedItem type="succeeding">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=786]">
+ <relatedItem type="original">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=800]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <name type="personal">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">aq</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"/>
+ <xsl:call-template name="nameDate"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=810]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">dg</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="relatedPartNumName"/>
+ </titleInfo>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <namePart>
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">c</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=811]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="afterCodes">g</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="relatedPartNumName"/>
+ </titleInfo>
+ <name type="conference">
+ <namePart>
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+ <xsl:with-param name="axis">t</xsl:with-param>
+ <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=830]">
+ <relatedItem type="series">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <xsl:call-template name="relatedForm"/>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856][@ind2=2]/marc:subfield[@code='q']">
+ <relatedItem>
+ <internetMediaType>
+ <xsl:value-of select="."/>
+ </internetMediaType>
+ </relatedItem>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=020]">
+ <identifier type="isbn">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=0]">
+ <identifier type="isrc">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=2]">
+ <identifier type="ismn">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=022]">
+ <identifier type="issn">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=010]">
+ <identifier type="lccn">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=028]">
+ <identifier>
+ <xsl:call-template name="isInvalid"/>
+ <xsl:attribute name="type">
+ <xsl:choose>
+ <xsl:when test="@ind1=0">issue number</xsl:when>
+ <xsl:when test="@ind1=1">matrix number</xsl:when>
+ <xsl:when test="@ind1=2">music plate</xsl:when>
+ <xsl:when test="@ind1=3">music publisher</xsl:when>
+ <xsl:when test="@ind1=4">videorecording identifier</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1='4']">
+ <identifier type="sici">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=037]">
+ <identifier type="stock number">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
+ <identifier>
+ <xsl:attribute name="type">
+ <xsl:choose>
+ <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')">doi</xsl:when>
+ <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov')">hdl</xsl:when>
+ <xsl:otherwise>uri</xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:choose>
+ <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov') ">
+ <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="marc:subfield[@code='u']"/></xsl:otherwise>
+ </xsl:choose>
+ </identifier>
+ <xsl:if test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
+ <identifier type="hdl">
+ <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
+ <xsl:attribute name="displayLabel">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">y3z</xsl:with-param>
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u']),'http://hdl.loc.gov/')"/>
+ </identifier>
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
+ <identifier type="upc">
+ <xsl:call-template name="isInvalid"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
+ <location>
+ <url>
+ <xsl:if test="marc:subfield[@code=3]">
+ <xsl:attribute name="displayLabel">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">3</xsl:with-param>
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:value-of select="marc:subfield[@code='u']"/>
+ </url>
+ </location>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=852]">
+ <location>
+ <physicalLocation>
+ <xsl:call-template name="displayLabel"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abje</xsl:with-param>
+ </xsl:call-template>
+ </physicalLocation>
+ </location>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=506]">
+ <accessCondition type="restrictionOnAccess">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd35</xsl:with-param>
+ </xsl:call-template>
+ </accessCondition>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=540]">
+ <accessCondition type="useAndReproduction">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcde35</xsl:with-param>
+ </xsl:call-template>
+ </accessCondition>
+ </xsl:for-each>
+
+ <recordInfo>
+ <xsl:for-each select="marc:datafield[@tag=040]">
+ <recordContentSource authority="marcorg">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </recordContentSource>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:controlfield[@tag=008]">
+ <recordCreationDate encoding="marc">
+ <xsl:value-of select="substring(.,1,6)"/>
+ </recordCreationDate>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:controlfield[@tag=005]">
+ <recordChangeDate encoding="iso8601">
+ <xsl:value-of select="."/>
+ </recordChangeDate>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:controlfield[@tag=001]">
+ <recordIdentifier>
+ <xsl:if test="../marc:controlfield[@tag=003]">
+ <xsl:attribute name="source">
+ <xsl:value-of select="../marc:controlfield[@tag=003]"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:value-of select="."/>
+ </recordIdentifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
+ <languageOfCataloging>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="."/>
+ </languageTerm>
+ </languageOfCataloging>
+ </xsl:for-each>
+ </recordInfo>
+ </xsl:template>
+
+ <xsl:template name="displayForm">
+ <xsl:for-each select="marc:subfield[@code='c']">
+ <displayForm>
+ <xsl:value-of select="."/>
+ </displayForm>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="affiliation">
+ <xsl:for-each select="marc:subfield[@code='u']">
+ <affiliation>
+ <xsl:value-of select="."/>
+ </affiliation>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="uri">
+ <xsl:for-each select="marc:subfield[@code='u']">
+ <xsl:attribute name="xlink:href">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="role">
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <role>
+ <roleTerm type="text">
+ <xsl:value-of select="."/>
+ </roleTerm>
+ </role>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='4']">
+ <role>
+ <roleTerm authority="marcrelator" type="code">
+ <xsl:value-of select="."/>
+ </roleTerm>
+ </role>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="part">
+ <xsl:variable name="partNumber">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">n</xsl:with-param>
+ <xsl:with-param name="anyCodes">n</xsl:with-param>
+ <xsl:with-param name="afterCodes">fghkdlmor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="partName">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">p</xsl:with-param>
+ <xsl:with-param name="anyCodes">p</xsl:with-param>
+ <xsl:with-param name="afterCodes">fghkdlmor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="string-length(normalize-space($partNumber))">
+ <partNumber>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$partNumber"/>
+ </xsl:call-template>
+ </partNumber>
+ </xsl:if>
+ <xsl:if test="string-length(normalize-space($partName))">
+ <partName>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$partName"/>
+ </xsl:call-template>
+ </partName>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="relatedPart">
+ <xsl:if test="@tag=773">
+ <xsl:for-each select="marc:subfield[@code='g']">
+ <part>
+ <text>
+ <xsl:value-of select="."/>
+ </text>
+ </part>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='q']">
+ <part>
+ <xsl:call-template name="parsePart"/>
+ </part>
+ </xsl:for-each>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="relatedPartNumName">
+ <xsl:variable name="partNumber">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">g</xsl:with-param>
+ <xsl:with-param name="anyCodes">g</xsl:with-param>
+ <xsl:with-param name="afterCodes">pst</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="partName">
+ <xsl:call-template name="specialSubfieldSelect">
+ <xsl:with-param name="axis">p</xsl:with-param>
+ <xsl:with-param name="anyCodes">p</xsl:with-param>
+ <xsl:with-param name="afterCodes">fghkdlmor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="string-length(normalize-space($partNumber))">
+ <partNumber>
+ <xsl:value-of select="$partNumber"/>
+ </partNumber>
+ </xsl:if>
+ <xsl:if test="string-length(normalize-space($partName))">
+ <partName>
+ <xsl:value-of select="$partName"/>
+ </partName>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="relatedName">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <name>
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </name>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedForm">
+ <xsl:for-each select="marc:subfield[@code='h']">
+ <physicalDescription>
+ <form>
+ <xsl:value-of select="."/>
+ </form>
+ </physicalDescription>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedExtent">
+ <xsl:for-each select="marc:subfield[@code='h']">
+ <physicalDescription>
+ <extent>
+ <xsl:value-of select="."/>
+ </extent>
+ </physicalDescription>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedNote">
+ <xsl:for-each select="marc:subfield[@code='n']">
+ <note>
+ <xsl:value-of select="."/>
+ </note>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedSubject">
+ <xsl:for-each select="marc:subfield[@code='j']">
+ <subject>
+ <temporal encoding="iso8601">
+ <xsl:value-of select="."/>
+ </temporal>
+ </subject>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedIdentifierISSN">
+ <xsl:for-each select="marc:subfield[@code='x']">
+ <identifier type="issn">
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedIdentifierLocal">
+ <xsl:for-each select="marc:subfield[@code='w']">
+ <identifier type="local">
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedIdentifier">
+ <xsl:for-each select="marc:subfield[@code='o']">
+ <identifier>
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedItem76X-78X">
+ <xsl:call-template name="displayLabel"/>
+ <xsl:call-template name="relatedTitle76X-78X"/>
+ <xsl:call-template name="relatedName"/>
+ <xsl:call-template name="relatedOriginInfo"/>
+ <xsl:call-template name="relatedLanguage"/>
+ <xsl:call-template name="relatedExtent"/>
+ <xsl:call-template name="relatedNote"/>
+ <xsl:call-template name="relatedSubject"/>
+ <xsl:call-template name="relatedIdentifier"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ <xsl:call-template name="relatedIdentifierLocal"/>
+ <xsl:call-template name="relatedPart"/>
+ </xsl:template>
+
+ <xsl:template name="subjectGeographicZ">
+ <geographic>
+ <xsl:value-of select="."/>
+ </geographic>
+ </xsl:template>
+
+ <xsl:template name="subjectTemporalY">
+ <temporal>
+ <xsl:value-of select="."/>
+ </temporal>
+ </xsl:template>
+
+ <xsl:template name="subjectTopic">
+ <topic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </topic>
+ </xsl:template>
+
+ <xsl:template name="nameABCDN">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="nameABCDQ">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"/>
+ <xsl:call-template name="nameDate"/>
+ </xsl:template>
+
+ <xsl:template name="nameACDEQ">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">acdeq</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:template>
+
+ <xsl:template name="constituentOrRelatedType">
+ <xsl:if test="@ind2=2">
+ <xsl:attribute name="type">constituent</xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="relatedTitle">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedTitle76X-78X">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='p']">
+ <titleInfo type="abbreviated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='s']">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="relatedOriginInfo">
+ <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+ <originInfo>
+ <xsl:if test="@tag=775">
+ <xsl:for-each select="marc:subfield[@code='f']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">marcgac</xsl:attribute>
+ <xsl:value-of select="."/>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <publisher>
+ <xsl:value-of select="."/>
+ </publisher>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <edition>
+ <xsl:value-of select="."/>
+ </edition>
+ </xsl:for-each>
+ </originInfo>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="relatedLanguage">
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="nameDate">
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <namePart type="date">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </namePart>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="subjectAuthority">
+ <xsl:attribute name="authority">
+ <xsl:choose>
+ <xsl:when test="@ind2=0">lcsh</xsl:when>
+ <xsl:when test="@ind2=1">lcshac</xsl:when>
+ <xsl:when test="@ind2=2">mesh</xsl:when>
+ <!-- 1/04 fix -->
+ <xsl:when test="@ind2=3">nal</xsl:when>
+ <xsl:when test="@ind2=5">csh</xsl:when>
+ <xsl:when test="@ind2=6">rvm</xsl:when>
+ <xsl:when test="@ind2=7">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:template>
+
+ <xsl:template name="subjectAnyOrder">
+ <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+ <xsl:choose>
+ <xsl:when test="@code='v'">
+ <xsl:call-template name="subjectTopic"/>
+ </xsl:when>
+ <xsl:when test="@code='x'">
+ <xsl:call-template name="subjectTopic"/>
+ </xsl:when>
+ <xsl:when test="@code='y'">
+ <xsl:call-template name="subjectTemporalY"/>
+ </xsl:when>
+ <xsl:when test="@code='z'">
+ <xsl:call-template name="subjectGeographicZ"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="specialSubfieldSelect">
+ <xsl:param name="anyCodes"/>
+ <xsl:param name="axis"/>
+ <xsl:param name="beforeCodes"/>
+ <xsl:param name="afterCodes"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($anyCodes, @code)
+ or (contains($beforeCodes,@code) and following-sibling::marc:subfield[@code=$axis])
+ or (contains($afterCodes,@code) and preceding-sibling::marc:subfield[@code=$axis])">
+ <xsl:value-of select="text()"/>
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=600]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="personal">
+ <xsl:call-template name="termsOfAddress"/>
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="nameDate"/>
+ <xsl:call-template name="affiliation"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=610]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=611]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="conference">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:for-each select="marc:subfield[@code='4']">
+ <role>
+ <roleTerm authority="marcrelator" type="code">
+ <xsl:value-of select="."/>
+ </roleTerm>
+ </role>
+ </xsl:for-each>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=630]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfhklor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:call-template name="part"/>
+ </title>
+ </titleInfo>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=650]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <topic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </topic>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=651]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <geographic>
+ <xsl:value-of select="."/>
+ </geographic>
+ </xsl:for-each>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=653]">
+ <subject>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <topic>
+ <xsl:value-of select="."/>
+ </topic>
+ </xsl:for-each>
+ </subject>
+ </xsl:template>
+
+ <xsl:template match="marc:datafield[@tag=656]">
+ <subject>
+ <xsl:if test="marc:subfield[@code=2]">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code=2]"/>
+ </xsl:attribute>
+ </xsl:if>
+ <occupation>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </occupation>
+ </subject>
+ </xsl:template>
+
+ <xsl:template name="termsOfAddress">
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <namePart type="termsOfAddress">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">bc</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="displayLabel">
+ <xsl:if test="marc:subfield[@code='i']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='i']"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='3']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='3']"/>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="isInvalid">
+ <xsl:if test="marc:subfield[@code='z']">
+ <xsl:attribute name="invalid">yes</xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="script">
+ <xsl:param name="scriptCode"/>
+ <xsl:attribute name="script">
+ <xsl:choose>
+ <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+ <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+ <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+ <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+ <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+ <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:template>
+
+ <xsl:template name="parsePart">
+ <!-- assumes 773$q= 1:2:3<4
+ with up to 3 levels and one optional start page
+ -->
+ <xsl:variable name="level1">
+ <xsl:choose>
+ <xsl:when test="contains(text(),':')"><!-- 1:2 -->
+ <xsl:value-of select="substring-before(text(),':')"/>
+ </xsl:when>
+ <xsl:when test="not(contains(text(),':'))"><!-- 1 or 1<3 -->
+ <xsl:if test="contains(text(),'<')"><!-- 1<3 -->
+ <xsl:value-of select="substring-before(text(),'<')"/>
+ </xsl:if>
+ <xsl:if test="not(contains(text(),'<'))"><!-- 1 -->
+ <xsl:value-of select="text()"/>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici2">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+ <xsl:value-of select="substring(substring-after(text(),$level1),2)"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="substring-after(text(),$level1)"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level2">
+ <xsl:choose>
+ <xsl:when test="contains($sici2,':')"><!-- 2:3<4 -->
+ <xsl:value-of select="substring-before($sici2,':')"/>
+ </xsl:when>
+ <xsl:when test="contains($sici2,'<')"><!-- 1: 2<4 -->
+ <xsl:value-of select="substring-before($sici2,'<')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici2"/><!-- 1:2 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici3">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+ <xsl:value-of select="substring(substring-after($sici2,$level2),2)"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="substring-after($sici2,$level2)"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level3">
+ <xsl:choose>
+ <xsl:when test="contains($sici3,'<')"><!-- 2<4 -->
+ <xsl:value-of select="substring-before($sici3,'<')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici3"/><!-- 3 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="page">
+ <xsl:if test="contains(text(),'<')">
+ <xsl:value-of select="substring-after(text(),'<')"/>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:if test="$level1">
+ <detail level = "1">
+ <number><xsl:value-of select="$level1"/></number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level2">
+ <detail level = "2">
+ <number><xsl:value-of select="$level2"/></number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level3">
+ <detail level = "3">
+ <number><xsl:value-of select="$level3"/></number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$page">
+ <extent unit="page">
+ <start><xsl:value-of select="$page"/></start>
+ </extent>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="getLanguage">
+ <xsl:param name="langString"/>
+ <xsl:param name="controlField008-35-37"/>
+ <xsl:variable name="length" select="string-length($langString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="substring($langString,1,3)"/>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="isoLanguage">
+ <xsl:param name="currentLanguage"/>
+ <xsl:param name="usedLanguages"/>
+ <xsl:param name="remainingLanguages"/>
+ <xsl:choose>
+ <xsl:when test="string-length($currentLanguage)=0"/>
+ <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage"><xsl:value-of select="substring($remainingLanguages,1,3)"/></xsl:with-param>
+ <xsl:with-param name="usedLanguages"><xsl:value-of select="concat($usedLanguages,$currentLanguage)"/></xsl:with-param>
+ <xsl:with-param name="remainingLanguages"><xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage"><xsl:value-of select="substring($remainingLanguages,1,3)"/></xsl:with-param>
+ <xsl:with-param name="usedLanguages"><xsl:value-of select="concat($usedLanguages,$currentLanguage)"/></xsl:with-param>
+ <xsl:with-param name="remainingLanguages"><xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="chopBrackets">
+ <xsl:param name="chopString"/>
+ <xsl:variable name="string">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$chopString"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="substring($string, 1,1)='['">
+ <xsl:value-of select="substring($string,2, string-length($string)-2)"/>
+ </xsl:if>
+ <xsl:if test="substring($string, 1,1)!='['">
+ <xsl:value-of select="$string"/>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="rfcLanguages">
+ <xsl:param name="langCodes"/>
+ <xsl:param name="nodeNum"/>
+ <xsl:param name="usedLanguages"/>
+ <xsl:param name="controlField008-35-37"/>
+ <xsl:variable name="currentLanguage" select="$langCodes/child::*[position()=$nodeNum]/text()"/>
+ <xsl:choose>
+ <xsl:when test="not($currentLanguage)"/>
+ <xsl:when test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+ <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+ <language>
+ <languageTerm authority="rfc3066" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ </xsl:if>
+ <xsl:call-template name="rfcLanguages">
+ <xsl:with-param name="langCodes"><xsl:copy-of select="$langCodes"/></xsl:with-param>
+ <xsl:with-param name="nodeNum"><xsl:value-of select="$nodeNum+1"/></xsl:with-param>
+ <xsl:with-param name="usedLanguages"><xsl:value-of select="concat($usedLanguages,$currentLanguage)"/></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37"><xsl:value-of select="$controlField008-35-37"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="rfcLanguages">
+ <xsl:with-param name="langCodes"><xsl:copy-of select="$langCodes"/></xsl:with-param>
+ <xsl:with-param name="nodeNum"><xsl:value-of select="$nodeNum+1"/></xsl:with-param>
+ <xsl:with-param name="usedLanguages"><xsl:value-of select="concat($usedLanguages,$currentLanguage)"/></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37"><xsl:value-of select="$controlField008-35-37"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+</xsl:stylesheet><!-- Stylus Studio meta-information - (c)1998-2003 Copyright Sonic Software Corporation. All rights reserved.
+<metaInformation>
+<scenarios ><scenario default="no" name="Scenario1" userelativepaths="yes" externalpreview="no" url="..\..\TESTSETS\marc\78x.xml" htmlbaseurl="" outputurl="..\..\TESTSETS\marc\78xmods.xml" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="v3Test" userelativepaths="yes" externalpreview="no" url="..\..\TESTSETS\marc\tempsubj.xml" htmlbaseurl="" outputurl="..\modsv3Test.xml" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="Apr 02 Test" userelativepaths="yes" externalpreview="no" url="..\..\TESTSETS\marc\MODStest.Apr.02.03.xml" htmlbaseurl="" outputurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="yes" name="v3Test1" userelativepaths="yes" externalpreview="no" url="..\test_files\marcxml.xml" htmlbaseurl="" outputurl="..\test_files\modsv3Converted.xml" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/></scenarios><MapperInfo srcSchemaPath="" srcSchemaRoot="" srcSchemaPathIsRelative="yes" srcSchemaInterpretAsXML="no" destSchemaPath="" destSchemaRoot="" destSchemaPathIsRelative="yes" destSchemaInterpretAsXML="no"/>
+</metaInformation>
+-->
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">\r
+ <xsl:import href="MARC21slimUtils.xsl"/>\r
+ <xsl:output method="xml" indent="yes"/>\r
+ \r
+ <xsl:template match="/">\r
+ <xsl:apply-templates/>\r
+ </xsl:template>\r
+\r
+ <xsl:template match="marc:record">\r
+ <xsl:variable name="leader" select="marc:leader"/>\r
+ <xsl:variable name="leader6" select="substring($leader,7,1)"/>\r
+ <xsl:variable name="leader7" select="substring($leader,8,1)"/>\r
+ <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>\r
+\r
+ <rdf:Description>\r
+ <xsl:for-each select="marc:datafield[@tag=245]">\r
+ <dc:title>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abfghk</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:title>\r
+ </xsl:for-each>\r
+\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=100]|marc:datafield[@tag=110]|marc:datafield[@tag=111]|marc:datafield[@tag=700]|marc:datafield[@tag=710]|marc:datafield[@tag=711]|marc:datafield[@tag=720]">\r
+ <dc:creator>\r
+ <xsl:value-of select="."/>\r
+ </dc:creator>\r
+ </xsl:for-each>\r
+\r
+ <dc:type> \r
+ <xsl:if test="$leader7='c'">\r
+ <xsl:attribute name="collection">yes</xsl:attribute>\r
+ </xsl:if>\r
+\r
+ <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">\r
+ <xsl:attribute name="manuscript">yes</xsl:attribute>\r
+ </xsl:if>\r
+\r
+ <xsl:choose>\r
+ <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>\r
+ <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>\r
+ <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>\r
+ <xsl:when test="$leader6='i' or $leader6='j'">sound recording</xsl:when>\r
+ <xsl:when test="$leader6='k'">still image</xsl:when>\r
+ <xsl:when test="$leader6='g'">moving image</xsl:when>\r
+ <xsl:when test="$leader6='r'">three dimensional object</xsl:when>\r
+ <xsl:when test="$leader6='m'">software, multimedia</xsl:when>\r
+ <xsl:when test="$leader6='p'">mixed material</xsl:when>\r
+ </xsl:choose>\r
+ </dc:type>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=655]">\r
+ <dc:type>\r
+ <xsl:value-of select="."/>\r
+ </dc:type>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=260]">\r
+ <dc:publisher>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ab</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:publisher>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='c']">\r
+ <dc:date>\r
+ <xsl:value-of select="."/>\r
+ </dc:date> \r
+ </xsl:for-each>\r
+\r
+ <dc:language>\r
+ <xsl:value-of select="substring($controlField008,36,3)"/>\r
+ </dc:language>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q']">\r
+ <dc:format>\r
+ <xsl:value-of select="."/>\r
+ </dc:format>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=520]">\r
+ <dc:description>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </dc:description>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=521]">\r
+ <dc:description>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </dc:description>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[500<@tag][@tag<=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">\r
+ <dc:description>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </dc:description>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=600]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=610]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=611]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+ \r
+ <xsl:for-each select="marc:datafield[@tag=630]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=650]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=653]">\r
+ <dc:subject>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdq</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:subject>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=752]">\r
+ <dc:coverage>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcd</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:coverage>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=530]">\r
+ <dc:relation type="original">\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">abcdu</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:relation> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]|marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=770]|marc:datafield[@tag=772]|marc:datafield[@tag=773]|marc:datafield[@tag=774]|marc:datafield[@tag=775]|marc:datafield[@tag=776]|marc:datafield[@tag=777]|marc:datafield[@tag=780]|marc:datafield[@tag=785]|marc:datafield[@tag=786]|marc:datafield[@tag=787]">\r
+ <dc:relation>\r
+ <xsl:call-template name="subfieldSelect">\r
+ <xsl:with-param name="codes">ot</xsl:with-param>\r
+ </xsl:call-template>\r
+ </dc:relation> \r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=856]">\r
+ <dc:identifier>\r
+ <xsl:value-of select="marc:subfield[@code='u']"/>\r
+ </dc:identifier>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=506]">\r
+ <dc:rights>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </dc:rights>\r
+ </xsl:for-each>\r
+\r
+ <xsl:for-each select="marc:datafield[@tag=540]">\r
+ <dc:rights>\r
+ <xsl:value-of select="marc:subfield[@code='a']"/>\r
+ </dc:rights>\r
+ </xsl:for-each>\r
+ </rdf:Description>\r
+ </xsl:template>\r
+</xsl:stylesheet><!-- Stylus Studio meta-information - (c)1998-2002 eXcelon Corp.\r
+<metaInformation>\r
+<scenarios ><scenario default="no" name="MODS Website Samples" userelativepaths="yes" externalpreview="no" url="..\xml\MARC21slim\modswebsitesamples.xml" htmlbaseurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="Ray Charles" userelativepaths="yes" externalpreview="no" url="..\xml\MARC21slim\raycharles.xml" htmlbaseurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="yes" name="s6" userelativepaths="yes" externalpreview="no" url="..\ifla\sally6.xml" htmlbaseurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="s7" userelativepaths="yes" externalpreview="no" url="..\ifla\sally7.xml" htmlbaseurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/><scenario default="no" name="s12" userelativepaths="yes" externalpreview="no" url="..\ifla\sally12.xml" htmlbaseurl="" processortype="internal" commandline="" additionalpath="" additionalclasspath="" postprocessortype="none" postprocesscommandline="" postprocessadditionalpath="" postprocessgeneratedext=""/></scenarios><MapperInfo srcSchemaPath="" srcSchemaRoot="" srcSchemaPathIsRelative="yes" srcSchemaInterpretAsXML="no" destSchemaPath="" destSchemaRoot="" destSchemaPathIsRelative="yes" destSchemaInterpretAsXML="no"/>\r
+</metaInformation>\r
+-->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:marc="http://www.loc.gov/MARC21/slim"
+ xmlns:srw_dc="info:srw/schema/1/dc-schema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://purl.org/dc/elements/1.1/"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:import href="MARC21slimUtils.xsl"/>
+ <xsl:output method="xml" indent="yes"/>
+<!-- modification log
+ NT 01/04: added collection level element
+ and removed attributes
+
+-->
+ <xsl:template match="/">
+ <srw_dc:dc xsi:schemaLocation="http://www.loc.gov/z3950/agency/zing/srw/dc-schema.xsd">
+ <xsl:apply-templates select="marc:record"/>
+ </srw_dc:dc>
+ </xsl:template>
+
+ <xsl:template match="marc:record">
+ <xsl:variable name="leader" select="marc:leader"/>
+ <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+ <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+ <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>
+
+ <xsl:for-each select="marc:datafield[@tag=245]">
+ <title>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abfghk</xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=100]|marc:datafield[@tag=110]|marc:datafield[@tag=111]|marc:datafield[@tag=700]|marc:datafield[@tag=710]|marc:datafield[@tag=711]|marc:datafield[@tag=720]">
+ <creator>
+ <xsl:value-of select="normalize-space(.)"/>
+ </creator>
+ </xsl:for-each>
+
+ <type>
+ <xsl:if test="$leader7='c'">
+ <!-- nt fix 1/04 -->
+ <!--<xsl:attribute name="collection">yes</xsl:attribute>-->
+ <xsl:text>collection</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+ <!-- nt fix 1/04 -->
+ <!--<xsl:attribute name="manuscript">yes</xsl:attribute> -->
+ <xsl:text>manuscript</xsl:text>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+ <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+ <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+ <xsl:when test="$leader6='i' or $leader6='j'">sound recording</xsl:when>
+ <xsl:when test="$leader6='k'">still image</xsl:when>
+ <xsl:when test="$leader6='g'">moving image</xsl:when>
+ <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+ <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+ <xsl:when test="$leader6='p'">mixed material</xsl:when>
+ </xsl:choose>
+ </type>
+
+ <xsl:for-each select="marc:datafield[@tag=655]">
+ <type>
+ <xsl:value-of select="normalize-space(.)"/>
+ </type>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]">
+ <publisher>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ab</xsl:with-param>
+ </xsl:call-template>
+ </publisher>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='c']">
+ <date>
+ <xsl:value-of select="."/>
+ </date>
+ </xsl:for-each>
+
+ <language>
+ <xsl:value-of select="substring($controlField008,36,3)"/>
+ </language>
+
+ <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q']">
+ <format>
+ <xsl:value-of select="."/>
+ </format>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=520]">
+ <description>
+ <!-- nt fix 01/04 -->
+ <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+ </description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=521]">
+ <description>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[500<@tag][@tag<=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
+ <description>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </description>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=600]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=610]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=611]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=630]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=650]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=653]">
+ <subject>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdq</xsl:with-param>
+ </xsl:call-template>
+ </subject>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=752]">
+ <coverage>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </coverage>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=530]">
+ <!-- nt 01/04 attribute fix -->
+ <relation>
+ <!--<xsl:attribute name="type">original</xsl:attribute>-->
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdu</xsl:with-param>
+ </xsl:call-template>
+ </relation>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]|marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=770]|marc:datafield[@tag=772]|marc:datafield[@tag=773]|marc:datafield[@tag=774]|marc:datafield[@tag=775]|marc:datafield[@tag=776]|marc:datafield[@tag=777]|marc:datafield[@tag=780]|marc:datafield[@tag=785]|marc:datafield[@tag=786]|marc:datafield[@tag=787]">
+ <relation>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">ot</xsl:with-param>
+ </xsl:call-template>
+ </relation>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=856]">
+ <identifier>
+ <xsl:value-of select="marc:subfield[@code='u']"/>
+ </identifier>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=506]">
+ <rights>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </rights>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=540]">
+ <rights>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </rights>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0'?>\r
+<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\r
+ <xsl:template name="datafield">\r
+ <xsl:param name="tag"/>\r
+ <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>\r
+ <xsl:param name="ind2"><xsl:text> </xsl:text></xsl:param>\r
+ <xsl:param name="subfields"/>\r
+ <xsl:element name="datafield">\r
+ <xsl:attribute name="tag">\r
+ <xsl:value-of select="$tag"/>\r
+ </xsl:attribute>\r
+ <xsl:attribute name="ind1">\r
+ <xsl:value-of select="$ind1"/>\r
+ </xsl:attribute>\r
+ <xsl:attribute name="ind2">\r
+ <xsl:value-of select="$ind2"/>\r
+ </xsl:attribute>\r
+ <xsl:copy-of select="$subfields"/>\r
+ </xsl:element>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="subfieldSelect">\r
+ <xsl:param name="codes"/>\r
+ <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>\r
+ <xsl:variable name="str">\r
+ <xsl:for-each select="marc:subfield">\r
+ <xsl:if test="contains($codes, @code)">\r
+ <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>\r
+ </xsl:if>\r
+ </xsl:for-each>\r
+ </xsl:variable>\r
+ <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="buildSpaces">\r
+ <xsl:param name="spaces"/>\r
+ <xsl:param name="char"><xsl:text> </xsl:text></xsl:param>\r
+ <xsl:if test="$spaces>0">\r
+ <xsl:value-of select="$char"/>\r
+ <xsl:call-template name="buildSpaces">\r
+ <xsl:with-param name="spaces" select="$spaces - 1"/>\r
+ <xsl:with-param name="char" select="$char"/>\r
+ </xsl:call-template>\r
+ </xsl:if>\r
+ </xsl:template>\r
+\r
+ <xsl:template name="chopPunctuation">\r
+ <xsl:param name="chopString"/>\r
+ <xsl:variable name="length" select="string-length($chopString)"/>\r
+ <xsl:choose>\r
+ <xsl:when test="$length=0"/>\r
+ <xsl:when test="contains('.:,;/ ', substring($chopString,$length,1))">\r
+ <xsl:call-template name="chopPunctuation">\r
+ <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>\r
+ </xsl:call-template>\r
+ </xsl:when>\r
+ <xsl:when test="not($chopString)"/>\r
+ <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>\r
+ </xsl:choose>\r
+ </xsl:template>\r
+</xsl:stylesheet><!-- Stylus Studio meta-information - (c)1998-2002 eXcelon Corp.\r
+<metaInformation>\r
+<scenarios/><MapperInfo srcSchemaPath="" srcSchemaRoot="" srcSchemaPathIsRelative="yes" srcSchemaInterpretAsXML="no" destSchemaPath="" destSchemaRoot="" destSchemaPathIsRelative="yes" destSchemaInterpretAsXML="no"/>\r
+</metaInformation>\r
+-->
\ No newline at end of file
--- /dev/null
+# $Id: Makefile.am,v 1.1 2004-04-11 11:37:00 adam Exp $
+
+proxydatadir=$(datadir)/yazproxy
+proxydata_DATA = \
+ MARC21slim2DC.xsl \
+ MARC21slim2SRWDC.xsl \
+ MARC21slim2MODS.xsl \
+ MARC21slim2MODS3.xsl \
+ MARC21slim2RDFDC.xsl \
+ MARC21slimUtils.xsl \
+ config.xml \
+ voyager.xml \
+ pqf.properties \
+ yaz-proxy.sh
+
+EXTRA_DIST = $(proxydata_DATA)
+
+noinst_SCRIPTS = yaz-proxy.sh
--- /dev/null
+<?xml version="1.0"?>
+<!-- $Id: config.xml,v 1.1 2004-04-11 11:37:01 adam Exp $ -->
+<proxy>
+ <target name="bagel">
+ <url>indexdata.dk</url>
+ <target-timeout>240</target-timeout>
+ <client-timeout>180</client-timeout>
+ <keepalive>
+ <bandwidth>1000000</bandwidth>
+ <pdu>1000</pdu>
+ </keepalive>
+ <limit><!-- per minute limits .. -->
+ <bandwidth>2000000</bandwidth>
+ <pdu>50</pdu>
+ <retrieve>100</retrieve>
+ </limit>
+ <attribute type="1" value="1-11,13-1010"/>
+ <attribute type="1" value="*" error="114"/>
+ <syntax type="opac"/>
+ <syntax type="usmarc"/>
+ <syntax type="none"/>
+ <syntax type="xml" marcxml="1"/>
+ <syntax type="*" error="238"/>
+ <preinit>0</preinit>
+ <cql2rpn>pqf.properties</cql2rpn>
+ <zeerex>zeerex.xml</zeerex>
+ </target>
+ <target default="1" name="localhost">
+ <url>localhost:9999</url>
+ <target-timeout>300</target-timeout>
+ <client-timeout>180</client-timeout>
+ <keepalive/> <!-- keepalive enabled -->
+ <limit><!-- limits .. -->
+ <bandwidth>50000</bandwidth>
+ <pdu>60</pdu>
+ <retrieve>50</retrieve>
+ </limit>
+ <attribute type="1" value="1-1023"/>
+ <attribute type="1" value="*" error="114"/>
+ <syntax type="usmarc"/>
+ <syntax type="grs1"/>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2SRWDC.xsl"
+ identifier="info:srw/schema/1/dc-v1.1"
+ >
+ <name>dc</name>
+ </syntax>
+ <syntax type="xml" marcxml="1"
+ identifier="info:srw/schema/1/marcxml-v1.1"
+ >
+ <name>marcxml</name>
+ </syntax>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2MODS.xsl"
+ identifier="http://www.loc.gov/mods"
+ >
+ <name>mods2</name>
+ </syntax>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2MODS3.xsl"
+ identifier="info:srw/schema/1/mods-v3.0"
+ >
+ <name>mods3</name>
+ </syntax>
+ <syntax type="none"/>
+ <syntax type="*" error="238"/>
+ <preinit>2</preinit>
+ <cql2rpn>pqf.properties</cql2rpn>
+ <explain>
+ <serverInfo>
+ <host>indexdata.dk</host>
+ <port>9000</port>
+ <database>Default</database>
+ </serverInfo>
+ </explain>
+ </target>
+ <target name="*">
+ <!-- everything else -->
+ </target>
+ <max-clients>50</max-clients>
+ <log>client-requests server-requests</log>
+</proxy>
--- /dev/null
+# $Id: pqf.properties,v 1.1 2004-04-11 11:36:54 adam Exp $
+#
+# Propeties file to drive org.z3950.zing.cql.CQLNode's toPQF()
+# back-end and the YAZ CQL-to-PQF converter. This specifies the
+# interpretation of various CQL indexes, relations, etc. in terms
+# of Type-1 query attributes.
+#
+# This configuration file generates queries using BIB-1 attributes.
+# See http://www.loc.gov/z3950/agency/zing/cql/dc-indexes.html
+# for the Maintenance Agency's work-in-progress mapping of Dublin Core
+# indexes to Attribute Architecture (util, XD and BIB-2)
+# attributes.
+
+# Identifiers for prefixes used in this file. (index.*)
+set.cql = info:srw/cql-context-set/1/cql-v1.1
+set.rec = info:srw/cql-context-set/2/rec-1.0
+set.dc = info:srw/cql-context-set/1/dc-v1.1
+set.bath = http://zing.z3950.org/cql/bath/2.0/
+
+# default set (in query)
+set = info:srw/cql-context-set/1/dc-v1.1
+
+# The default access point and result-set references
+index.cql.serverChoice = 1=1016
+ # srw.serverChoice is deprecated in favour of cql.serverChoice
+ # BIB-1 "any"
+
+index.rec.id = 1=12
+
+index.dc.title = 1=4
+index.dc.subject = 1=21
+index.dc.creator = 1=1003
+index.dc.author = 1=1003
+ ### Unofficial synonym for "creator"
+index.dc.editor = 1=1020
+index.dc.publisher = 1=1018
+index.dc.description = 1=62
+ # "abstract"
+index.dc.date = 1=30
+index.dc.resourceType = 1=1031
+ # guesswork: "Material-type"
+index.dc.format = 1=1034
+ # guesswork: "Content-type"
+index.dc.resourceIdentifier = 1=12
+ # "Local number"
+index.dc.source = 1=1019
+ # "Record-source"
+index.dc.language = 1=54
+ # "Code--language"
+index.dc.relation = 1=?
+ ### No idea how to represent this
+index.dc.coverage = 1=?
+ ### No idea how to represent this
+index.dc.rights = 1=?
+ ### No idea how to represent this
+
+# Relation attributes are selected according to the CQL relation by
+# looking up the "relation.<relation>" property:
+#
+relation.< = 2=1
+relation.le = 2=2
+relation.eq = 2=3
+relation.exact = 2=3
+relation.ge = 2=4
+relation.> = 2=5
+relation.<> = 2=6
+
+### These two are not really right:
+relation.all = 2=3
+relation.any = 2=3
+
+# BIB-1 doesn't have a server choice relation, so we just make the
+# choice here, and use equality (which is clearly correct).
+relation.scr = 2=3
+
+# Relation modifiers.
+#
+relationModifier.relevant = 2=102
+relationModifier.fuzzy = 2=100
+ ### 100 is "phonetic", which is not quite the same thing
+relationModifier.stem = 2=101
+relationModifier.phonetic = 2=100
+
+# Position attributes may be specified for anchored terms (those
+# beginning with "^", which is stripped) and unanchored (those not
+# beginning with "^"). This may change when we get a BIB-1 truncation
+# attribute that says "do what CQL does".
+#
+position.first = 3=1 6=1
+ # "first in field"
+position.any = 3=3 6=1
+ # "any position in field"
+position.last = 3=4 6=1
+ # not a standard BIB-1 attribute
+position.firstAndLast = 3=3 6=3
+ # search term is anchored to be complete field
+
+# Structure attributes may be specified for individual relations; a
+# default structure attribute my be specified by the pseudo-relation
+# "*", to be used whenever a relation not listed here occurs.
+#
+structure.exact = 4=108
+ # string
+structure.all = 4=2
+structure.any = 4=2
+structure.* = 4=1
+ # phrase
+
+# Truncation attributes used to implement CQL wildcard patterns. The
+# simpler forms, left, right- and both-truncation will be used for the
+# simplest patterns, so that we produce PQF queries that conform more
+# closely to the Bath Profile. However, when a more complex pattern
+# such as "foo*bar" is used, we fall back on Z39.58-style masking.
+#
+truncation.right = 5=1
+truncation.left = 5=2
+truncation.both = 5=3
+truncation.none = 5=100
+truncation.z3958 = 5=104
+
+# Finally, any additional attributes that should always be included
+# with each term can be specified in the "always" property.
+#
+always = 6=1
+# 6=1: completeness = incomplete subfield
+
+
+# Bath Profile support, added Thu Dec 18 13:06:20 GMT 2003
+# See the Bath Profile for SRW at
+# http://zing.z3950.org/cql/bath.html
+# including the Bath Context Set defined within that document.
+#
+# In this file, we only map index-names to BIB-1 use attributes, doing
+# so in accordance with the specifications of the Z39.50 Bath Profile,
+# and leaving the relations, wildcards, etc. to fend for themselves.
+
+index.bath.keyTitle = 1=33
+index.bath.possessingInstitution = 1=1044
+index.bath.name = 1=1002
+index.bath.personalName = 1=1
+index.bath.corporateName = 1=2
+index.bath.conferenceName = 1=3
+index.bath.uniformTitle = 1=6
+index.bath.isbn = 1=7
+index.bath.issn = 1=8
+index.bath.geographicName = 1=58
+index.bath.notes = 1=63
+index.bath.topicalSubject = 1=1079
+index.bath.genreForm = 1=1075
+
--- /dev/null
+<?xml version="1.0"?>
+<!-- $Id: voyager.xml,v 1.1 2004-04-11 11:37:01 adam Exp $ -->
+<proxy>
+ <!-- define default target and name it voyager -->
+ <target default="1" name="voyager">
+ <!-- all backend addresses as seen from this proxy .. -->
+ <url>z3950.loc.gov:7090</url>
+
+ <!-- set session timeout between proxy and backend target -->
+ <target-timeout>300</target-timeout>
+
+ <!-- set session timeout between client and proxy.
+ Should be lower than target-timeout -->
+ <client-timeout>180</client-timeout>
+
+ <!-- if either bandwidth or pdu limit is reached the session is no
+ longer kept alive -->
+ <keepalive>
+ <bandwidth>500000</bandwidth>
+ <pdu>500</pdu>
+ </keepalive>
+
+ <!-- client limits .. -->
+ <limit>
+ <bandwidth>200000</bandwidth>
+ <pdu>31</pdu>
+ <retrieve>50</retrieve>
+ </limit>
+
+ <!-- use attributes -->
+ <attribute type="1" value="1-11,13-1010,1013-1023,1025-1030"/>
+ <attribute type="1" value="*" error="114"/>
+
+ <!-- relation attributes -->
+ <attribute type="2" value="1,2,3,4,5,6"/>
+ <attribute type="2" value="*" error="117"/>
+
+ <!-- position attributes -->
+ <attribute type="3" value="1,2,3"/>
+ <attribute type="3" value="*" error="119"/>
+
+ <!-- structure attributes -->
+ <attribute type="4" value="1,2,3,4,5,6"/>
+ <attribute type="4" value="*" error="118"/>
+
+ <!-- truncation attributes -->
+ <attribute type="5" value="1,100"/>
+ <attribute type="5" value="*" error="120"/>
+
+ <!-- completeness attributes -->
+ <attribute type="6" value="1,2,3"/>
+ <attribute type="6" value="*" error="122"/>
+
+ <!-- other types -->
+ <attribute type="*" value="*" error="113"/>
+
+ <!-- list allowed record syntaxes and possible schemas (if any);
+ reject all others at the end -->
+ <syntax type="opac"/>
+ <syntax type="usmarc"/>
+ <syntax type="none"/>
+
+ <syntax type="xml" marcxml="1"
+ identifier="info:srw/schema/1/marcxml-v1.1"
+ >
+ <title>MARCXML</title>
+ <name>marcxml</name>
+ </syntax>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2SRWDC.xsl"
+ identifier="info:srw/schema/1/dc-v1.1"
+ >
+ <title>Dublin Core</title>
+ <name>dc</name>
+ </syntax>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2MODS.xsl"
+ identifier="http://www.loc.gov/mods"
+ >
+ <title>MODS v2</title>
+ <name>mods2</name>
+ </syntax>
+ <syntax type="xml" marcxml="1" stylesheet="MARC21slim2MODS3.xsl"
+ identifier="info:srw/schema/1/mods-v3.0"
+ >
+ <title>MODS v3</title>
+ <name>mods3</name>
+ <name>mods</name>
+ </syntax>
+
+ <syntax type="*" error="238"/>
+
+ <!-- keep this number of spare sessions for future sessions -->
+ <preinit>2</preinit>
+
+ <explain xmlns="http://explain.z3950.org/dtd/2.0/">
+ <serverInfo>
+ <host>indexdata.dk</host>
+ <port>9000</port>
+ <database>voyager</database>
+ </serverInfo>
+
+ <databaseInfo>
+ <title>LoC gateway</title>
+ <description lang="en" primary="true">
+ SRW/SRU/Z39.50 Gateway to Library of Congress' Z39.50 server
+ </description>
+ </databaseInfo>
+
+ <indexInfo>
+ <set identifier="info:srw/cql-context-set/1/cql-v1.1"
+ name="cql"/>
+ <set identifier="info:srw/cql-context-set/1/dc-v1.1"
+ name="dc"/>
+ <set identifier="http://zing.z3950.org/cql/bath/2.0/"
+ name="bath"/>
+
+ <index id="4">
+ <title>title</title>
+ <map><name set="dc">title</name></map>
+ </index>
+ <index id="21">
+ <title>subject</title>
+ <map><name set="dc">subject</name></map>
+ </index>
+ <index id="1003">
+ <title>creator</title>
+ <map><name set="dc">creator</name></map>
+ <map><name set="dc">author</name></map>
+ </index>
+
+ <index id="1020">
+ <title>editor</title>
+ <map><name set="dc">editor</name></map>
+ </index>
+
+ <index id="1018">
+ <title>publisher</title>
+ <map><name set="dc">publisher</name></map>
+ </index>
+
+ <index id="62">
+ <title>description</title>
+ <map><name set="dc">description</name></map>
+ </index>
+
+ <index id="30">
+ <title>date</title>
+ <map><name set="dc">date</name></map>
+ </index>
+
+ <index id="1002">
+ <title>name</title>
+ <map><name set="bath">name</name></map>
+ </index>
+
+ <index id="7">
+ <title>isbn</title>
+ <map><name set="bath">isbn</name></map>
+ </index>
+ <index id="8">
+ <title>issn</title>
+ <map><name set="bath">issn</name></map>
+ </index>
+ </indexInfo>
+
+ <schemaInfo>
+ <schema identifier="info:srw/schema/1/marcxml-v1.1"
+ sort="false" name="marcxml">
+ <title>MARCXML</title>
+ </schema>
+
+ <schema identifier="info:srw/schema/1/dc-v1.1"
+ sort="false" name="dc">
+ <title>Dublin Core</title>
+ </schema>
+
+ <schema identifier="http://www.loc.gov/mods"
+ sort="false" name="mods2">
+ <title>MODS v2</title>
+ </schema>
+
+ <schema identifier="info:srw/schema/1/mods-v3.0"
+ sort="false" name="mods">
+ <title>MODS v3</title>
+ </schema>
+
+ </schemaInfo>
+
+ <configInfo>
+ <default type="numberOfRecords">0</default>
+ </configInfo>
+ </explain>
+ <cql2rpn>pqf.properties</cql2rpn>
+ </target>
+
+
+ <!-- maximum number of client sessions. Remember to allow for
+ at least max-clients*2+5 sockets. Use 'ulimit -n 1040' on bash -->
+ <max-clients>500</max-clients>
+
+ <!-- what we log. Allowed tokens: client-apdu, server-apdu,
+ client-requests, server-requests -->
+ <log>client-requests server-requests</log>
+</proxy>
--- /dev/null
+
+SUBDIRS = yazproxy
--- /dev/null
+
+proxyincludedir=$(pkgincludedir)/proxy
+
+proxyinclude_HEADERS = proxy.h bw.h
--- /dev/null
+/* $Id: bw.h,v 1.1 2004-04-11 11:37:01 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+class YAZ_EXPORT Yaz_bw {
+ public:
+ Yaz_bw(int sz);
+ ~Yaz_bw();
+ void add_bytes(int m);
+ int get_total();
+ private:
+ long m_sec; // time of most recent bucket
+ int *m_bucket;
+ int m_ptr;
+ int m_size;
+};
+
--- /dev/null
+/* $Id: proxy.h,v 1.1 2004-04-11 11:37:01 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#if HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+#include <yaz++/z-assoc.h>
+#include <yaz++/z-query.h>
+#include <yaz++/z-databases.h>
+#include <yaz++/cql2rpn.h>
+#include <yaz/cql.h>
+#include <yaz++/proxy/bw.h>
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+#endif
+
+class Yaz_Proxy;
+
+#define MAX_ZURL_PLEX 10
+
+#define PROXY_LOG_APDU_CLIENT 1
+#define PROXY_LOG_APDU_SERVER 2
+#define PROXY_LOG_REQ_CLIENT 4
+#define PROXY_LOG_REQ_SERVER 8
+
+struct Yaz_RecordCache_Entry;
+
+class YAZ_EXPORT Yaz_ProxyConfig {
+public:
+ Yaz_ProxyConfig();
+ ~Yaz_ProxyConfig();
+ int read_xml(const char *fname);
+
+ int get_target_no(int no,
+ const char **name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn);
+
+ void get_generic_info(int *log_mask, int *max_clients);
+
+ void get_target_info(const char *name, const char **url,
+ int *limit_bw, int *limit_pdu, int *limit_req,
+ int *target_idletime, int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw, int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn);
+
+ int check_query(ODR odr, const char *name, Z_Query *query, char **addinfo);
+ int check_syntax(ODR odr, const char *name,
+ Odr_oid *syntax, Z_RecordComposition *comp,
+ char **addinfo, char **stylesheet, char **schema);
+ char *get_explain(ODR odr, const char *name, const char *db,
+ int *len);
+private:
+ void operator=(const Yaz_ProxyConfig &conf);
+ int mycmp(const char *hay, const char *item, size_t len);
+#if HAVE_XSLT
+ int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
+ const char *schema_identifier);
+ xmlDocPtr m_docPtr;
+ xmlNodePtr m_proxyPtr;
+ void return_target_info(xmlNodePtr ptr, const char **url,
+ int *limit_bw, int *limit_pdu, int *limit_req,
+ int *target_idletime, int *client_idletime,
+ int *keepalive_limit_bw, int *keepalive_limit_pdu,
+ int *pre_init, const char **cql2rpn);
+ void return_limit(xmlNodePtr ptr,
+ int *limit_bw, int *limit_pdu, int *limit_req);
+ int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+ char **addinfo);
+ xmlNodePtr find_target_node(const char *name, const char *db);
+ xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
+ const char *get_text(xmlNodePtr ptr);
+ int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
+ Z_AttributeList *attrs,
+ char **addinfo);
+ int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
+ char **addinfo);
+#endif
+ int m_copy;
+ int match_list(int v, const char *m);
+ int atoi_l(const char **cp);
+};
+
+class YAZ_EXPORT Yaz_RecordCache {
+ public:
+ Yaz_RecordCache ();
+ ~Yaz_RecordCache ();
+ void add (ODR o, Z_NamePlusRecordList *npr, int start, int hits);
+
+ int lookup (ODR o, Z_NamePlusRecordList **npr, int start, int num,
+ Odr_oid *syntax, Z_RecordComposition *comp);
+ void clear();
+
+ void copy_searchRequest(Z_SearchRequest *sr);
+ void copy_presentRequest(Z_PresentRequest *pr);
+ void set_max_size(int sz);
+ private:
+ NMEM m_mem;
+ Yaz_RecordCache_Entry *m_entries;
+ Z_SearchRequest *m_searchRequest;
+ Z_PresentRequest *m_presentRequest;
+ int match (Yaz_RecordCache_Entry *entry,
+ Odr_oid *syntax, int offset,
+ Z_RecordComposition *comp);
+ int m_max_size;
+};
+
+/// Private class
+class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc {
+ friend class Yaz_Proxy;
+ Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent);
+ ~Yaz_ProxyClient();
+ void recv_GDU(Z_GDU *apdu, int len);
+ void recv_Z_PDU(Z_APDU *apdu, int len);
+ void recv_HTTP_response(Z_HTTP_Response *apdu, int len);
+ IYaz_PDU_Observer* sessionNotify
+ (IYaz_PDU_Observable *the_PDU_Observable, int fd);
+ void shutdown();
+ Yaz_Proxy *m_server;
+ void failNotify();
+ void timeoutNotify();
+ void connectNotify();
+ int send_to_target(Z_APDU *apdu);
+ const char *get_session_str();
+ char *m_cookie;
+ Yaz_ProxyClient *m_next;
+ Yaz_ProxyClient **m_prev;
+ int m_init_flag;
+ Yaz_Z_Query *m_last_query;
+ Yaz_Z_Databases m_last_databases;
+ char *m_last_resultSetId;
+ int m_last_ok;
+ int m_last_resultCount;
+ int m_sr_transform;
+ int m_seqno;
+ int m_waiting;
+ int m_resultSetStartPoint;
+ int m_bytes_sent;
+ int m_bytes_recv;
+ int m_pdu_recv;
+ ODR m_init_odr;
+ Z_APDU *m_initResponse;
+ Z_Options *m_initResponse_options;
+ Z_ProtocolVersion *m_initResponse_version;
+ int m_initResponse_preferredMessageSize;
+ int m_initResponse_maximumRecordSize;
+ Yaz_RecordCache m_cache;
+ void pre_init_client();
+ int m_target_idletime;
+ Yaz_Proxy *m_root;
+};
+
+
+/// Information Retrieval Proxy Server.
+class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
+ private:
+ char *get_cookie(Z_OtherInformation **otherInfo);
+ char *get_proxy(Z_OtherInformation **otherInfo);
+ Yaz_ProxyClient *get_client(Z_APDU *apdu, const char *cookie,
+ const char *proxy_host);
+ Z_APDU *result_set_optimize(Z_APDU *apdu);
+ void shutdown();
+
+ Yaz_ProxyClient *m_client;
+ IYaz_PDU_Observable *m_PDU_Observable;
+ Yaz_ProxyClient *m_clientPool;
+ Yaz_Proxy *m_parent;
+ int m_seqno;
+ int m_max_clients;
+ int m_log_mask;
+ int m_keepalive_limit_bw;
+ int m_keepalive_limit_pdu;
+ int m_client_idletime;
+ int m_target_idletime;
+ char *m_proxyTarget;
+ char *m_default_target;
+ char *m_proxy_authentication;
+ long m_seed;
+ char *m_optimize;
+ int m_session_no; // sequence for each client session
+ char m_session_str[30]; // session string (time:session_no)
+ Yaz_ProxyConfig *m_config;
+ char *m_config_fname;
+ int m_bytes_sent;
+ int m_bytes_recv;
+ int m_bw_max;
+ Yaz_bw m_bw_stat;
+ int m_pdu_max;
+ Yaz_bw m_pdu_stat;
+ Z_GDU *m_bw_hold_PDU;
+ int m_max_record_retrieve;
+ void handle_max_record_retrieve(Z_APDU *apdu);
+ void display_diagrecs(Z_DiagRec **pp, int num);
+ Z_Records *create_nonSurrogateDiagnostics(ODR o, int error,
+ const char *addinfo);
+
+ Z_APDU *handle_query_validation(Z_APDU *apdu);
+ Z_APDU *handle_query_transformation(Z_APDU *apdu);
+
+ Z_APDU *handle_syntax_validation(Z_APDU *apdu);
+ const char *load_balance(const char **url);
+ int m_reconfig_flag;
+ Yaz_ProxyConfig *check_reconfigure();
+ int m_request_no;
+ int m_invalid_session;
+ int m_marcxml_flag;
+#if HAVE_XSLT
+ xsltStylesheetPtr m_stylesheet_xsp;
+#else
+ void *m_stylesheet_xsp;
+#endif
+ int m_stylesheet_offset;
+ Z_APDU *m_stylesheet_apdu;
+ Z_NamePlusRecordList *m_stylesheet_nprl;
+ char *m_schema;
+ void convert_to_marcxml(Z_NamePlusRecordList *p);
+ int convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu);
+ void convert_xsl_delay();
+ Z_APDU *m_initRequest_apdu;
+ int m_initRequest_preferredMessageSize;
+ int m_initRequest_maximumRecordSize;
+ Z_Options *m_initRequest_options;
+ Z_ProtocolVersion *m_initRequest_version;
+ NMEM m_initRequest_mem;
+ Z_APDU *m_apdu_invalid_session;
+ NMEM m_mem_invalid_session;
+ int send_PDU_convert(Z_APDU *apdu);
+ ODR m_s2z_odr_init;
+ ODR m_s2z_odr_search;
+ int m_s2z_hit_count;
+ int m_s2z_packing;
+ char *m_s2z_database;
+ Z_APDU *m_s2z_init_apdu;
+ Z_APDU *m_s2z_search_apdu;
+ Z_APDU *m_s2z_present_apdu;
+ char *m_s2z_stylesheet;
+ char *m_soap_ns;
+ int send_to_srw_client_error(int error, const char *add);
+ int send_to_srw_client_ok(int hits, Z_Records *records, int start);
+ int send_http_response(int code);
+ int send_srw_response(Z_SRW_PDU *srw_pdu);
+ int send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+ int num_diagnostics);
+ int z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
+ Z_DefaultDiagFormat *ddf);
+ int m_http_keepalive;
+ const char *m_http_version;
+ Yaz_cql2rpn m_cql2rpn;
+#if HAVE_GETTIMEOFDAY
+ struct timeval m_time_tv;
+#endif
+ void logtime();
+ Z_ElementSetNames *mk_esn_from_schema(ODR o, const char *schema);
+ Z_ReferenceId *m_referenceId;
+ NMEM m_referenceId_mem;
+#define NO_SPARE_SOLARIS_FD 10
+ int m_lo_fd[NO_SPARE_SOLARIS_FD];
+ void low_socket_open();
+ void low_socket_close();
+ public:
+ Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent = 0);
+ ~Yaz_Proxy();
+ void inc_request_no();
+ void recv_GDU(Z_GDU *apdu, int len);
+ void handle_incoming_HTTP(Z_HTTP_Request *req);
+ void handle_incoming_Z_PDU(Z_APDU *apdu);
+ IYaz_PDU_Observer* sessionNotify
+ (IYaz_PDU_Observable *the_PDU_Observable, int fd);
+ void failNotify();
+ void timeoutNotify();
+ void connectNotify();
+ void markInvalid();
+ const char *option(const char *name, const char *value);
+ void set_default_target(const char *target);
+ void set_proxy_authentication (const char *auth);
+ char *get_proxy_target() { return m_proxyTarget; };
+ char *get_session_str() { return m_session_str; };
+ void set_max_clients(int m) { m_max_clients = m; };
+ void set_client_idletime (int t) { m_client_idletime = (t > 1) ? t : 600; };
+ void set_target_idletime (int t) { m_target_idletime = (t > 1) ? t : 600; };
+ int get_target_idletime () { return m_target_idletime; }
+ int set_config(const char *name);
+ void reconfig() { m_reconfig_flag = 1; }
+ int send_to_client(Z_APDU *apdu);
+ int server(const char *addr);
+ void pre_init();
+ int get_log_mask() { return m_log_mask; };
+ int handle_init_response_for_invalid_session(Z_APDU *apdu);
+};
+
--- /dev/null
+## $Id: Makefile.am,v 1.1 2004-04-11 11:36:46 adam Exp $
+
+AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include $(XSLT_CFLAGS)
+
+lib_LTLIBRARIES = libyazproxy.la
+libyazproxy_la_LDFLAGS=-version-info 1:0:0
+
+libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp
+
+bin_PROGRAMS = yaz-proxy
+
+yaz_proxy_SOURCES=yaz-proxy-main.cpp
+
+LDADD=libyazproxy.la ../src/libyazcpp.la $(YAZLALIB) $(XSLT_LIBS)
+libyazproxy_la_LIBADD = $(XSLT_LIBS)
--- /dev/null
+/* $Id: yaz-bw.cpp,v 1.1 2004-04-11 11:36:46 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <time.h>
+#include <yaz/log.h>
+#include <yaz++/proxy/bw.h>
+
+Yaz_bw::Yaz_bw(int sz)
+{
+ m_sec = 0;
+ m_size = sz;
+ m_bucket = new int[m_size];
+ m_ptr = 0;
+}
+
+Yaz_bw::~Yaz_bw()
+{
+ delete [] m_bucket;
+}
+
+int Yaz_bw::get_total()
+{
+ add_bytes(0);
+ int bw = 0;
+ int i;
+ for (i = 0; i<m_size; i++)
+ bw += m_bucket[i];
+ return bw;
+}
+
+void Yaz_bw::add_bytes(int b)
+{
+ long now = time(0);
+
+ int d = now - m_sec;
+ if (d > m_size)
+ d = m_size;
+ while (--d >= 0)
+ {
+ if (++m_ptr == m_size)
+ m_ptr = 0;
+ m_bucket[m_ptr] = 0;
+ }
+ m_bucket[m_ptr] += b;
+ m_sec = now;
+}
+
--- /dev/null
+/* $Id: yaz-proxy-config.cpp,v 1.1 2004-04-11 11:36:47 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <ctype.h>
+#include <yaz/log.h>
+#include <yaz++/proxy/proxy.h>
+
+Yaz_ProxyConfig::Yaz_ProxyConfig()
+{
+ m_copy = 0;
+#if HAVE_XSLT
+ m_docPtr = 0;
+ m_proxyPtr = 0;
+#endif
+}
+
+Yaz_ProxyConfig::~Yaz_ProxyConfig()
+{
+#if HAVE_XSLT
+ if (!m_copy && m_docPtr)
+ xmlFreeDoc(m_docPtr);
+#endif
+}
+
+int Yaz_ProxyConfig::read_xml(const char *fname)
+{
+#if HAVE_XSLT
+ xmlDocPtr ndoc = xmlParseFile(fname);
+
+ if (!ndoc)
+ {
+ yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
+ return -1; // no good
+ }
+ xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
+ if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
+ strcmp((const char *) proxyPtr->name, "proxy"))
+ {
+ yaz_log(LOG_WARN, "No proxy element in %s", fname);
+ xmlFreeDoc(ndoc);
+ return -1;
+ }
+ m_proxyPtr = proxyPtr;
+
+ // OK: release previous and make it the current one.
+ if (m_docPtr)
+ xmlFreeDoc(m_docPtr);
+ m_docPtr = ndoc;
+ return 0;
+#else
+ return -2;
+#endif
+}
+
+#if HAVE_XSLT
+const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
+{
+ for(ptr = ptr->children; ptr; ptr = ptr->next)
+ if (ptr->type == XML_TEXT_NODE)
+ {
+ xmlChar *t = ptr->content;
+ if (t)
+ {
+ while (*t == ' ')
+ t++;
+ return (const char *) t;
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req)
+{
+ for (ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "bandwidth"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_bw = atoi(t);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "retrieve"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_req = atoi(t);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "pdu"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_pdu = atoi(t);
+ }
+ }
+}
+#endif
+
+#if HAVE_XSLT
+void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+ *pre_init = 0;
+ int no_url = 0;
+ ptr = ptr->children;
+ for (; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "preinit"))
+ {
+ const char *v = get_text(ptr);
+ *pre_init = v ? atoi(v) : 1;
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "url"))
+ {
+ const char *t = get_text(ptr);
+ if (t && no_url < MAX_ZURL_PLEX)
+ {
+ url[no_url++] = t;
+ url[no_url] = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "keepalive"))
+ {
+ int dummy;
+ *keepalive_limit_bw = 500000;
+ *keepalive_limit_pdu = 1000;
+ return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
+ &dummy);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "limit"))
+ return_limit(ptr, limit_bw, limit_pdu, limit_req);
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "target-timeout"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *target_idletime = atoi(t);
+ if (*target_idletime < 0)
+ *target_idletime = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "client-timeout"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *client_idletime = atoi(t);
+ if (*client_idletime < 0)
+ *client_idletime = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "cql2rpn"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *cql2rpn = t;
+ }
+ }
+}
+#endif
+
+int Yaz_ProxyConfig::atoi_l(const char **cp)
+{
+ int v = 0;
+ while (**cp && isdigit(**cp))
+ {
+ v = v*10 + (**cp - '0');
+ (*cp)++;
+ }
+ return v;
+}
+
+int Yaz_ProxyConfig::match_list(int v, const char *m)
+{
+ while(m && *m)
+ {
+ while(*m && isspace(*m))
+ m++;
+ if (*m == '*')
+ return 1;
+ int l = atoi_l(&m);
+ int h = l;
+ if (*m == '-')
+ {
+ ++m;
+ h = atoi_l(&m);
+ }
+ if (v >= l && v <= h)
+ return 1;
+ if (*m == ',')
+ m++;
+ }
+ return 0;
+}
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
+ Z_AttributeList *attrs,
+ char **addinfo)
+{
+ int i;
+ for (i = 0; i<attrs->num_attributes; i++)
+ {
+ Z_AttributeElement *el = attrs->attributes[i];
+
+ if (!el->attributeType)
+ continue;
+ int type = *el->attributeType;
+ int *value = 0;
+
+ if (el->which == Z_AttributeValue_numeric && el->value.numeric)
+ value = el->value.numeric;
+
+ xmlNodePtr ptr;
+ for(ptr = ptrl->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "attribute"))
+ {
+ const char *match_type = 0;
+ const char *match_value = 0;
+ const char *match_error = 0;
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_type = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "value") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_value = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "error") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_error = (const char *) attr->children->content;
+ }
+ if (match_type && match_value)
+ {
+ char addinfo_str[20];
+ if (!match_list(type, match_type))
+ continue;
+
+ *addinfo_str = '\0';
+ if (!strcmp(match_type, "*"))
+ sprintf (addinfo_str, "%d", type);
+ else if (value)
+ {
+ if (!match_list(*value, match_value))
+ continue;
+ sprintf (addinfo_str, "%d", *value);
+ }
+ else
+ continue;
+
+ if (match_error)
+ {
+ if (*addinfo_str)
+ *addinfo = odr_strdup(odr, addinfo_str);
+ return atoi(match_error);
+ }
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
+ Z_RPNStructure *q,
+ char **addinfo)
+{
+ if (q->which == Z_RPNStructure_complex)
+ {
+ int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
+ if (e)
+ return e;
+ e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
+ return e;
+ }
+ else if (q->which == Z_RPNStructure_simple)
+ {
+ if (q->u.simple->which == Z_Operand_APT)
+ {
+ return check_type_1_attributes(
+ odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
+ addinfo);
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+ char **addinfo)
+{
+ // possibly check for Bib-1
+ return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
+}
+#endif
+
+int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
+ char **addinfo)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+
+ ptr = find_target_node(name, 0);
+ if (ptr)
+ {
+ if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
+ return check_type_1(odr, ptr, query->u.type_1, addinfo);
+ }
+#endif
+ return 0;
+}
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
+ const char *schema_identifier)
+{
+ char *esn = 0;
+ int default_match = 1;
+ if (comp && comp->which == Z_RecordComp_simple &&
+ comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
+ {
+ esn = comp->u.simple->u.generic;
+ }
+ // if no ESN/schema was given accept..
+ if (!esn)
+ return 1;
+ // check if schema identifier match
+ if (schema_identifier && !strcmp(esn, schema_identifier))
+ return 1;
+ // Check each name element
+ for (; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "name"))
+ {
+ xmlNodePtr tptr = ptr->children;
+ default_match = 0;
+ for (; tptr; tptr = tptr->next)
+ if (tptr->type == XML_TEXT_NODE && tptr->content)
+ {
+ xmlChar *t = tptr->content;
+ while (*t && isspace(*t))
+ t++;
+ int i = 0;
+ while (esn[i] && esn[i] == t[i])
+ i++;
+ if (!esn[i] && (!t[i] || isspace(t[i])))
+ return 1;
+ }
+ }
+ }
+ return default_match;
+}
+#endif
+
+int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
+ Odr_oid *syntax, Z_RecordComposition *comp,
+ char **addinfo,
+ char **stylesheet, char **schema)
+{
+ if (stylesheet)
+ {
+ xfree (*stylesheet);
+ *stylesheet = 0;
+ }
+ if (schema)
+ {
+ xfree (*schema);
+ *schema = 0;
+ }
+#if HAVE_XSLT
+ int syntax_has_matched = 0;
+ xmlNodePtr ptr;
+
+ ptr = find_target_node(name, 0);
+ if (!ptr)
+ return 0;
+ for(ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "syntax"))
+ {
+ int match = 0; // if we match record syntax
+ const char *match_type = 0;
+ const char *match_error = 0;
+ const char *match_marcxml = 0;
+ const char *match_stylesheet = 0;
+ const char *match_identifier = 0;
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_type = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "error") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_error = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "marcxml") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_marcxml = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "stylesheet") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_stylesheet = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "identifier") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_identifier = (const char *) attr->children->content;
+ }
+ if (match_type)
+ {
+ if (!strcmp(match_type, "*"))
+ match = 1;
+ else if (!strcmp(match_type, "none"))
+ {
+ if (syntax == 0)
+ match = 1;
+ }
+ else if (syntax)
+ {
+ int match_oid[OID_SIZE];
+ oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
+ if (oid_oidcmp(match_oid, syntax) == 0)
+ match = 1;
+ }
+ }
+ if (match)
+ {
+ if (!match_error)
+ syntax_has_matched = 1;
+ match = check_schema(ptr->children, comp, match_identifier);
+ }
+ if (match)
+ {
+ if (stylesheet && match_stylesheet)
+ {
+ xfree(*stylesheet);
+ *stylesheet = xstrdup(match_stylesheet);
+ }
+ if (schema && match_identifier)
+ {
+ xfree(*schema);
+ *schema = xstrdup(match_identifier);
+ }
+ if (match_marcxml)
+ {
+ return -1;
+ }
+ if (match_error)
+ {
+ if (syntax_has_matched) // if syntax OK, bad schema/ESN
+ return 25;
+ if (syntax)
+ {
+ char dotoid_str[100];
+ oid_to_dotstring(syntax, dotoid_str);
+ *addinfo = odr_strdup(odr, dotoid_str);
+ }
+ return atoi(match_error);
+ }
+ return 0;
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+#if HAVE_XSLT
+xmlNodePtr Yaz_ProxyConfig::find_target_db(xmlNodePtr ptr, const char *db)
+{
+ xmlNodePtr dptr;
+ if (!db)
+ return ptr;
+ if (!ptr)
+ return 0;
+ for (dptr = ptr->children; dptr; dptr = dptr->next)
+ if (dptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) dptr->name, "database"))
+ {
+ struct _xmlAttr *attr;
+ for (attr = dptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content
+ && (!strcmp((const char *) attr->children->content, db)
+ || !strcmp((const char *) attr->children->content,
+ "*")))
+ return dptr;
+ }
+ }
+ return ptr;
+}
+
+xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name, const char *db)
+{
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "target"))
+ {
+ // default one ?
+ if (!name)
+ {
+ // <target default="1"> ?
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "default") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ {
+ xmlChar *t = attr->children->content;
+ if (!t || *t == '1')
+ {
+ return find_target_db(ptr, db);
+ }
+ }
+ }
+ else
+ {
+ // <target name="name"> ?
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content
+ && (!strcmp((const char *) attr->children->content,
+ name)
+ || !strcmp((const char *) attr->children->content,
+ "*")))
+ {
+ return find_target_db(ptr, db);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+int Yaz_ProxyConfig::get_target_no(int no,
+ const char **name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return 0;
+ int i = 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "target"))
+ {
+ if (i == no)
+ {
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content)
+ *name = (const char *) attr->children->content;
+ }
+ return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
+ target_idletime, client_idletime,
+ keepalive_limit_bw, keepalive_limit_pdu,
+ pre_init, cql2rpn);
+ return 1;
+ }
+ i++;
+ }
+#endif
+ return 0;
+}
+
+int Yaz_ProxyConfig::mycmp(const char *hay, const char *item, size_t len)
+{
+ if (len == strlen(item) && memcmp(hay, item, len) == 0)
+ return 1;
+ return 0;
+}
+
+void Yaz_ProxyConfig::get_generic_info(int *log_mask,
+ int *max_clients)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "log"))
+ {
+ const char *v = get_text(ptr);
+ *log_mask = 0;
+ while (v && *v)
+ {
+ const char *cp = v;
+ while (*cp && *cp != ',' && !isspace(*cp))
+ cp++;
+ size_t len = cp - v;
+ if (mycmp(v, "client-apdu", len))
+ *log_mask |= PROXY_LOG_APDU_CLIENT;
+ if (mycmp(v, "server-apdu", len))
+ *log_mask |= PROXY_LOG_APDU_SERVER;
+ if (mycmp(v, "client-requests", len))
+ *log_mask |= PROXY_LOG_REQ_CLIENT;
+ if (mycmp(v, "server-requests", len))
+ *log_mask |= PROXY_LOG_REQ_SERVER;
+ if (isdigit(*v))
+ *log_mask |= atoi(v);
+ if (*cp == ',')
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ v = cp;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "max-clients"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *max_clients = atoi(t);
+ if (*max_clients < 1)
+ *max_clients = 1;
+ }
+ }
+ }
+#endif
+}
+
+char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
+ int *len)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr = find_target_node(name, db);
+ if (ptr)
+ {
+ ptr = ptr->children;
+ for (; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "explain"))
+ {
+ xmlNodePtr ptr1 = ptr->children;
+ if (db)
+ {
+ for (; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr1->name, "serverInfo"))
+ break;
+ if (!ptr1)
+ continue;
+ for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr1->name, "database"))
+ break;
+
+ if (!ptr1)
+ continue;
+ for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_TEXT_NODE &&
+ ptr1->content &&
+ !strcmp((const char *) ptr1->content, db))
+ break;
+ if (!ptr1)
+ continue;
+ }
+ xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
+
+ xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
+
+ xmlDocSetRootElement(doc, ptr2);
+
+ xmlChar *buf_out;
+ xmlDocDumpMemory(doc, &buf_out, len);
+ char *content = (char*) odr_malloc(odr, *len);
+ memcpy(content, buf_out, *len);
+
+ xmlFree(buf_out);
+ xmlFreeDoc(doc);
+ return content;
+ }
+ }
+#endif
+ return 0;
+}
+
+void Yaz_ProxyConfig::get_target_info(const char *name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ {
+ url[0] = name;
+ url[1] = 0;
+ return;
+ }
+ url[0] = 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "max-clients"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *max_clients = atoi(t);
+ if (*max_clients < 1)
+ *max_clients = 1;
+ }
+ }
+ }
+ ptr = find_target_node(name, 0);
+ if (ptr)
+ {
+ if (name)
+ {
+ url[0] = name;
+ url[1] = 0;
+ }
+ return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
+ target_idletime, client_idletime,
+ keepalive_limit_bw, keepalive_limit_pdu,
+ pre_init, cql2rpn);
+ }
+#else
+ *url = name;
+ return;
+#endif
+}
+
+
--- /dev/null
+/* $Id: yaz-proxy-main.cpp,v 1.1 2004-04-11 11:36:47 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#ifdef WIN32
+#else
+#include <signal.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include <sys/types.h>
+
+#include <stdarg.h>
+
+#if HAVE_GETRLIMIT
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#include <yaz/log.h>
+#include <yaz/options.h>
+
+#include <yaz++/socket-manager.h>
+#include <yaz++/pdu-assoc.h>
+#include <yaz++/proxy/proxy.h>
+
+void usage(char *prog)
+{
+ fprintf (stderr, "%s: [-c config] [-l log] [-a log] [-v level] [-t target] "
+ "[-u uid] [-p pidfile] @:port\n", prog);
+ exit (1);
+}
+
+static char *pid_fname = 0;
+static char *uid = 0;
+static char *log_file = 0;
+static int debug = 0;
+static int no_limit_files = 0;
+
+int args(Yaz_Proxy *proxy, int argc, char **argv)
+{
+ char *addr = 0;
+ char *arg;
+ char *prog = argv[0];
+ int ret;
+
+ while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:U:n:X",
+ argv, argc, &arg)) != -2)
+ {
+ int err;
+ switch (ret)
+ {
+ case 0:
+ if (addr)
+ {
+ usage(prog);
+ return 1;
+ }
+ addr = arg;
+ break;
+ case 'c':
+ err = proxy->set_config(arg);
+ if (err == -2)
+ {
+ fprintf(stderr, "Config file support not enabled (proxy not compiled with libxml2 support)\n");
+ exit(1);
+ }
+ else if (err == -1)
+ {
+ fprintf(stderr, "Bad or missing file %s\n", arg);
+ exit(1);
+ }
+ break;
+ case 'a':
+ proxy->set_APDU_log(arg);
+ break;
+ case 't':
+ proxy->set_default_target(arg);
+ break;
+ case 'U':
+ proxy->set_proxy_authentication(arg);
+ break;
+ case 'o':
+ proxy->option("optimize", arg);
+ break;
+ case 'v':
+ yaz_log_init_level (yaz_log_mask_str(arg));
+ break;
+ case 'l':
+ yaz_log_init_file (arg);
+ log_file = xstrdup(arg);
+ break;
+ case 'm':
+ proxy->set_max_clients(atoi(arg));
+ break;
+ case 'i':
+ proxy->set_client_idletime(atoi(arg));
+ break;
+ case 'T':
+ proxy->set_target_idletime(atoi(arg));
+ break;
+ case 'n':
+ no_limit_files = atoi(arg);
+ break;
+ case 'X':
+ debug = 1;
+ break;
+ case 'p':
+ if (!pid_fname)
+ pid_fname = xstrdup(arg);
+ break;
+ case 'u':
+ if (!uid)
+ uid = xstrdup(arg);
+ break;
+ default:
+ usage(prog);
+ return 1;
+ }
+ }
+ if (addr)
+ {
+ if (proxy->server(addr))
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "listen %s", addr);
+ exit(1);
+ }
+ }
+ else
+ {
+ usage(prog);
+ return 1;
+ }
+ return 0;
+}
+
+static Yaz_Proxy *static_yaz_proxy = 0;
+static void sighup_handler(int num)
+{
+#if WIN32
+#else
+ signal(SIGHUP, sighup_handler);
+#endif
+ if (static_yaz_proxy)
+ static_yaz_proxy->reconfig();
+}
+
+#if HAVE_XSLT
+static void proxy_xml_error_handler(void *ctx, const char *fmt, ...)
+{
+ char buf[1024];
+
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifdef WIN32
+ vsprintf(buf, fmt, ap);
+#else
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+#endif
+ yaz_log(LOG_WARN, "%s: %s", (char*) ctx, buf);
+
+ va_end (ap);
+}
+#endif
+
+static void child_run(Yaz_SocketManager *m, int run)
+{
+#ifdef WIN32
+#else
+ signal(SIGHUP, sighup_handler);
+#endif
+
+#if HAVE_XSLT
+ xmlSetGenericErrorFunc((void *) "XML", proxy_xml_error_handler);
+ xsltSetGenericErrorFunc((void *) "XSLT", proxy_xml_error_handler);
+#endif
+#ifdef WIN32
+#else
+ yaz_log(LOG_LOG, "0 proxy run=%d pid=%ld", run, (long) getpid());
+#endif
+ if (no_limit_files)
+ {
+#if HAVE_SETRLIMIT
+ struct rlimit limit_data;
+ limit_data.rlim_cur = no_limit_files;
+ limit_data.rlim_max = no_limit_files;
+
+ yaz_log(LOG_LOG, "0 setrlimit NOFILE cur=%d max=%d",
+ limit_data.rlim_cur, limit_data.rlim_max);
+ if (setrlimit(RLIMIT_NOFILE, &limit_data))
+ yaz_log(LOG_ERRNO|LOG_WARN, "setrlimit");
+#else
+ yaz_log(LOG_WARN, "setrlimit unavablable. Option -n ignored");
+#endif
+ }
+#ifdef WIN32
+#else
+ if (pid_fname)
+ {
+ FILE *f = fopen(pid_fname, "w");
+ if (!f)
+ {
+ yaz_log(LOG_ERRNO|LOG_FATAL, "Couldn't create %s", pid_fname);
+ exit(0);
+ }
+ fprintf(f, "%ld", (long) getpid());
+ fclose(f);
+ xfree(pid_fname);
+ }
+ if (uid)
+ {
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(uid)))
+ {
+ yaz_log(LOG_FATAL, "%s: Unknown user", uid);
+ exit(3);
+ }
+ if (log_file)
+ {
+ chown(log_file, pw->pw_uid, pw->pw_gid);
+ xfree(log_file);
+ }
+ if (setuid(pw->pw_uid) < 0)
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
+ exit(4);
+ }
+ xfree(uid);
+ }
+#endif
+#if HAVE_GETRLIMIT
+ struct rlimit limit_data;
+ getrlimit(RLIMIT_NOFILE, &limit_data);
+ yaz_log(LOG_LOG, "0 getrlimit NOFILE cur=%d max=%d",
+ limit_data.rlim_cur, limit_data.rlim_max);
+#endif
+
+ while (m->processEvent() > 0)
+ ;
+
+ exit (0);
+}
+
+int main(int argc, char **argv)
+{
+#if HAVE_XSLT
+ xmlInitMemory();
+
+ LIBXML_TEST_VERSION
+#endif
+ int cont = 1;
+ int run = 1;
+ Yaz_SocketManager mySocketManager;
+ Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
+
+ static_yaz_proxy = &proxy;
+
+ args(&proxy, argc, argv);
+
+#ifdef WIN32
+ child_run(&mySocketManager, run);
+#else
+ if (debug)
+ {
+ child_run(&mySocketManager, run);
+ exit(0);
+ }
+ while (cont)
+ {
+ pid_t p = fork();
+ if (p == (pid_t) -1)
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
+ exit(1);
+ }
+ else if (p == 0)
+ {
+ child_run(&mySocketManager, run);
+ }
+ pid_t p1;
+ int status;
+ p1 = wait(&status);
+
+ yaz_log_reopen();
+
+ if (p1 != p)
+ {
+ yaz_log(LOG_FATAL, "p1=%d != p=%d", p1, p);
+ exit(1);
+ }
+ if (WIFSIGNALED(status))
+ {
+ switch(WTERMSIG(status)) {
+ case SIGILL:
+ yaz_log(LOG_WARN, "Received SIGILL from child %ld", (long) p);
+ cont = 1;
+ break;
+ case SIGABRT:
+ yaz_log(LOG_WARN, "Received SIGABRT from child %ld", (long) p);
+ cont = 1;
+ break ;
+ case SIGSEGV:
+ yaz_log(LOG_WARN, "Received SIGSEGV from child %ld", (long) p);
+ cont = 1;
+ break;
+ case SIGBUS:
+ yaz_log(LOG_WARN, "Received SIGBUS from child %ld", (long) p);
+ cont = 1;
+ break;
+ case SIGTERM:
+ yaz_log(LOG_LOG, "Received SIGTERM from child %ld",
+ (long) p);
+ cont = 0;
+ break;
+ default:
+ yaz_log(LOG_WARN, "Received SIG %d from child %ld",
+ WTERMSIG(status), (long) p);
+ cont = 0;
+ }
+ }
+ else if (status == 0)
+ cont = 0;
+ else
+ {
+ yaz_log(LOG_LOG, "Exit %d from child %ld", status, (long) p);
+ cont = 1;
+ }
+ if (cont)
+ sleep(1 + run/5);
+ run++;
+ }
+#endif
+ exit (0);
+ return 0;
+}
--- /dev/null
+/* $Id: yaz-proxy.cpp,v 1.1 2004-04-11 11:36:52 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra 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, or (at your option) any later
+version.
+
+Zebra 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 Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#ifdef WIN32
+#else
+#include <unistd.h>
+#endif
+
+#include <assert.h>
+#include <time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <yaz/srw.h>
+#include <yaz/marcdisp.h>
+#include <yaz/yaz-iconv.h>
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+#include <yaz++/proxy/proxy.h>
+#include <yaz/pquery.h>
+
+static const char *apdu_name(Z_APDU *apdu)
+{
+ switch (apdu->which)
+ {
+ case Z_APDU_initRequest:
+ return "initRequest";
+ case Z_APDU_initResponse:
+ return "initResponse";
+ case Z_APDU_searchRequest:
+ return "searchRequest";
+ case Z_APDU_searchResponse:
+ return "searchResponse";
+ case Z_APDU_presentRequest:
+ return "presentRequest";
+ case Z_APDU_presentResponse:
+ return "presentResponse";
+ case Z_APDU_deleteResultSetRequest:
+ return "deleteResultSetRequest";
+ case Z_APDU_deleteResultSetResponse:
+ return "deleteResultSetResponse";
+ case Z_APDU_scanRequest:
+ return "scanRequest";
+ case Z_APDU_scanResponse:
+ return "scanResponse";
+ case Z_APDU_sortRequest:
+ return "sortRequest";
+ case Z_APDU_sortResponse:
+ return "sortResponse";
+ case Z_APDU_extendedServicesRequest:
+ return "extendedServicesRequest";
+ case Z_APDU_extendedServicesResponse:
+ return "extendedServicesResponse";
+ case Z_APDU_close:
+ return "close";
+ }
+ return "other";
+}
+
+static const char *gdu_name(Z_GDU *gdu)
+{
+ switch(gdu->which)
+ {
+ case Z_GDU_Z3950:
+ return apdu_name(gdu->u.z3950);
+ case Z_GDU_HTTP_Request:
+ return "HTTP Request";
+ case Z_GDU_HTTP_Response:
+ return "HTTP Response";
+ }
+ return "Unknown request/response";
+}
+
+Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent) :
+ Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
+{
+ m_PDU_Observable = the_PDU_Observable;
+ m_client = 0;
+ m_parent = parent;
+ m_clientPool = 0;
+ m_seqno = 1;
+ m_keepalive_limit_bw = 500000;
+ m_keepalive_limit_pdu = 1000;
+ m_proxyTarget = 0;
+ m_default_target = 0;
+ m_proxy_authentication = 0;
+ m_max_clients = 150;
+ m_log_mask = 0;
+ m_seed = time(0);
+ m_client_idletime = 600;
+ m_target_idletime = 600;
+ m_optimize = xstrdup ("1");
+ strcpy(m_session_str, "0 ");
+ m_session_no=0;
+ m_bytes_sent = 0;
+ m_bytes_recv = 0;
+ m_bw_hold_PDU = 0;
+ m_bw_max = 0;
+ m_pdu_max = 0;
+ m_max_record_retrieve = 0;
+ m_reconfig_flag = 0;
+ m_config_fname = 0;
+ m_request_no = 0;
+ m_invalid_session = 0;
+ m_referenceId = 0;
+ m_referenceId_mem = nmem_create();
+ m_config = 0;
+ m_marcxml_flag = 0;
+ m_stylesheet_xsp = 0;
+ m_stylesheet_nprl = 0;
+ m_s2z_stylesheet = 0;
+ m_s2z_database = 0;
+ m_schema = 0;
+ m_initRequest_apdu = 0;
+ m_initRequest_mem = 0;
+ m_initRequest_preferredMessageSize = 0;
+ m_initRequest_maximumRecordSize = 0;
+ m_initRequest_options = 0;
+ m_initRequest_version = 0;
+ m_apdu_invalid_session = 0;
+ m_mem_invalid_session = 0;
+ m_s2z_odr_init = 0;
+ m_s2z_odr_search = 0;
+ m_s2z_init_apdu = 0;
+ m_s2z_search_apdu = 0;
+ m_s2z_present_apdu = 0;
+ m_http_keepalive = 0;
+ m_http_version = 0;
+ m_soap_ns = 0;
+ m_s2z_packing = Z_SRW_recordPacking_string;
+#if HAVE_GETTIMEOFDAY
+ m_time_tv.tv_sec = 0;
+ m_time_tv.tv_usec = 0;
+#endif
+ if (!m_parent)
+ low_socket_open();
+}
+
+Yaz_Proxy::~Yaz_Proxy()
+{
+ yaz_log(LOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
+ m_bytes_sent, m_bytes_recv);
+ nmem_destroy(m_initRequest_mem);
+ nmem_destroy(m_mem_invalid_session);
+ nmem_destroy(m_referenceId_mem);
+
+ xfree (m_proxyTarget);
+ xfree (m_default_target);
+ xfree (m_proxy_authentication);
+ xfree (m_optimize);
+
+#if HAVE_XSLT
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+#endif
+ xfree (m_schema);
+ if (m_s2z_odr_init)
+ odr_destroy(m_s2z_odr_init);
+ if (m_s2z_odr_search)
+ odr_destroy(m_s2z_odr_search);
+ if (!m_parent)
+ low_socket_close();
+ delete m_config;
+}
+
+int Yaz_Proxy::set_config(const char *config)
+{
+ delete m_config;
+ m_config = new Yaz_ProxyConfig();
+ xfree(m_config_fname);
+ m_config_fname = xstrdup(config);
+ int r = m_config->read_xml(config);
+ if (!r)
+ m_config->get_generic_info(&m_log_mask, &m_max_clients);
+ return r;
+}
+
+void Yaz_Proxy::set_default_target(const char *target)
+{
+ xfree (m_default_target);
+ m_default_target = 0;
+ if (target)
+ m_default_target = (char *) xstrdup (target);
+}
+
+void Yaz_Proxy::set_proxy_authentication (const char *auth)
+{
+ xfree (m_proxy_authentication);
+ m_proxy_authentication = 0;
+ if (auth)
+ m_proxy_authentication = (char *) xstrdup (auth);
+}
+
+Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
+{
+ if (m_parent)
+ return m_parent->check_reconfigure();
+
+ Yaz_ProxyConfig *cfg = m_config;
+ if (m_reconfig_flag)
+ {
+ yaz_log(LOG_LOG, "reconfigure");
+ yaz_log_reopen();
+ if (m_config_fname && cfg)
+ {
+ yaz_log(LOG_LOG, "reconfigure config %s", m_config_fname);
+ int r = cfg->read_xml(m_config_fname);
+ if (r)
+ yaz_log(LOG_WARN, "reconfigure failed");
+ else
+ {
+ m_log_mask = 0;
+ cfg->get_generic_info(&m_log_mask, &m_max_clients);
+ }
+ }
+ else
+ yaz_log(LOG_LOG, "reconfigure");
+ m_reconfig_flag = 0;
+ }
+ return cfg;
+}
+
+IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
+ *the_PDU_Observable, int fd)
+{
+ check_reconfigure();
+ Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable, this);
+ new_proxy->m_config = 0;
+ new_proxy->m_config_fname = 0;
+ new_proxy->timeout(m_client_idletime);
+ new_proxy->m_target_idletime = m_target_idletime;
+ new_proxy->set_default_target(m_default_target);
+ new_proxy->m_max_clients = m_max_clients;
+ new_proxy->m_log_mask = m_log_mask;
+ new_proxy->set_APDU_log(get_APDU_log());
+ if (m_log_mask & PROXY_LOG_APDU_CLIENT)
+ new_proxy->set_APDU_yazlog(1);
+ else
+ new_proxy->set_APDU_yazlog(0);
+ new_proxy->set_proxy_authentication(m_proxy_authentication);
+ sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
+ m_session_no++;
+ yaz_log (LOG_LOG, "%sNew session %s", new_proxy->m_session_str,
+ the_PDU_Observable->getpeername());
+ return new_proxy;
+}
+
+char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
+{
+ int oid[OID_SIZE];
+ Z_OtherInformationUnit *oi;
+ struct oident ent;
+ ent.proto = PROTO_Z3950;
+ ent.oclass = CLASS_USERINFO;
+ ent.value = (oid_value) VAL_COOKIE;
+ assert (oid_ent_to_oid (&ent, oid));
+
+ if (oid_ent_to_oid (&ent, oid) &&
+ (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
+ oi->which == Z_OtherInfo_characterInfo)
+ return oi->information.characterInfo;
+ return 0;
+}
+
+char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
+{
+ int oid[OID_SIZE];
+ Z_OtherInformationUnit *oi;
+ struct oident ent;
+ ent.proto = PROTO_Z3950;
+ ent.oclass = CLASS_USERINFO;
+ ent.value = (oid_value) VAL_PROXY;
+ if (oid_ent_to_oid (&ent, oid) &&
+ (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
+ oi->which == Z_OtherInfo_characterInfo)
+ return oi->information.characterInfo;
+ return 0;
+}
+
+const char *Yaz_Proxy::load_balance(const char **url)
+{
+ int zurl_in_use[MAX_ZURL_PLEX];
+ int zurl_in_spare[MAX_ZURL_PLEX];
+ Yaz_ProxyClient *c;
+ int i;
+
+ for (i = 0; i<MAX_ZURL_PLEX; i++)
+ {
+ zurl_in_use[i] = 0;
+ zurl_in_spare[i] = 0;
+ }
+ for (c = m_parent->m_clientPool; c; c = c->m_next)
+ {
+ for (i = 0; url[i]; i++)
+ if (!strcmp(url[i], c->get_hostname()))
+ {
+ zurl_in_use[i]++;
+ if (c->m_cookie == 0 && c->m_server == 0 && c->m_waiting == 0)
+ zurl_in_spare[i]++;
+ }
+ }
+ int min_use = 100000;
+ int spare_for_min = 0;
+ int max_spare = 0;
+ const char *ret_min = 0;
+ const char *ret_spare = 0;
+ for (i = 0; url[i]; i++)
+ {
+ yaz_log(LOG_DEBUG, "%szurl=%s use=%d spare=%d",
+ m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
+ if (min_use > zurl_in_use[i])
+ {
+ ret_min = url[i];
+ min_use = zurl_in_use[i];
+ spare_for_min = zurl_in_spare[i];
+ }
+ if (max_spare < zurl_in_spare[i])
+ {
+ ret_spare = url[i];
+ max_spare = zurl_in_spare[i];
+ }
+ }
+ // use the one with minimum connections if spare is > 3
+ if (spare_for_min > 3)
+ return ret_min;
+ // use one with most spares (if any)
+ if (max_spare > 0)
+ return ret_spare;
+ return ret_min;
+}
+
+Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
+ const char *proxy_host)
+{
+ assert (m_parent);
+ Yaz_Proxy *parent = m_parent;
+ Yaz_ProxyClient *c = m_client;
+
+ if (!m_proxyTarget)
+ {
+ const char *url[MAX_ZURL_PLEX];
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (proxy_host)
+ {
+#if 0
+/* only to be enabled for debugging... */
+ if (!strcmp(proxy_host, "stop"))
+ exit(0);
+#endif
+ xfree(m_default_target);
+ m_default_target = xstrdup(proxy_host);
+ proxy_host = m_default_target;
+ }
+ int client_idletime = -1;
+ const char *cql2rpn_fname = 0;
+ url[0] = m_default_target;
+ url[1] = 0;
+ if (cfg)
+ {
+ int pre_init = 0;
+ cfg->get_target_info(proxy_host, url, &m_bw_max,
+ &m_pdu_max, &m_max_record_retrieve,
+ &m_target_idletime, &client_idletime,
+ &parent->m_max_clients,
+ &m_keepalive_limit_bw,
+ &m_keepalive_limit_pdu,
+ &pre_init,
+ &cql2rpn_fname);
+ }
+ if (client_idletime != -1)
+ {
+ m_client_idletime = client_idletime;
+ timeout(m_client_idletime);
+ }
+ if (cql2rpn_fname)
+ m_cql2rpn.set_pqf_file(cql2rpn_fname);
+ if (!url[0])
+ {
+ yaz_log(LOG_LOG, "%sNo default target", m_session_str);
+ return 0;
+ }
+ // we don't handle multiplexing for cookie session, so we just
+ // pick the first one in this case (anonymous users will be able
+ // to use any backend)
+ if (cookie && *cookie)
+ m_proxyTarget = (char*) xstrdup(url[0]);
+ else
+ m_proxyTarget = (char*) xstrdup(load_balance(url));
+ }
+ if (cookie && *cookie)
+ { // search in sessions with a cookie
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ assert (c->m_prev);
+ assert (*c->m_prev == c);
+ if (c->m_cookie && !strcmp(cookie,c->m_cookie) &&
+ !strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ // Found it in cache
+ // The following handles "cancel"
+ // If connection is busy (waiting for PDU) and
+ // we have an initRequest we can safely do re-open
+ if (c->m_waiting && apdu->which == Z_APDU_initRequest)
+ {
+ yaz_log (LOG_LOG, "%s REOPEN target=%s", m_session_str,
+ c->get_hostname());
+ c->close();
+ c->m_init_flag = 0;
+
+ c->m_last_ok = 0;
+ c->m_cache.clear();
+ c->m_last_resultCount = 0;
+ c->m_sr_transform = 0;
+ c->m_waiting = 0;
+ c->m_resultSetStartPoint = 0;
+ c->m_target_idletime = m_target_idletime;
+ if (c->client(m_proxyTarget))
+ {
+ delete c;
+ return 0;
+ }
+ c->timeout(30);
+ }
+ c->m_seqno = parent->m_seqno;
+ if (c->m_server && c->m_server != this)
+ c->m_server->m_client = 0;
+ c->m_server = this;
+ (parent->m_seqno)++;
+ yaz_log (LOG_DEBUG, "get_client 1 %p %p", this, c);
+ return c;
+ }
+ }
+ }
+ else if (!c)
+ {
+ // don't have a client session yet. Search in session w/o cookie
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ assert (c->m_prev);
+ assert (*c->m_prev == c);
+ if (c->m_server == 0 && c->m_cookie == 0 &&
+ c->m_waiting == 0 &&
+ !strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ // found it in cache
+ yaz_log (LOG_LOG, "%sREUSE %d %s",
+ m_session_str, parent->m_seqno, c->get_hostname());
+
+ c->m_seqno = parent->m_seqno;
+ assert(c->m_server == 0);
+ c->m_server = this;
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ (parent->m_seqno)++;
+
+ parent->pre_init();
+
+ return c;
+ }
+ }
+ }
+ if (!m_client)
+ {
+ if (apdu->which != Z_APDU_initRequest)
+ {
+ yaz_log (LOG_LOG, "%sno init request as first PDU", m_session_str);
+ return 0;
+ }
+ Z_InitRequest *initRequest = apdu->u.initRequest;
+
+ if (!initRequest->idAuthentication)
+ {
+ if (m_proxy_authentication)
+ {
+ initRequest->idAuthentication =
+ (Z_IdAuthentication *)
+ odr_malloc (odr_encode(),
+ sizeof(*initRequest->idAuthentication));
+ initRequest->idAuthentication->which =
+ Z_IdAuthentication_open;
+ initRequest->idAuthentication->u.open =
+ odr_strdup (odr_encode(), m_proxy_authentication);
+ }
+ }
+ // go through list of clients - and find the lowest/oldest one.
+ Yaz_ProxyClient *c_min = 0;
+ int min_seq = -1;
+ int no_of_clients = 0;
+ if (parent->m_clientPool)
+ yaz_log (LOG_DEBUG, "Existing sessions");
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ yaz_log (LOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
+ c->m_waiting, c->get_hostname(),
+ c->m_cookie ? c->m_cookie : "");
+ no_of_clients++;
+ if (min_seq < 0 || c->m_seqno < min_seq)
+ {
+ min_seq = c->m_seqno;
+ c_min = c;
+ }
+ }
+ if (no_of_clients >= parent->m_max_clients)
+ {
+ c = c_min;
+ if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ yaz_log (LOG_LOG, "%sMAXCLIENTS %d Destroy %d",
+ m_session_str, parent->m_max_clients, c->m_seqno);
+ if (c->m_server && c->m_server != this)
+ delete c->m_server;
+ c->m_server = 0;
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
+ m_session_str, parent->m_max_clients,
+ c->m_seqno, parent->m_seqno, c->get_hostname());
+ xfree (c->m_cookie);
+ c->m_cookie = 0;
+ if (cookie)
+ c->m_cookie = xstrdup(cookie);
+ c->m_seqno = parent->m_seqno;
+ if (c->m_server && c->m_server != this)
+ {
+ c->m_server->m_client = 0;
+ delete c->m_server;
+ }
+ (parent->m_seqno)++;
+ c->m_target_idletime = m_target_idletime;
+ c->timeout(m_target_idletime);
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ return c;
+ }
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sNEW %d %s",
+ m_session_str, parent->m_seqno, m_proxyTarget);
+ c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
+ c->m_next = parent->m_clientPool;
+ if (c->m_next)
+ c->m_next->m_prev = &c->m_next;
+ parent->m_clientPool = c;
+ c->m_prev = &parent->m_clientPool;
+ }
+
+ xfree (c->m_cookie);
+ c->m_cookie = 0;
+ if (cookie)
+ c->m_cookie = xstrdup(cookie);
+
+ c->m_seqno = parent->m_seqno;
+ c->m_init_flag = 0;
+ c->m_last_resultCount = 0;
+ c->m_last_ok = 0;
+ c->m_cache.clear();
+ c->m_sr_transform = 0;
+ c->m_waiting = 0;
+ c->m_resultSetStartPoint = 0;
+ (parent->m_seqno)++;
+ if (c->client(m_proxyTarget))
+ {
+ delete c;
+ return 0;
+ }
+ c->m_target_idletime = m_target_idletime;
+ c->timeout(30);
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+ }
+ yaz_log (LOG_DEBUG, "get_client 3 %p %p", this, c);
+ return c;
+}
+
+void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
+{
+ int i;
+ for (i = 0; i<num; i++)
+ {
+ oident *ent;
+ Z_DefaultDiagFormat *r;
+ Z_DiagRec *p = pp[i];
+ if (p->which != Z_DiagRec_defaultFormat)
+ {
+ yaz_log(LOG_LOG, "%sError no diagnostics", m_session_str);
+ return;
+ }
+ else
+ r = p->u.defaultFormat;
+ if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
+ ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
+ yaz_log(LOG_LOG, "%sError unknown diagnostic set", m_session_str);
+ switch (r->which)
+ {
+ case Z_DefaultDiagFormat_v2Addinfo:
+ yaz_log(LOG_LOG, "%sError %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v2Addinfo);
+ break;
+ case Z_DefaultDiagFormat_v3Addinfo:
+ yaz_log(LOG_LOG, "%sError %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v3Addinfo);
+ break;
+ }
+ }
+}
+
+int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
+{
+ if (!m_stylesheet_xsp || p->num_records <= 0)
+ return 0; /* no XSLT to be done ... */
+
+ m_stylesheet_offset = 0;
+ m_stylesheet_nprl = p;
+ m_stylesheet_apdu = apdu;
+ timeout(0);
+ return 1;
+}
+
+void Yaz_Proxy::convert_xsl_delay()
+{
+ Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
+#if HAVE_XSLT
+ if (npr->which == Z_NamePlusRecord_databaseRecord)
+ {
+ Z_External *r = npr->u.databaseRecord;
+ if (r->which == Z_External_octet)
+ {
+#if 0
+ fwrite((char*) r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, stdout);
+#endif
+ xmlDocPtr res, doc = xmlParseMemory(
+ (char*) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len);
+
+
+ yaz_log(LOG_LOG, "%sXSLT convert %d",
+ m_session_str, m_stylesheet_offset);
+ res = xsltApplyStylesheet(m_stylesheet_xsp, doc, 0);
+
+ if (res)
+ {
+ xmlChar *out_buf;
+ int out_len;
+ xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
+
+ m_stylesheet_nprl->records[m_stylesheet_offset]->
+ u.databaseRecord =
+ z_ext_record(odr_encode(), VAL_TEXT_XML,
+ (char*) out_buf, out_len);
+ xmlFree(out_buf);
+ xmlFreeDoc(res);
+ }
+
+ xmlFreeDoc(doc);
+ }
+ }
+#endif
+ m_stylesheet_offset++;
+ if (m_stylesheet_offset == m_stylesheet_nprl->num_records)
+ {
+ m_stylesheet_nprl = 0;
+#if HAVE_XSLT
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+#endif
+ m_stylesheet_xsp = 0;
+ timeout(m_client_idletime);
+ send_PDU_convert(m_stylesheet_apdu);
+ }
+ else
+ timeout(0);
+}
+
+void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p)
+{
+ int i;
+
+ yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC-8");
+ yaz_marc_t mt = yaz_marc_create();
+ yaz_marc_xml(mt, YAZ_MARC_MARCXML);
+ yaz_marc_iconv(mt, cd);
+ for (i = 0; i < p->num_records; i++)
+ {
+ Z_NamePlusRecord *npr = p->records[i];
+ if (npr->which == Z_NamePlusRecord_databaseRecord)
+ {
+ Z_External *r = npr->u.databaseRecord;
+ if (r->which == Z_External_octet)
+ {
+ int rlen;
+ char *result;
+ if (yaz_marc_decode_buf(mt, (char*) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len,
+ &result, &rlen))
+ {
+ npr->u.databaseRecord = z_ext_record(odr_encode(),
+ VAL_TEXT_XML,
+ result, rlen);
+ }
+ }
+ }
+ }
+ if (cd)
+ yaz_iconv_close(cd);
+ yaz_marc_destroy(mt);
+}
+
+void Yaz_Proxy::logtime()
+{
+#if HAVE_GETTIMEOFDAY
+ if (m_time_tv.tv_sec)
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ long diff = (tv.tv_sec - m_time_tv.tv_sec)*1000000 +
+ (tv.tv_usec - m_time_tv.tv_usec);
+ if (diff >= 0)
+ yaz_log(LOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
+ diff/1000000, (diff/1000)%1000);
+ }
+ m_time_tv.tv_sec = 0;
+ m_time_tv.tv_usec = 0;
+#endif
+}
+
+int Yaz_Proxy::send_http_response(int code)
+{
+ ODR o = odr_encode();
+ Z_GDU *gdu = z_get_HTTP_Response(o, code);
+ Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+ if (m_http_version)
+ hres->version = odr_strdup(o, m_http_version);
+ if (m_http_keepalive)
+ z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+ else
+ timeout(0);
+
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ {
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ gdu_name(gdu));
+ }
+ int len;
+ int r = send_GDU(gdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+}
+
+int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
+{
+ ODR o = odr_encode();
+ const char *ctype = "text/xml";
+ Z_GDU *gdu = z_get_HTTP_Response(o, 200);
+ Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+ if (m_http_version)
+ hres->version = odr_strdup(o, m_http_version);
+ z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+ if (m_http_keepalive)
+ z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+ else
+ timeout(0);
+
+ static Z_SOAP_Handler soap_handlers[2] = {
+#if HAVE_XSLT
+ {"http://www.loc.gov/zing/srw/", 0,
+ (Z_SOAP_fun) yaz_srw_codec},
+#endif
+ {0, 0, 0}
+ };
+
+ Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP));
+ soap_package->which = Z_SOAP_generic;
+ soap_package->u.generic =
+ (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic));
+ soap_package->u.generic->no = 0;
+ soap_package->u.generic->ns = soap_handlers[0].ns;
+ soap_package->u.generic->p = (void *) srw_pdu;
+ soap_package->ns = m_soap_ns;
+ z_soap_codec_enc_xsl(o, &soap_package,
+ &hres->content_buf, &hres->content_len,
+ soap_handlers, 0, m_s2z_stylesheet);
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ {
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ gdu_name(gdu));
+ }
+ int len;
+ int r = send_GDU(gdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+}
+
+int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
+{
+ ODR o = odr_encode();
+ Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->num_diagnostics = 1;
+ srw_res->diagnostics = (Z_SRW_diagnostic *)
+ odr_malloc(o, sizeof(*srw_res->diagnostics));
+ yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add);
+ return send_srw_response(srw_pdu);
+}
+
+int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
+ Z_DefaultDiagFormat *ddf)
+{
+ int bib1_code = *ddf->condition;
+ if (bib1_code == 109)
+ return 404;
+ srw_res->num_diagnostics = 1;
+ srw_res->diagnostics = (Z_SRW_diagnostic *)
+ odr_malloc(o, sizeof(*srw_res->diagnostics));
+ yaz_mk_std_diagnostic(o, srw_res->diagnostics,
+ yaz_diag_bib1_to_srw(*ddf->condition),
+ ddf->u.v2Addinfo);
+ return 0;
+}
+
+int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
+{
+ ODR o = odr_encode();
+ Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->numberOfRecords = odr_intdup (o, hits);
+ if (records && records->which == Z_Records_DBOSD)
+ {
+ srw_res->num_records =
+ records->u.databaseOrSurDiagnostics->num_records;
+ int i;
+ srw_res->records = (Z_SRW_record *)
+ odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record));
+ for (i = 0; i < srw_res->num_records; i++)
+ {
+ Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i];
+ if (npr->which != Z_NamePlusRecord_databaseRecord)
+ {
+ srw_res->records[i].recordSchema = "diagnostic";
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = "67";
+ srw_res->records[i].recordData_len = 2;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ continue;
+ }
+ Z_External *r = npr->u.databaseRecord;
+ oident *ent = oid_getentbyoid(r->direct_reference);
+ if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML)
+ {
+ srw_res->records[i].recordSchema = m_schema;
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = (char*)
+ r->u.octet_aligned->buf;
+ srw_res->records[i].recordData_len = r->u.octet_aligned->len;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ }
+ else
+ {
+ srw_res->records[i].recordSchema = "diagnostic";
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = "67";
+ srw_res->records[i].recordData_len = 2;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ }
+ }
+ }
+ if (records && records->which == Z_Records_NSD)
+ {
+ int http_code;
+ http_code = z_to_srw_diag(odr_encode(), srw_res,
+ records->u.nonSurrogateDiagnostic);
+ if (http_code)
+ return send_http_response(http_code);
+ }
+ return send_srw_response(srw_pdu);
+
+}
+
+int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+ int num_diagnostics)
+{
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (cfg)
+ {
+ int len;
+ char *b = cfg->get_explain(odr_encode(), 0 /* target */,
+ m_s2z_database, &len);
+ if (b)
+ {
+ Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
+ Z_SRW_explainResponse *er = res->u.explain_response;
+
+ er->record.recordData_buf = b;
+ er->record.recordData_len = len;
+ er->record.recordPacking = m_s2z_packing;
+ er->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
+
+ er->diagnostics = diagnostics;
+ er->num_diagnostics = num_diagnostics;
+ return send_srw_response(res);
+ }
+ }
+ return send_http_response(404);
+}
+
+int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
+{
+ if (m_http_version)
+ {
+ if (apdu->which == Z_APDU_initResponse)
+ {
+ Z_InitResponse *res = apdu->u.initResponse;
+ if (*res->result == 0)
+ {
+ send_to_srw_client_error(3, 0);
+ }
+ else if (!m_s2z_search_apdu)
+ {
+ send_srw_explain_response(0, 0);
+ }
+ else
+ {
+ handle_incoming_Z_PDU(m_s2z_search_apdu);
+ }
+ }
+ else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
+ {
+ m_s2z_search_apdu = 0;
+ Z_SearchResponse *res = apdu->u.searchResponse;
+ m_s2z_hit_count = *res->resultCount;
+ if (res->records && res->records->which == Z_Records_NSD)
+ {
+ send_to_srw_client_ok(0, res->records, 1);
+ }
+ else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
+ {
+ // adjust
+ Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
+
+ if (*pr->resultSetStartPoint <= m_s2z_hit_count)
+ {
+ if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
+ > m_s2z_hit_count)
+ *pr->numberOfRecordsRequested =
+ 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
+ }
+ handle_incoming_Z_PDU(m_s2z_present_apdu);
+ }
+ else
+ {
+ m_s2z_present_apdu = 0;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
+ }
+ }
+ else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
+ {
+ int start =
+ *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
+
+ m_s2z_present_apdu = 0;
+ Z_PresentResponse *res = apdu->u.presentResponse;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
+ }
+ }
+ else
+ {
+ int len = 0;
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ apdu_name(apdu));
+ int r = send_Z_PDU(apdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+ }
+ return 0;
+}
+
+int Yaz_Proxy::send_to_client(Z_APDU *apdu)
+{
+ int kill_session = 0;
+ Z_ReferenceId **new_id = get_referenceIdP(apdu);
+
+ if (new_id)
+ *new_id = m_referenceId;
+
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+
+ *sr->searchStatus = 0;
+ display_diagrecs(&dr_p, 1);
+ }
+ else
+ {
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_marcxml_flag)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+
+ }
+ if (sr->resultCount)
+ {
+ yaz_log(LOG_LOG, "%s%d hits", m_session_str,
+ *sr->resultCount);
+ if (*sr->resultCount < 0)
+ {
+ m_invalid_session = 1;
+ kill_session = 1;
+
+ *sr->searchStatus = 0;
+ sr->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
+ *sr->resultCount = 0;
+ }
+ }
+ }
+ }
+ else if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *sr = apdu->u.presentResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+ if (*sr->presentStatus == Z_PresentStatus_success)
+ *sr->presentStatus = Z_PresentStatus_failure;
+ display_diagrecs(&dr_p, 1);
+ }
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_marcxml_flag)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+ }
+ }
+ else if (apdu->which == Z_APDU_initResponse)
+ {
+ if (m_initRequest_options)
+ {
+ Z_Options *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<24; i++)
+ if (ODR_MASK_GET(m_initRequest_options, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->options, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->options = nopt;
+ }
+ if (m_initRequest_version)
+ {
+ Z_ProtocolVersion *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<8; i++)
+ if (ODR_MASK_GET(m_initRequest_version, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->protocolVersion = nopt;
+ }
+ apdu->u.initResponse->preferredMessageSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_preferredMessageSize >
+ m_initRequest_preferredMessageSize ?
+ m_initRequest_preferredMessageSize :
+ m_client->m_initResponse_preferredMessageSize);
+ apdu->u.initResponse->maximumRecordSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_maximumRecordSize >
+ m_initRequest_maximumRecordSize ?
+ m_initRequest_maximumRecordSize :
+ m_client->m_initResponse_maximumRecordSize);
+ }
+ int r = send_PDU_convert(apdu);
+ if (r)
+ return r;
+ if (kill_session)
+ {
+ delete m_client;
+ m_client = 0;
+ m_parent->pre_init();
+ }
+ return r;
+}
+
+int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
+{
+ int len = 0;
+ const char *apdu_name_tmp = apdu_name(apdu);
+ int r = send_Z_PDU(apdu, &len);
+ if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
+ yaz_log (LOG_LOG, "%sSending %s to %s %d bytes",
+ get_session_str(),
+ apdu_name_tmp, get_hostname(), len);
+ m_bytes_sent += len;
+ return r;
+}
+
+Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ int toget = *pr->numberOfRecordsRequested;
+ int start = *pr->resultSetStartPoint;
+
+ yaz_log(LOG_LOG, "%sPresent %s %d+%d", m_session_str,
+ pr->resultSetId, start, toget);
+
+ if (*m_parent->m_optimize == '0')
+ return apdu;
+
+ if (!m_client->m_last_resultSetId)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 30,
+ pr->resultSetId);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId))
+ {
+ if (start+toget-1 > m_client->m_last_resultCount)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 13, 0);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ Z_NamePlusRecordList *npr;
+ if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
+ pr->preferredRecordSyntax,
+ pr->recordComposition))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for present request",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+
+ new_apdu->u.presentResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.presentResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.presentResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), start+toget);
+
+ send_to_client(new_apdu);
+ return 0;
+ }
+ }
+ }
+
+ if (apdu->which != Z_APDU_searchRequest)
+ return apdu;
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ Yaz_Z_Query *this_query = new Yaz_Z_Query;
+ Yaz_Z_Databases this_databases;
+
+ this_databases.set(sr->num_databaseNames, (const char **)
+ sr->databaseNames);
+
+ this_query->set_Z_Query(sr->query);
+
+ char query_str[120];
+ this_query->print(query_str, sizeof(query_str)-1);
+ yaz_log(LOG_LOG, "%sSearch %s", m_session_str, query_str);
+
+ if (*m_parent->m_optimize != '0' &&
+ m_client->m_last_ok && m_client->m_last_query &&
+ m_client->m_last_query->match(this_query) &&
+ !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
+ m_client->m_last_databases.match(this_databases))
+ {
+ delete this_query;
+ if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
+ m_client->m_last_resultCount < *sr->largeSetLowerBound)
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = *sr->mediumSetPresentNumber;
+ Z_RecordComposition *comp = 0;
+
+ if (toget > m_client->m_last_resultCount)
+ toget = m_client->m_last_resultCount;
+
+ if (sr->mediumSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->mediumSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for medium set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ // medium Set
+ // send present request (medium size)
+ yaz_log (LOG_LOG, "%sOptimizing search for medium set",
+ m_session_str);
+
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
+ m_client->m_last_resultCount <= 0)
+ {
+ // large set. Return pseudo-search response immediately
+ yaz_log (LOG_LOG, "%sOptimizing search for large set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = m_client->m_last_resultCount;
+ Z_RecordComposition *comp = 0;
+ // small set
+ // send a present request (small set)
+
+ if (sr->smallSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->smallSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sOptimizing search for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ }
+ else // query doesn't match
+ {
+ delete m_client->m_last_query;
+ m_client->m_last_query = this_query;
+ m_client->m_last_ok = 0;
+ m_client->m_cache.clear();
+ m_client->m_resultSetStartPoint = 0;
+
+ xfree (m_client->m_last_resultSetId);
+ m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
+
+ m_client->m_last_databases.set(sr->num_databaseNames,
+ (const char **) sr->databaseNames);
+ }
+ return apdu;
+}
+
+
+void Yaz_Proxy::inc_request_no()
+{
+ char *cp = strchr(m_session_str, ' ');
+ m_request_no++;
+ if (cp)
+ sprintf(cp+1, "%d ", m_request_no);
+}
+
+void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
+{
+ inc_request_no();
+
+ m_bytes_recv += len;
+
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ yaz_log (LOG_LOG, "%sReceiving %s from client %d bytes",
+ m_session_str, gdu_name(apdu), len);
+
+ if (m_bw_hold_PDU) // double incoming PDU. shutdown now.
+ shutdown();
+
+ m_bw_stat.add_bytes(len);
+ m_pdu_stat.add_bytes(1);
+
+#if HAVE_GETTIMEOFDAY
+ gettimeofday(&m_time_tv, 0);
+#endif
+
+ int bw_total = m_bw_stat.get_total();
+ int pdu_total = m_pdu_stat.get_total();
+
+ int reduce = 0;
+ if (m_bw_max)
+ {
+ if (bw_total > m_bw_max)
+ {
+ reduce = (bw_total/m_bw_max);
+ }
+ }
+ if (m_pdu_max)
+ {
+ if (pdu_total > m_pdu_max)
+ {
+ int nreduce = (m_pdu_max >= 60) ? 1 : 60/m_pdu_max;
+ reduce = (reduce > nreduce) ? reduce : nreduce;
+ }
+ }
+ if (reduce)
+ {
+ yaz_log(LOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, reduce, bw_total, pdu_total,
+ m_bw_max, m_pdu_max);
+
+ m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
+ timeout(reduce); // call us reduce seconds later
+ }
+ else if (apdu->which == Z_GDU_Z3950)
+ handle_incoming_Z_PDU(apdu->u.z3950);
+ else if (apdu->which == Z_GDU_HTTP_Request)
+ handle_incoming_HTTP(apdu->u.HTTP_Request);
+}
+
+void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
+{
+ if (m_max_record_retrieve)
+ {
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ if (pr->numberOfRecordsRequested &&
+ *pr->numberOfRecordsRequested > m_max_record_retrieve)
+ *pr->numberOfRecordsRequested = m_max_record_retrieve;
+ }
+ }
+}
+
+Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
+ int error,
+ const char *addinfo)
+{
+ Z_Records *rec = (Z_Records *)
+ odr_malloc (odr, sizeof(*rec));
+ int *err = (int *)
+ odr_malloc (odr, sizeof(*err));
+ Z_DiagRec *drec = (Z_DiagRec *)
+ odr_malloc (odr, sizeof(*drec));
+ Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+ odr_malloc (odr, sizeof(*dr));
+ *err = error;
+ rec->which = Z_Records_NSD;
+ rec->u.nonSurrogateDiagnostic = dr;
+ dr->diagnosticSetId =
+ yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
+ dr->condition = err;
+ dr->which = Z_DefaultDiagFormat_v2Addinfo;
+ dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
+ return rec;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest &&
+ apdu->u.searchRequest->query &&
+ apdu->u.searchRequest->query->which == Z_Query_type_104 &&
+ apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL)
+ {
+ Z_RPNQuery *rpnquery = 0;
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ char *addinfo = 0;
+
+ yaz_log(LOG_LOG, "%sCQL: %s", m_session_str,
+ sr->query->u.type_104->u.cql);
+
+ int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
+ &rpnquery, odr_encode(),
+ &addinfo);
+ if (r == -3)
+ yaz_log(LOG_LOG, "%sNo CQL to RPN table", m_session_str);
+ else if (r)
+ {
+ yaz_log(LOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(),
+ yaz_diag_srw_to_bib1(r),
+ addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ else
+ {
+ sr->query->which = Z_Query_type_1;
+ sr->query->u.type_1 = rpnquery;
+ }
+ return apdu;
+ }
+ return apdu;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ int err = 0;
+ char *addinfo = 0;
+
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (cfg)
+ err = cfg->check_query(odr_encode(), m_default_target,
+ sr->query, &addinfo);
+ if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
+Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
+{
+ m_marcxml_flag = 0;
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ int err = 0;
+ char *addinfo = 0;
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ Z_RecordComposition rc_temp, *rc = 0;
+ if (sr->smallSetElementSetNames)
+ {
+ rc_temp.which = Z_RecordComp_simple;
+ rc_temp.u.simple = sr->smallSetElementSetNames;
+ rc = &rc_temp;
+ }
+
+ char *stylesheet_name = 0;
+ if (cfg)
+ err = cfg->check_syntax(odr_encode(),
+ m_default_target,
+ sr->preferredRecordSyntax, rc,
+ &addinfo, &stylesheet_name, &m_schema);
+ if (stylesheet_name)
+ {
+ m_parent->low_socket_close();
+
+#if HAVE_XSLT
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+ m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
+ stylesheet_name);
+#endif
+ m_stylesheet_offset = 0;
+ xfree(stylesheet_name);
+
+ m_parent->low_socket_open();
+ }
+ if (err == -1)
+ {
+ sr->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN, VAL_USMARC);
+ m_marcxml_flag = 1;
+ }
+ else if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ else if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ int err = 0;
+ char *addinfo = 0;
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ char *stylesheet_name = 0;
+ if (cfg)
+ err = cfg->check_syntax(odr_encode(), m_default_target,
+ pr->preferredRecordSyntax,
+ pr->recordComposition,
+ &addinfo, &stylesheet_name, &m_schema);
+ if (stylesheet_name)
+ {
+ m_parent->low_socket_close();
+
+#if HAVE_XSLT
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+
+ m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
+ stylesheet_name);
+#endif
+ m_stylesheet_offset = 0;
+ xfree(stylesheet_name);
+
+ m_parent->low_socket_open();
+ }
+ if (err == -1)
+ {
+ pr->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(odr_decode(), CLASS_RECSYN, VAL_USMARC);
+ m_marcxml_flag = 1;
+ }
+ else if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.presentResponse->presentStatus =
+ Z_PresentStatus_failure;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
+Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
+{
+ if (!schema)
+ return 0;
+ Z_ElementSetNames *esn = (Z_ElementSetNames *)
+ odr_malloc(o, sizeof(Z_ElementSetNames));
+ esn->which = Z_ElementSetNames_generic;
+ esn->u.generic = odr_strdup(o, schema);
+ return esn;
+}
+
+void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
+{
+ if (m_s2z_odr_init)
+ {
+ odr_destroy(m_s2z_odr_init);
+ m_s2z_odr_init = 0;
+ }
+ if (m_s2z_odr_search)
+ {
+ odr_destroy(m_s2z_odr_search);
+ m_s2z_odr_search = 0;
+ }
+
+ m_http_keepalive = 0;
+ m_http_version = 0;
+ if (!strcmp(hreq->version, "1.0"))
+ {
+ const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
+ if (v && !strcmp(v, "Keep-Alive"))
+ m_http_keepalive = 1;
+ else
+ m_http_keepalive = 0;
+ m_http_version = "1.0";
+ }
+ else
+ {
+ const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
+ if (v && !strcmp(v, "close"))
+ m_http_keepalive = 0;
+ else
+ m_http_keepalive = 1;
+ m_http_version = "1.1";
+ }
+
+ Z_SRW_PDU *srw_pdu = 0;
+ Z_SOAP *soap_package = 0;
+ char *charset = 0;
+ Z_SRW_diagnostic *diagnostic = 0;
+ int num_diagnostic = 0;
+ if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+ &charset) == 0
+ || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+ &charset, &diagnostic, &num_diagnostic) == 0)
+ {
+ m_s2z_odr_init = odr_createmem(ODR_ENCODE);
+ m_s2z_odr_search = odr_createmem(ODR_ENCODE);
+ m_soap_ns = odr_strdup(m_s2z_odr_search, soap_package->ns);
+ m_s2z_init_apdu = 0;
+ m_s2z_search_apdu = 0;
+ m_s2z_present_apdu = 0;
+
+ m_s2z_stylesheet = 0;
+
+ if (srw_pdu->which == Z_SRW_searchRetrieve_request)
+ {
+ Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
+
+ m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
+ // recordXPath unsupported.
+ if (srw_req->recordXPath)
+ {
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 72, 0);
+ }
+ // sort unsupported
+ if (srw_req->sort_type != Z_SRW_sort_type_none)
+ {
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 80, 0);
+ }
+ // save stylesheet
+ if (srw_req->stylesheet)
+ m_s2z_stylesheet =
+ odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+
+ // set packing for response records ..
+ if (srw_req->recordPacking &&
+ !strcmp(srw_req->recordPacking, "xml"))
+ m_s2z_packing = Z_SRW_recordPacking_XML;
+ else
+ m_s2z_packing = Z_SRW_recordPacking_string;
+
+ if (num_diagnostic)
+ {
+ Z_SRW_PDU *srw_pdu =
+ yaz_srw_get(odr_encode(),
+ Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->diagnostics = diagnostic;
+ srw_res->num_diagnostics = num_diagnostic;
+ send_srw_response(srw_pdu);
+ return;
+ }
+
+ // prepare search PDU
+ m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
+ Z_APDU_searchRequest);
+ Z_SearchRequest *z_searchRequest =
+ m_s2z_search_apdu->u.searchRequest;
+
+ z_searchRequest->num_databaseNames = 1;
+ z_searchRequest->databaseNames = (char**)
+ odr_malloc(m_s2z_odr_search, sizeof(char *));
+ z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
+ srw_req->database);
+
+ // query transformation
+ Z_Query *query = (Z_Query *)
+ odr_malloc(m_s2z_odr_search, sizeof(Z_Query));
+ z_searchRequest->query = query;
+
+ if (srw_req->query_type == Z_SRW_query_type_cql)
+ {
+ Z_External *ext = (Z_External *)
+ odr_malloc(m_s2z_odr_search, sizeof(*ext));
+ ext->direct_reference =
+ odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
+ ext->indirect_reference = 0;
+ ext->descriptor = 0;
+ ext->which = Z_External_CQL;
+ ext->u.cql = srw_req->query.cql;
+
+ query->which = Z_Query_type_104;
+ query->u.type_104 = ext;
+ }
+ else if (srw_req->query_type == Z_SRW_query_type_pqf)
+ {
+ Z_RPNQuery *RPNquery;
+ YAZ_PQF_Parser pqf_parser;
+
+ pqf_parser = yaz_pqf_create ();
+
+ RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
+ srw_req->query.pqf);
+ if (!RPNquery)
+ {
+ const char *pqf_msg;
+ size_t off;
+ int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
+ yaz_log(LOG_LOG, "%*s^\n", off+4, "");
+ yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
+
+ send_to_srw_client_error(10, 0);
+ return;
+ }
+ query->which = Z_Query_type_1;
+ query->u.type_1 = RPNquery;
+
+ yaz_pqf_destroy (pqf_parser);
+ }
+ else
+ {
+ send_to_srw_client_error(7, "query");
+ return;
+ }
+
+ // present
+ m_s2z_present_apdu = 0;
+ int max = 0;
+ if (srw_req->maximumRecords)
+ max = *srw_req->maximumRecords;
+ int start = 1;
+ if (srw_req->startRecord)
+ start = *srw_req->startRecord;
+ if (max > 0)
+ {
+ // Some backend, such as Voyager doesn't honor piggyback
+ // So we use present always (0 &&).
+ if (0 && start <= 1) // Z39.50 piggyback
+ {
+ *z_searchRequest->smallSetUpperBound = max;
+ *z_searchRequest->mediumSetPresentNumber = max;
+ *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
+
+ z_searchRequest->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
+ VAL_TEXT_XML);
+ if (srw_req->recordSchema)
+ {
+ z_searchRequest->smallSetElementSetNames =
+ z_searchRequest->mediumSetElementSetNames =
+ mk_esn_from_schema(m_s2z_odr_search,
+ srw_req->recordSchema);
+ }
+ }
+ else // Z39.50 present
+ {
+ m_s2z_present_apdu = zget_APDU(m_s2z_odr_search,
+ Z_APDU_presentRequest);
+ Z_PresentRequest *z_presentRequest =
+ m_s2z_present_apdu->u.presentRequest;
+ *z_presentRequest->resultSetStartPoint = start;
+ *z_presentRequest->numberOfRecordsRequested = max;
+ z_presentRequest->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
+ VAL_TEXT_XML);
+ if (srw_req->recordSchema)
+ {
+ z_presentRequest->recordComposition =
+ (Z_RecordComposition *)
+ odr_malloc(m_s2z_odr_search,
+ sizeof(Z_RecordComposition));
+ z_presentRequest->recordComposition->which =
+ Z_RecordComp_simple;
+ z_presentRequest->recordComposition->u.simple =
+ mk_esn_from_schema(m_s2z_odr_search,
+ srw_req->recordSchema);
+ }
+ }
+ }
+ if (!m_client)
+ {
+ m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
+ Z_APDU_initRequest);
+
+ // prevent m_initRequest_apdu memory from being grabbed
+ // in Yaz_Proxy::handle_incoming_Z_PDU
+ m_initRequest_apdu = m_s2z_init_apdu;
+ handle_incoming_Z_PDU(m_s2z_init_apdu);
+ return;
+ }
+ else
+ {
+ handle_incoming_Z_PDU(m_s2z_search_apdu);
+ return;
+ }
+ }
+ else if (srw_pdu->which == Z_SRW_explain_request)
+ {
+ Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
+
+ m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
+
+ // save stylesheet
+ if (srw_req->stylesheet)
+ m_s2z_stylesheet =
+ odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+
+ if (srw_req->recordPacking &&
+ !strcmp(srw_req->recordPacking, "xml"))
+ m_s2z_packing = Z_SRW_recordPacking_XML;
+ else
+ m_s2z_packing = Z_SRW_recordPacking_string;
+
+ if (num_diagnostic)
+ {
+ send_srw_explain_response(diagnostic, num_diagnostic);
+ return;
+ }
+
+ if (!m_client)
+ {
+ m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
+ Z_APDU_initRequest);
+
+ // prevent m_initRequest_apdu memory from being grabbed
+ // in Yaz_Proxy::handle_incoming_Z_PDU
+ m_initRequest_apdu = m_s2z_init_apdu;
+ handle_incoming_Z_PDU(m_s2z_init_apdu);
+ }
+ else
+ send_srw_explain_response(0, 0);
+ return;
+ }
+ else if (srw_pdu->which == Z_SRW_scan_request)
+ {
+ m_s2z_database = odr_strdup(m_s2z_odr_init,
+ srw_pdu->u.scan_request->database);
+
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 4, "scan");
+ Z_SRW_PDU *srw_pdu =
+ yaz_srw_get(odr_encode(),
+ Z_SRW_scan_response);
+ Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
+
+ srw_res->diagnostics = diagnostic;
+ srw_res->num_diagnostics = num_diagnostic;
+ send_srw_response(srw_pdu);
+ return;
+ }
+ else
+ {
+ m_s2z_database = 0;
+
+ send_to_srw_client_error(4, 0);
+ }
+ }
+ int len = 0;
+ Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);
+ timeout(0);
+ send_GDU(p, &len);
+}
+
+void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
+{
+ Z_ReferenceId **refid = get_referenceIdP(apdu);
+ nmem_reset(m_referenceId_mem);
+ if (refid && *refid)
+ {
+ m_referenceId = (Z_ReferenceId *)
+ nmem_malloc(m_referenceId_mem, sizeof(*m_referenceId));
+ m_referenceId->len = m_referenceId->size = (*refid)->len;
+ m_referenceId->buf = (unsigned char *)
+ nmem_malloc(m_referenceId_mem, (*refid)->len);
+ memcpy(m_referenceId->buf, (*refid)->buf, (*refid)->len);
+ }
+ else
+ m_referenceId = 0;
+
+ if (!m_client && m_invalid_session)
+ {
+ m_apdu_invalid_session = apdu;
+ m_mem_invalid_session = odr_extract_mem(odr_decode());
+ apdu = m_initRequest_apdu;
+ }
+
+ // Determine our client.
+ Z_OtherInformation **oi;
+ get_otherInfoAPDU(apdu, &oi);
+ m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
+ if (!m_client)
+ {
+ delete this;
+ return;
+ }
+ m_client->m_server = this;
+
+ if (apdu->which == Z_APDU_initRequest)
+ {
+ if (apdu->u.initRequest->implementationId)
+ yaz_log(LOG_LOG, "%simplementationId: %s",
+ m_session_str, apdu->u.initRequest->implementationId);
+ if (apdu->u.initRequest->implementationName)
+ yaz_log(LOG_LOG, "%simplementationName: %s",
+ m_session_str, apdu->u.initRequest->implementationName);
+ if (apdu->u.initRequest->implementationVersion)
+ yaz_log(LOG_LOG, "%simplementationVersion: %s",
+ m_session_str, apdu->u.initRequest->implementationVersion);
+ if (m_initRequest_apdu == 0)
+ {
+ if (m_initRequest_mem)
+ nmem_destroy(m_initRequest_mem);
+ m_initRequest_apdu = apdu;
+ m_initRequest_mem = odr_extract_mem(odr_decode());
+
+ m_initRequest_preferredMessageSize = *apdu->u.initRequest->
+ preferredMessageSize;
+ *apdu->u.initRequest->preferredMessageSize = 1024*1024;
+ m_initRequest_maximumRecordSize = *apdu->u.initRequest->
+ maximumRecordSize;
+ *apdu->u.initRequest->maximumRecordSize = 1024*1024;
+
+ // save init options for the response..
+ m_initRequest_options = apdu->u.initRequest->options;
+
+ apdu->u.initRequest->options =
+ (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(apdu->u.initRequest->options);
+ int i;
+ for (i = 0; i<= 24; i++)
+ ODR_MASK_SET(apdu->u.initRequest->options, i);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_negotiationModel);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_concurrentOperations);
+
+ // make new version
+ m_initRequest_version = apdu->u.initRequest->protocolVersion;
+ apdu->u.initRequest->protocolVersion =
+ (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
+
+ for (i = 0; i<= 8; i++)
+ ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
+ }
+ if (m_client->m_init_flag)
+ {
+ if (handle_init_response_for_invalid_session(apdu))
+ return;
+ if (m_client->m_initResponse)
+ {
+ Z_APDU *apdu2 = m_client->m_initResponse;
+ apdu2->u.initResponse->otherInfo = 0;
+ if (m_client->m_cookie && *m_client->m_cookie)
+ set_otherInformationString(apdu2, VAL_COOKIE, 1,
+ m_client->m_cookie);
+ apdu2->u.initResponse->referenceId =
+ apdu->u.initRequest->referenceId;
+ apdu2->u.initResponse->options = m_client->m_initResponse_options;
+ apdu2->u.initResponse->protocolVersion =
+ m_client->m_initResponse_version;
+
+ send_to_client(apdu2);
+ return;
+ }
+ }
+ m_client->m_init_flag = 1;
+ }
+ handle_max_record_retrieve(apdu);
+
+ if (apdu)
+ apdu = handle_syntax_validation(apdu);
+
+ if (apdu)
+ apdu = handle_query_transformation(apdu);
+
+ if (apdu)
+ apdu = handle_query_validation(apdu);
+
+ if (apdu)
+ apdu = result_set_optimize(apdu);
+ if (!apdu)
+ {
+ m_client->timeout(m_target_idletime); // mark it active even
+ // though we didn't use it
+ return;
+ }
+
+ // delete other info part from PDU before sending to target
+ get_otherInfoAPDU(apdu, &oi);
+ if (oi)
+ *oi = 0;
+
+ if (apdu->which == Z_APDU_presentRequest &&
+ m_client->m_resultSetStartPoint == 0)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ m_client->m_resultSetStartPoint = *pr->resultSetStartPoint;
+ m_client->m_cache.copy_presentRequest(apdu->u.presentRequest);
+ } else {
+ m_client->m_resultSetStartPoint = 0;
+ }
+ if (m_client->send_to_target(apdu) < 0)
+ {
+ delete m_client;
+ m_client = 0;
+ delete this;
+ }
+ else
+ m_client->m_waiting = 1;
+}
+
+void Yaz_Proxy::connectNotify()
+{
+}
+
+void Yaz_Proxy::shutdown()
+{
+ m_invalid_session = 0;
+ // only keep if keep_alive flag is set...
+ if (m_client &&
+ m_client->m_pdu_recv < m_keepalive_limit_pdu &&
+ m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
+ m_client->m_waiting == 0)
+ {
+ yaz_log(LOG_LOG, "%sShutdown (client to proxy) keepalive %s",
+ m_session_str,
+ m_client->get_hostname());
+ yaz_log(LOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, m_client->m_pdu_recv,
+ m_client->m_bytes_sent + m_client->m_bytes_recv,
+ m_keepalive_limit_bw, m_keepalive_limit_pdu);
+ assert (m_client->m_waiting != 2);
+ // Tell client (if any) that no server connection is there..
+ m_client->m_server = 0;
+ m_invalid_session = 0;
+ }
+ else if (m_client)
+ {
+ yaz_log (LOG_LOG, "%sShutdown (client to proxy) close %s",
+ m_session_str,
+ m_client->get_hostname());
+ assert (m_client->m_waiting != 2);
+ delete m_client;
+ }
+ else if (!m_parent)
+ {
+ yaz_log (LOG_LOG, "%sshutdown (client to proxy) bad state",
+ m_session_str);
+ assert (m_parent);
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sShutdown (client to proxy)",
+ m_session_str);
+ }
+ if (m_parent)
+ m_parent->pre_init();
+ delete this;
+}
+
+const char *Yaz_ProxyClient::get_session_str()
+{
+ if (!m_server)
+ return "0 ";
+ return m_server->get_session_str();
+}
+
+void Yaz_ProxyClient::shutdown()
+{
+ yaz_log (LOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
+ get_hostname());
+ delete m_server;
+ delete this;
+}
+
+void Yaz_Proxy::failNotify()
+{
+ inc_request_no();
+ yaz_log (LOG_LOG, "%sConnection closed by client",
+ get_session_str());
+ shutdown();
+}
+
+void Yaz_ProxyClient::failNotify()
+{
+ if (m_server)
+ m_server->inc_request_no();
+ yaz_log (LOG_LOG, "%sConnection closed by target %s",
+ get_session_str(), get_hostname());
+ shutdown();
+}
+
+void Yaz_ProxyClient::connectNotify()
+{
+ const char *s = get_session_str();
+ const char *h = get_hostname();
+ yaz_log (LOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
+ m_target_idletime);
+ timeout(m_target_idletime);
+ if (!m_server)
+ pre_init_client();
+}
+
+IYaz_PDU_Observer *Yaz_ProxyClient::sessionNotify(IYaz_PDU_Observable
+ *the_PDU_Observable, int fd)
+{
+ return new Yaz_ProxyClient(the_PDU_Observable, 0);
+}
+
+Yaz_ProxyClient::~Yaz_ProxyClient()
+{
+ if (m_prev)
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ m_waiting = 2; // for debugging purposes only.
+ odr_destroy(m_init_odr);
+ delete m_last_query;
+ xfree (m_last_resultSetId);
+ xfree (m_cookie);
+}
+
+void Yaz_ProxyClient::pre_init_client()
+{
+ Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
+ Z_InitRequest *req = apdu->u.initRequest;
+
+ int i;
+ for (i = 0; i<= 24; i++)
+ ODR_MASK_SET(req->options, i);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_negotiationModel);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_concurrentOperations);
+ for (i = 0; i<= 10; i++)
+ ODR_MASK_SET(req->protocolVersion, i);
+
+ if (send_to_target(apdu) < 0)
+ {
+ delete this;
+ }
+ else
+ {
+ m_waiting = 1;
+ m_init_flag = 1;
+ }
+}
+
+void Yaz_Proxy::pre_init()
+{
+ int i;
+ const char *name = 0;
+ const char *zurl_in_use[MAX_ZURL_PLEX];
+ int limit_bw, limit_pdu, limit_req;
+ int target_idletime, client_idletime;
+ int max_clients;
+ int keepalive_limit_bw, keepalive_limit_pdu;
+ int pre_init;
+ const char *cql2rpn = 0;
+
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ zurl_in_use[0] = 0;
+
+ if (m_log_mask & PROXY_LOG_APDU_CLIENT)
+ set_APDU_yazlog(1);
+ else
+ set_APDU_yazlog(0);
+
+ for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use,
+ &limit_bw, &limit_pdu, &limit_req,
+ &target_idletime, &client_idletime,
+ &max_clients,
+ &keepalive_limit_bw,
+ &keepalive_limit_pdu,
+ &pre_init,
+ &cql2rpn) ; i++)
+ {
+ if (pre_init)
+ {
+ int j;
+ for (j = 0; zurl_in_use[j]; j++)
+ {
+ Yaz_ProxyClient *c;
+ int spare = 0;
+ int spare_waiting = 0;
+ int in_use = 0;
+ int other = 0;
+ for (c = m_clientPool; c; c = c->m_next)
+ {
+ if (!strcmp(zurl_in_use[j], c->get_hostname()))
+ {
+ if (c->m_cookie == 0)
+ {
+ if (c->m_server == 0)
+ if (c->m_waiting)
+ spare_waiting++;
+ else
+ spare++;
+ else
+ in_use++;
+ }
+ else
+ other++;
+ }
+ }
+ yaz_log(LOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
+ "sparew=%d preinit=%d",m_session_str,
+ name, zurl_in_use[j], in_use, other,
+ spare, spare_waiting, pre_init);
+ if (spare + spare_waiting < pre_init)
+ {
+ c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
+ c->m_next = m_clientPool;
+ if (c->m_next)
+ c->m_next->m_prev = &c->m_next;
+ m_clientPool = c;
+ c->m_prev = &m_clientPool;
+
+ if (m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ if (c->client(zurl_in_use[j]))
+ {
+ timeout(60);
+ delete c;
+ return;
+ }
+ c->timeout(30);
+ c->m_waiting = 1;
+ c->m_target_idletime = target_idletime;
+ c->m_seqno = m_seqno++;
+ }
+ }
+ }
+ }
+}
+
+void Yaz_Proxy::timeoutNotify()
+{
+ if (m_parent)
+ {
+ if (m_bw_hold_PDU)
+ {
+ timeout(m_client_idletime);
+ Z_GDU *apdu = m_bw_hold_PDU;
+ m_bw_hold_PDU = 0;
+
+ if (apdu->which == Z_GDU_Z3950)
+ handle_incoming_Z_PDU(apdu->u.z3950);
+ else if (apdu->which == Z_GDU_HTTP_Request)
+ handle_incoming_HTTP(apdu->u.HTTP_Request);
+ }
+ else if (m_stylesheet_nprl)
+ convert_xsl_delay();
+ else
+ {
+ inc_request_no();
+
+ yaz_log (LOG_LOG, "%sTimeout (client to proxy)", m_session_str);
+ shutdown();
+ }
+ }
+ else
+ {
+ timeout(600);
+ pre_init();
+ }
+}
+
+void Yaz_Proxy::markInvalid()
+{
+ m_client = 0;
+ m_invalid_session = 1;
+}
+
+void Yaz_ProxyClient::timeoutNotify()
+{
+ if (m_server)
+ m_server->inc_request_no();
+
+ yaz_log (LOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
+ get_hostname());
+ m_waiting = 1;
+ m_root->pre_init();
+ if (m_server && m_init_flag)
+ {
+ // target timed out in a session that was properly initialized
+ // server object stay alive but we mark it as invalid so it
+ // gets initialized again
+ m_server->markInvalid();
+ m_server = 0;
+ }
+ shutdown();
+}
+
+Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent) :
+ Yaz_Z_Assoc (the_PDU_Observable)
+{
+ m_cookie = 0;
+ m_next = 0;
+ m_prev = 0;
+ m_init_flag = 0;
+ m_last_query = 0;
+ m_last_resultSetId = 0;
+ m_last_resultCount = 0;
+ m_last_ok = 0;
+ m_sr_transform = 0;
+ m_waiting = 0;
+ m_init_odr = odr_createmem (ODR_DECODE);
+ m_initResponse = 0;
+ m_initResponse_options = 0;
+ m_initResponse_version = 0;
+ m_initResponse_preferredMessageSize = 0;
+ m_initResponse_maximumRecordSize = 0;
+ m_resultSetStartPoint = 0;
+ m_bytes_sent = m_bytes_recv = 0;
+ m_pdu_recv = 0;
+ m_server = 0;
+ m_seqno = 0;
+ m_target_idletime = 600;
+ m_root = parent;
+}
+
+const char *Yaz_Proxy::option(const char *name, const char *value)
+{
+ if (!strcmp (name, "optimize")) {
+ if (value) {
+ xfree (m_optimize);
+ m_optimize = xstrdup (value);
+ }
+ return m_optimize;
+ }
+ return 0;
+}
+
+void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len)
+{
+
+}
+
+void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len)
+{
+ if (apdu->which == Z_GDU_Z3950)
+ recv_Z_PDU(apdu->u.z3950, len);
+ else if (apdu->which == Z_GDU_HTTP_Response)
+ recv_HTTP_response(apdu->u.HTTP_Response, len);
+ else
+ shutdown();
+}
+
+int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu)
+{
+ if (!m_invalid_session)
+ return 0;
+ m_invalid_session = 0;
+ handle_incoming_Z_PDU(m_apdu_invalid_session);
+ assert (m_mem_invalid_session);
+ nmem_destroy(m_mem_invalid_session);
+ m_mem_invalid_session = 0;
+ return 1;
+}
+
+void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
+{
+ m_bytes_recv += len;
+
+ m_pdu_recv++;
+ m_waiting = 0;
+ if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
+ yaz_log (LOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
+ apdu_name(apdu), get_hostname(), len);
+ if (apdu->which == Z_APDU_initResponse)
+ {
+ if (!m_server) // if this is a pre init session , check for more
+ m_root->pre_init();
+ NMEM nmem = odr_extract_mem (odr_decode());
+ odr_reset (m_init_odr);
+ nmem_transfer (m_init_odr->mem, nmem);
+ m_initResponse = apdu;
+ m_initResponse_options = apdu->u.initResponse->options;
+ m_initResponse_version = apdu->u.initResponse->protocolVersion;
+ m_initResponse_preferredMessageSize =
+ *apdu->u.initResponse->preferredMessageSize;
+ m_initResponse_maximumRecordSize =
+ *apdu->u.initResponse->maximumRecordSize;
+
+ Z_InitResponse *ir = apdu->u.initResponse;
+ char *im0 = ir->implementationName;
+
+ char *im1 = (char*)
+ odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
+ *im1 = '\0';
+ if (im0)
+ {
+ strcat(im1, im0);
+ strcat(im1, " ");
+ }
+ strcat(im1, "(YAZ Proxy)");
+ ir->implementationName = im1;
+
+ nmem_destroy (nmem);
+
+ if (m_server && m_server->handle_init_response_for_invalid_session(apdu))
+ return;
+ }
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ m_last_resultCount = *sr->resultCount;
+ int status = *sr->searchStatus;
+ if (status && (!sr->records || sr->records->which == Z_Records_DBOSD))
+ {
+ m_last_ok = 1;
+
+ if (sr->records && sr->records->which == Z_Records_DBOSD)
+ {
+ m_cache.add(odr_decode(),
+ sr->records->u.databaseOrSurDiagnostics, 1,
+ *sr->resultCount);
+ }
+ }
+ }
+ if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *pr = apdu->u.presentResponse;
+ if (m_sr_transform)
+ {
+ m_sr_transform = 0;
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ Z_SearchResponse *sr = new_apdu->u.searchResponse;
+ sr->referenceId = pr->referenceId;
+ *sr->resultCount = m_last_resultCount;
+ sr->records = pr->records;
+ sr->nextResultSetPosition = pr->nextResultSetPosition;
+ sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
+ apdu = new_apdu;
+ }
+ if (pr->records &&
+ pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
+ {
+ m_cache.add(odr_decode(),
+ pr->records->u.databaseOrSurDiagnostics,
+ m_resultSetStartPoint, -1);
+ m_resultSetStartPoint = 0;
+ }
+ }
+ if (m_cookie)
+ set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
+ if (m_server)
+ {
+ m_server->send_to_client(apdu);
+ }
+ if (apdu->which == Z_APDU_close)
+ {
+ shutdown();
+ }
+}
+
+void Yaz_Proxy::low_socket_close()
+{
+#if WIN32
+#else
+ int i;
+ for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
+ if (m_lo_fd[i] >= 0)
+ ::close(m_lo_fd[i]);
+#endif
+}
+
+void Yaz_Proxy::low_socket_open()
+{
+#if WIN32
+#else
+ int i;
+ for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
+ m_lo_fd[i] = open("/dev/null", O_RDONLY);
+#endif
+}
+
+int Yaz_Proxy::server(const char *addr)
+{
+ int r = Yaz_Z_Assoc::server(addr);
+ if (!r)
+ {
+ yaz_log(LOG_LOG, "%sStarted proxy "
+#ifdef VERSION
+ VERSION
+#endif
+ " on %s", m_session_str, addr);
+ timeout(1);
+ }
+ return r;
+}
+
--- /dev/null
+## $Id: yazpp.m4,v 1.1 2004-04-11 11:36:46 adam Exp $
+AC_DEFUN([YAZPP_INIT],
+[
+ AC_SUBST(YAZPPLIB)
+ AC_SUBST(YAZPPLALIB)
+ AC_SUBST(YAZPPINC)
+ AC_SUBST(YAZPPVERSION)
+ yazppconfig=NONE
+ yazpppath=NONE
+ AC_ARG_WITH(yazppconfig, [ --with-yazppconfig=DIR yaz++-config in DIR (example /home/yaz++-0.5)], [yazpppath=$withval])
+ if test "x$yazpppath" != "xNONE"; then
+ yazppconfig=$yazpppath/yaz++-config
+ else
+ if test "x$srcdir" = "x"; then
+ yazppsrcdir=.
+ else
+ yazppsrcdir=$srcdir
+ fi
+ for i in ${yazppsrcdir}/../yaz++-* ${yazppsrcdir}/../yaz++; do
+ if test -d $i; then
+ if test -r $i/yaz++-config; then
+ yazppconfig=$i/yaz++-config
+ fi
+ fi
+ done
+ if test "x$yazppconfig" = "xNONE"; then
+ AC_PATH_PROG(yazppconfig, yaz-config, NONE)
+ fi
+ fi
+ AC_MSG_CHECKING(for YAZ++)
+ if $yazppconfig --version >/dev/null 2>&1; then
+ YAZPPLIB=`$yazppconfig --libs $1`
+ YAZPPLALIB=`$yazppconfig --lalibs $1`
+ YAZPPINC=`$yazppconfig --cflags $1`
+ YAZPPVERSION=`$yazppconfig --version`
+ AC_MSG_RESULT($yazppconfig)
+ else
+ AC_MSG_RESULT(Not found)
+ YAZVERSION=NONE
+ fi
+])
+