#!/usr/bin/python # Build a bibliography for an xml2rfc input file # # Eric Rescorla # # Copyright (c) 2008, RTFM, INC. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the RTFM, INC. nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY RTFM, INC. ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL RTFM, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import getopt import urllib2 from xml.sax import make_parser from xml.sax import ContentHandler, handler from os.path import exists, dirname, abspath, isdir from os import mkdir # Constants REFDIR="references" REF_RFC_URI_PREFIX="http://xml.resource.org/public/rfc/bibxml/reference.RFC." REF_ID_URI_PREFIX="http://xml.resource.org/public/rfc/bibxml3/reference." def usage(): sys.stderr.write("usage: bibxml2rfc [-inv] filename\n\ -i fake entries for IETF documents\n\ -n don't try to download new entries (operate from cache)\n\ -v verbose\n") sys.exit(1) def get_reference(name,cachefile): report("Getting reference "+name+" (cachefile="+cachefile+")") cached = None # Look in the cache report("Checking cache") if exists(cachefile): report("Already in cache") fh = open(cachefile,'r') cached=fh.read() if name.startswith("I-D."): # Internet Draft if (cached != None) and (dont_refresh_entries): return cached # There may be new versions so need to check the net uri=REF_ID_URI_PREFIX + name + ".xml" elif name.startswith("RFC"): # RFC # RFCs never change if cached != None: return cached uri=REF_RFC_URI_PREFIX + name[3:] + ".xml" else: # Something unknown. Don't know how to fetch return cached try: report("Trying to fetch uri "+uri) fh = urllib2.urlopen(uri) res = fh.read() fh.close() except Exception: warning("Could not fetch referene for "+name+" (url="+uri+")") if cached != None: report("Using cached value") return cached if fake_ietf_entries == True: report("Faking entry for "+name) res = '\n' + 'Fake Entry\n'+'\n'+ '\n'+ '\n'+ '\n'+ '\n' return res else: return None # OK, we have the file. Now open the cachefile and store it there report("Successfully fetched "+name) fh = open(cachefile, 'w') fh.write(res) fh.close() return res def warning(a): sys.stderr.write(a+"\n") def report(a): if verbose == True: sys.stdout.write(a+"\n") def opt_isset(opts,flag): for opt in opts: if opt[0] == flag: return True # Control parameters verbose = False fake_ietf_entries = True dont_refresh_entries = False # Read the command line arguments getopt_out=getopt.getopt(sys.argv[1:],"vin") options=getopt_out[0] if opt_isset(options,'-v'): verbose=True if opt_isset(options,'-i'): fake_ietf_entries=True if opt_isset(options,'-n'): dont_refresh_entries=True arguments=getopt_out[1] if len(arguments)!=1: usage() filename=arguments[0] if exists(filename)!=True: sys.stderr.write("File "+filename+" does not exist\n") sys.exit(1) filedir=dirname(abspath(filename)) # If the references directory does not exist, make it refdir = filedir + '/' + REFDIR if isdir(refdir)==False: mkdir(refdir) # Open the files to write to f_normative = open(filename + "-normative","w") f_informative = open(filename + "-informative","w") reference_out={}; reference_body={}; # Find all the references class XrefHandler(ContentHandler): def startElement(self, name, attrs): if name.lower() != "xref": return try: target = attrs.getValue("target") except KeyError: return report("processing xref for "+target) if target.find("/") != -1: warning("Illegal character '/' in target '"+target+"'") return # Figure out what kind of reference it is try: norm = attrs.getValue("norm").lower() if norm == "true": normative=f_normative elif norm == "false": normative=f_informative else: sys.stderr.write("Unknown 'norm' value '"+norm+"' for target '"+target+"'. Assuming informative.\n") normative=f_informative except KeyError: normative=f_informative cachefile = refdir + "/" + target + ".xml" ref_body = get_reference(target, cachefile) if ref_body != None: """ Add this reference if it's not already listed If it is already listed but as informative and defined here as normative, then override it""" if reference_out.has_key(target)==False: reference_out[target]=normative reference_body[target]=ref_body else: if reference_out[target]==f_informative and normative==True: reference_out[target]=f_normative # Parse the document parser=make_parser() parser.setContentHandler(XrefHandler()) parser.setFeature(handler.feature_external_ges,False) parser.parse(filename) # Now write out the reference sections refs = reference_out.keys() for key in sorted(refs): report("Including reference for "+key) reference_out[key].write("\n\n") reference_out[key].write(reference_body[key]) # Success sys.exit(0)