def Test(tester): base = Uri.OsPathToUri(__file__, attemptAbsolute=True) tester.startGroup('Simple XLinks') from Ft.Xml.XLink.Processor import Processor tester.startTest('Process w/xlink:show="embed"') uri1 = Uri.Absolutize('addr_book1.xml', base) isrc = InputSource.DefaultFactory.fromUri(uri1) p = Processor() doc = p.run(isrc) stream = cStringIO.StringIO() Print(doc, stream) actual = stream.getvalue() tester.compare(EXPECTED_1, actual, func=TreeCompare.TreeCompare) tester.testDone() tester.startTest('Process w/xlink:show="replace"') uri3 = Uri.Absolutize('addr_book3.xml', base) isrc = InputSource.DefaultFactory.fromUri(uri3) p = Processor() doc = p.run(isrc) stream = cStringIO.StringIO() Print(doc, stream) actual = stream.getvalue() tester.compare(EXPECTED_2, actual, func=TreeCompare.TreeCompare) tester.testDone() return tester.groupDone()
def _parseTr9401(self, data): """ Parse a TR9401 Catalog, as specified in <http://www.oasis-open.org/specs/a401.htm>. Partially implemented. """ prefer_public = True base = self.uri for cmd in TR9401.findall(data): token = cmd[0].upper() if token == 'PUBLIC': if len(cmd) == 3: self.publicIds[cmd[1]] = (Uri.Absolutize(cmd[2], base), prefer_public) elif token == 'SYSTEM': if len(cmd) == 3: self.systemIds[cmd[1]] = Uri.Absolutize(cmd[2], base) elif token == 'BASE': base = cmd[1] elif token[:8] == 'OVERRIDE': prefer_public = token[8:].strip() == 'YES' elif token == 'DELEGATE': if len(cmd) == 3: self.publicDelegates[cmd[1]] = Uri.Absolutize(cmd[2], base) elif token == 'CATALOG': if len(cmd) == 2: catalog = Catalog(Uri.Absolutize(cmd[1], base), self.quiet) self.catalogs.append(catalog) return
def Test(tester): tester.startGroup("instantiation of runNode") base = Uri.OsPathToUri(__file__, attemptAbsolute=True) src_uri = Uri.Absolutize('addr_book1.xml', base) sty_uri = Uri.Absolutize('addr_book1.xsl', base) tester.startTest("without whitespace preservation") p = Processor.Processor() node = Domlette.NonvalidatingReader.parseUri(src_uri) isrc = InputSource.DefaultFactory.fromUri(sty_uri) p.appendStylesheet(isrc) res = p.runNode(node, src_uri, ignorePis=True, preserveSrc=False) tester.compare(expected, res, func=TreeCompare.TreeCompare) tester.testDone() tester.startTest("with whitespace preservation") p = Processor.Processor() node = Domlette.NonvalidatingReader.parseUri(src_uri) isrc = InputSource.DefaultFactory.fromUri(sty_uri) p.appendStylesheet(isrc) res = p.runNode(node, src_uri, ignorePis=True, preserveSrc=True) tester.compare(expected, res, func=TreeCompare.TreeCompare) tester.testDone() tester.groupDone() return
def BaseUri(node, fallback=None): """ `BaseUri` is an implementation of the `node.baseURI` attribute that should be attached to DOM Level 3 nodes, but which is currently broken in 4Suite XML. Where you would use `node.baseURI` according to DOM Level 3, use `BaseUri(node)` (this function) instead. `BaseUri` returns the absolute base URI for a given `node` in a Domlette tree, or `None` if no such *absolute* base URI exists. If `fallback` is specified, then it is used to construct a base URI when everything else fails. """ baseUriPart = '' xmlBaseAncestorList = node.xpath('ancestor-or-self::*[@xml:base][1]') if len(xmlBaseAncestorList) > 0: node = xmlBaseAncestorList[0] baseUriPart = node.getAttributeNS(XML_NAMESPACE, 'base') # If the xml:base in scope for the current node is not absolute, we find # the element where that xml:base was declared, then Absolutize our # relative xml:base against the base URI of the parent of declaring # element, recursively. if (not Uri.IsAbsolute(baseUriPart) and node.parentNode is not None): baseUriPart = Uri.Absolutize(baseUriPart, BaseUri(node.parentNode)) # If we still don't have an absolute base URI, resolve against the # document's URI. if not Uri.IsAbsolute(baseUriPart): if hasattr(node, 'createElementNS'): baseUriPart = Uri.Absolutize(baseUriPart, node.documentURI) else: baseUriPart = Uri.Absolutize(baseUriPart, node.ownerDocument.documentURI) # Next, we try resolving against the fallback base URI, if one has been # provided. if not Uri.IsAbsolute(baseUriPart) and fallback is not None: baseUriPart = Uri.Absolutize(baseUriPart, fallback) # And if we *still* don't have an absolute base URI, well, there's not # much more we can do. No biscuit. Do we want to generate one if we # get to this case, instead of returning `None`? if not Uri.IsAbsolute(baseUriPart): return None else: return baseUriPart
def ResolveUrl(context, base, rel): """ Returns the relative URL ref given in the second argument resolved against the base given in the first argument. In case of URI processing error an empty string is returned """ base = Conversions.StringValue(base) rel = Conversions.StringValue(rel) try: return Uri.Absolutize(rel, base) except Uri.UriException: return u''
def doExceptionTest(tester, title, expected_exc_class, expected_exc_attrs, src_str=None, src_filename=None): tester.startTest(title) if src_filename is not None: uri = Uri.Absolutize(src_filename, BASE_URI) tester.testException(READER.parseUri, (uri, ), expected_exc_class, expected_exc_attrs) elif src_str is not None: tester.testException(READER.parseString, (src_str, BASE_URI), expected_exc_class, expected_exc_attrs) else: tester.exception("No source to attempt to parse!") tester.testDone() return
def instantiate(self, context, processor): context.processorNss = self.namespaces context.currentInstruction = self # this uses attributes directly from self self._output_parameters.avtParse(self, context) href = self._href.evaluate(context) if Uri.IsAbsolute(href): uri = href else: try: uri = Uri.Absolutize(href, Uri.OsPathToUri(processor.writer.getStream().name)) except Exception, e: raise XsltRuntimeException( ExsltError.NO_EXSLTDOCUMENT_BASE_URI, context.currentInstruction, href)
def Test(tester): base_uri = Uri.OsPathToUri(__file__, attemptAbsolute=True) tester.startTest('Creating test environment') from Ft.Xml import XPointer from Ft.Xml import Domlette r = Domlette.NonvalidatingReader doc_uri = Uri.Absolutize('addrbook.xml', base_uri) doc = r.parseUri(doc_uri) ADDRBOOK = doc.documentElement elementType = lambda n, nt=Node.ELEMENT_NODE: n.nodeType == nt ENTRIES = filter(elementType, ADDRBOOK.childNodes) PA = ENTRIES[0] children = filter(elementType, PA.childNodes) PA_NAME = children[0] PA_ADDR = children[1] PA_WORK = children[2] PA_FAX = children[3] PA_PAGER = children[4] PA_EMAIL = children[5] EN = ENTRIES[1] children = filter(elementType, EN.childNodes) EN_NAME = children[0] EN_ADDR = children[1] EN_WORK = children[2] EN_FAX = children[3] EN_PAGER = children[4] EN_EMAIL = children[5] VZ = ENTRIES[2] tester.testDone() # Just one; it can be too confusing to compare much else # because the documents are different uri = Uri.Absolutize('addrbook.xml#element(/1)', base_uri) tester.startTest('SelectUri(%s)' % uri) result = XPointer.SelectUri(uri) tester.compare(1, len(result)) tester.compare(ADDRBOOK.nodeName, result[0].nodeName) tester.testDone() tester.startTest('SelectNode()') frag = 'element(pa/2)' result = XPointer.SelectNode(doc, frag) tester.compare([PA_ADDR], result, 'frag=%s' % frag) frag = 'xpointer(//ENTRY[@ID="en"]/EMAIL)' result = XPointer.SelectNode(doc, frag) tester.compare([EN_EMAIL], result, 'frag=%s' % frag) tester.testDone() if tester.offline: # No further testing return tester.startTest('Testing remote lookup') nss = {'xsl': 'http://www.w3.org/1999/XSL/Transform'} uri = "http://www.w3.org/Style/XSL/stylesheets/public2html.xsl#xpointer(//xsl:template[@match='/'])" try: result = XPointer.SelectUri(uri, nss=nss) except UriException, error: if error.errorCode != UriException.RESOURCE_ERROR: raise tester.warning("No internet connection available")
def Test(tester): tester.startGroup('UriDict') tester.startGroup('file:/// and file://localhost/ equivalence') tester.startTest('equivalent key in UriDict') uris = Uri.UriDict() uris['file:///path/to/resource'] = 0 tester.compare(True, 'file://localhost/path/to/resource' in uris, 'RFC 1738 localhost support failed') tester.testDone() tester.startTest('value of 2 equivalent keys') uris = Uri.UriDict() uris['file:///path/to/resource'] = 1 uris['file://localhost/path/to/resource'] = 2 tester.compare(2, uris['file:///path/to/resource'], 'RFC 1738 localhost support failed') tester.testDone() tester.groupDone() tester.startGroup('case equivalence') for uri, expected, junk in caseNormalizationTests: tester.startTest('%s and %s equivalence' % (uri, expected)) uris[uri] = 1 uris[expected] = 2 tester.compare(2, uris[uri]) tester.testDone() tester.groupDone() tester.startGroup('percent-encoding equivalence') for uri, expected in pctEncNormalizationTests: tester.startTest('%s and %s equivalence' % (uri, expected)) uris[uri] = 1 uris[expected] = 2 tester.compare(2, uris[uri]) tester.testDone() tester.groupDone() tester.groupDone() tester.startGroup("PercentEncode and PercentDecode") for unencoded, encoded in percentEncodeTests: if len(unencoded) > 10: test_title = unencoded[:11] + '...' else: test_title = unencoded tester.startTest(repr(test_title)) tester.compare(encoded, Uri.PercentEncode(unencoded)) tester.compare(unencoded, Uri.PercentDecode(encoded)) tester.testDone() # non-BMP tests: # a couple of random chars from U+10000 to U+10FFFD. # # This string will be length 2 or 4 depending on how Python # was built. Either way, it should result in the same percent- # encoded sequence, which should decode back to the original # representation. unencoded = u'\U00010000\U0010FFFD' encoded = u'%F0%90%80%80%F4%8F%BF%BD' tester.startTest("u'\U00010000\U0010FFFD'") tester.compare(encoded, Uri.PercentEncode(unencoded)) tester.compare(unencoded, Uri.PercentDecode(encoded)) tester.testDone() # # This string will be length 4, regardless of how Python was # built. However, if Python was built with wide (UCS-4) chars, # PercentDecode will generate an optimal string (length: 2). unencoded_in = u'\ud800\udc00\udbff\udffd' encoded = u'%F0%90%80%80%F4%8F%BF%BD' unencoded_out = u'\U00010000\U0010FFFD' tester.startTest("u'\ud800\udc00\udbff\udffd'") tester.compare(encoded, Uri.PercentEncode(unencoded_in)) tester.compare(unencoded_out, Uri.PercentDecode(encoded)) tester.testDone() # test a few iso-8859-n variations just to make sure # iso-8859-1 isn't special unencoded = ''.join(map(chr, range(256))) encoded = '%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F' \ '%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F' \ '%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F' \ '0123456789%3A%3B%3C%3D%3E%3F%40' \ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60' \ 'abcdefghijklmnopqrstuvwxyz%7B%7C%7D~' \ '%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F' \ '%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F' \ '%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF' \ '%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF' \ '%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF' \ '%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF' \ '%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF' \ '%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF' for part in (1, 2, 3, 15): enc_name = 'iso-8859-%d' % part tester.startTest(enc_name) try: codecs.lookup(enc_name) except LookupError: tester.warning('Not supported on this platform') tester.testDone() continue tester.compare(encoded, Uri.PercentEncode(unencoded, encoding=enc_name)) tester.compare(unencoded, Uri.PercentDecode(encoded, encoding=enc_name)) tester.testDone() # utf-16be: why not? unencoded = u'a test string...\x00\xe9...\x20\x22...\xd8\x00\xdc\x00' encoded = u'a%20test%20string...\u00e9...%20%22...%D8%00%DC%00' tester.groupDone() tester.startGroup("PublicIdToUrn") for publicid, urn in publicIdTests: tester.startTest(publicid) tester.compare(urn, Uri.PublicIdToUrn(publicid)) tester.testDone() tester.groupDone() tester.startGroup("UrnToPublicId") for publicid, urn in publicIdTests: tester.startTest(urn) tester.compare(publicid, Uri.UrnToPublicId(urn)) tester.testDone() tester.groupDone() tester.startGroup("URI reference syntax") for testuri in good_URI_references: tester.startTest("Good URI ref: %s" % repr(testuri)) tester.compare(1, Uri.MatchesUriRefSyntax(testuri), "Mistakenly tests as invalid") tester.testDone() for testuri in bad_URI_references: tester.startTest("Bad URI ref: %s" % repr(testuri)) tester.compare(0, Uri.MatchesUriRefSyntax(testuri), "Mistakenly tests as valid") tester.testDone() tester.groupDone() tester.startGroup('Absolutize') for uriRef, baseUri, expectedUri in absolutize_test_cases: tester.startTest('base=%r ref=%r' % (baseUri, uriRef)) res = Uri.Absolutize(uriRef, baseUri) # in a couple cases, there's more than one correct result if isinstance(expectedUri, tuple): tester.compare(1, res in expectedUri, 'Invalid result') else: tester.compare(expectedUri, res, 'Invalid result') tester.testDone() tester.groupDone() tester.startGroup('Relativize') for targetUri, againstUri, relativeUri, subPathUri in relativize_test_cases: tester.startTest('target=%r against=%r (subPathOnly=False)' % (targetUri, againstUri)) res = Uri.Relativize(targetUri, againstUri) tester.compare(relativeUri, res, 'Invalid result') tester.testDone() if res is not None: tester.startTest( 'target=%r against=%r (subPathOnly=False, Absolutize)' % (targetUri, againstUri)) res = Uri.Absolutize(res, againstUri) tester.compare(res, targetUri, 'Invalid result') tester.testDone() tester.startTest('target=%r against=%r (subPathOnly=True)' % (targetUri, againstUri)) res = Uri.Relativize(targetUri, againstUri, True) tester.compare(subPathUri, res, 'Invalid result') tester.testDone() if res is not None: tester.startTest( 'target=%r against=%r (subPathOnly=True, Absolutize)' % (targetUri, againstUri)) res = Uri.Absolutize(res, againstUri) tester.compare(res, targetUri, 'Invalid result') tester.testDone() tester.groupDone() tester.startGroup('BaseJoin') for base, relative, expectedUri in basejoin_test_cases: tester.startTest('base=%r rel=%r' % (base, relative)) res = Uri.BaseJoin(base, relative) tester.compare(expectedUri, res, 'Invalid result') tester.testDone() tester.groupDone() tester.startGroup('UriToOsPath') for osname in ('posix', 'nt'): tester.startGroup(osname) for subgroupname in ('absolute', 'relative'): tester.startGroup(subgroupname) for uri, nt_path, posix_path in fileUris: if subgroupname == 'relative': if uri[:5] == 'file:': uri = uri[5:] else: break if isinstance(uri, unicode): testname = repr(uri) else: testname = uri tester.startTest(testname) if osname == 'nt': path = nt_path elif osname == 'posix': path = posix_path else: break if path is None: tester.testException(Uri.UriToOsPath, (uri, ), Uri.UriException, kwargs={ 'attemptAbsolute': False, 'osname': osname }) else: tester.compare( path, Uri.UriToOsPath(uri, attemptAbsolute=False, osname=osname)) tester.testDone() tester.groupDone() tester.groupDone() tester.groupDone() tester.startGroup('OsPathToUri') for osname in ('posix', 'nt'): tester.startGroup(osname) for path, nt_uri, posix_uri in filePaths: if isinstance(path, unicode): testname = repr(path) else: testname = path tester.startTest(testname) if osname == 'nt': uri = nt_uri elif osname == 'posix': uri = posix_uri else: break if uri is None: tester.testException(Uri.OsPathToUri, (path, ), Uri.UriException, kwargs={ 'attemptAbsolute': False, 'osname': osname }) else: tester.compare( uri, Uri.OsPathToUri(path, attemptAbsolute=False, osname=osname)) tester.testDone() tester.groupDone() tester.groupDone() tester.startGroup('NormalizeCase') for uri, expected0, expected1 in caseNormalizationTests: testname = uri uri = Uri.SplitUriRef(uri) tester.startTest(testname) tester.compare(expected0, Uri.UnsplitUriRef(Uri.NormalizeCase(uri))) tester.testDone() tester.startTest(testname + ' (host too)') tester.compare(expected1, Uri.UnsplitUriRef(Uri.NormalizeCase(uri, doHost=1))) tester.testDone() tester.groupDone() tester.startGroup('NormalizePercentEncoding') for uri, expected in pctEncNormalizationTests: testname = uri tester.startTest(testname) tester.compare(expected, Uri.NormalizePercentEncoding(uri)) tester.testDone() tester.groupDone() tester.startGroup('NormalizePathSegments') for path, expected in pathSegmentNormalizationTests: testname = path tester.startTest(testname) tester.compare(expected, Uri.NormalizePathSegments(path)) tester.testDone() tester.groupDone() tester.startGroup('NormalizePathSegmentsInUri') for path, expectedpath in pathSegmentNormalizationTests: # for non-hierarchical scheme, no change expected in every case uri = 'urn:bogus:%s?a=1&b=2#frag' % path expected = 'urn:bogus:%s?a=1&b=2#frag' % path testname = uri tester.startTest(testname) tester.compare(expected, Uri.NormalizePathSegmentsInUri(uri)) tester.testDone() for path, expectedpath in pathSegmentNormalizationTests: if path[:1] == '/': # hierarchical scheme uri = 'file://*****:*****@host%s?a=1&b=2#frag' % path expected = 'file://*****:*****@host%s?a=1&b=2#frag' % expectedpath testname = uri tester.startTest(testname) tester.compare(expected, Uri.NormalizePathSegmentsInUri(uri)) tester.testDone() tester.groupDone() tester.startGroup("MakeUrllibSafe") tests = makeUrllibSafeTests if os.name == 'nt': tests += winMakeUrllibSafeTests for uri, expected in makeUrllibSafeTests: if isinstance(uri, unicode): test_title = repr(uri) else: test_title = uri tester.startTest(test_title) res = Uri.MakeUrllibSafe(uri) tester.compare(expected, res) tester.testDone() tester.groupDone() tester.startGroup("Basic Uri Resolver") data = [ ('http://foo.com/root/', 'path', 'http://foo.com/root/path'), ('http://foo.com/root', 'path', 'http://foo.com/path'), ] for base, uri, exp in data: tester.startTest("normalize: %s %s" % (base, uri)) res = Uri.BASIC_RESOLVER.normalize(uri, base) tester.compare(exp, res) tester.testDone() base = 'foo:foo.com' uri = 'path' tester.startTest("normalize: %s %s" % (base, uri)) tester.testException(Uri.BASIC_RESOLVER.normalize, (uri, base), Uri.UriException) tester.testDone() tester.startTest('resolve') base = os.getcwd() if base[-1] != os.sep: base += os.sep stream = Uri.BASIC_RESOLVER.resolve('test.py', Uri.OsPathToUri(base)) tester.compare(TEST_DOT_PY_BANGPATH, string.rstrip(stream.readline())) stream.close() tester.testDone() tester.startTest('generate') uuid = Uri.BASIC_RESOLVER.generate() tester.compare('urn:uuid:', uuid[:9]) tester.testDone() tester.groupDone() tester.startGroup("SchemeRegistryResolver") def evalSchemeHandler(uri, base=None): if base: uri = base + uri uri = uri[5:] return str(eval(uri)) def shiftSchemeHandler(uri, base=None): if base: uri = base + uri uri = uri[6:] return ''.join([chr(ord(c) + 1) for c in uri]) resolver = SchemeRegistryResolver({ 'eval': evalSchemeHandler, 'shift': shiftSchemeHandler, }) scheme_cases = [ (None, 'eval:150-50', '100'), (None, 'shift:abcde', 'bcdef'), ('eval:150-', '50', '100'), ('shift:ab', 'cde', 'bcdef'), ] for base, relative, expected in scheme_cases: tester.startTest("URI: base=%s uri=%s" % (base, relative)) res = resolver.resolve(relative, base) tester.compare(expected, res) tester.testDone() resolver.handlers[None] = shiftSchemeHandler del resolver.handlers['shift'] for base, relative, expected in scheme_cases: tester.startTest("URI: base=%s uri=%s" % (base, relative)) res = resolver.resolve(relative, base) tester.compare(expected, res) tester.testDone() tester.groupDone() return
def Test(tester): tester.startGroup('XML and TR9401 Catalogs') tester.startTest('Parse an XML Catalog supplied via a URI') cat_path = os.path.join('Xml', 'Core', 'xcatalog.xml') cat_uri = Uri.OsPathToUri(cat_path, attemptAbsolute=1) cat = Catalog(cat_uri) tester.testDone() tf_path = os.path.join('Xml', 'Core', 'include1.xml') try: fd = open(tf_path) orig = fd.read() fd.close() except: fd.close() tester.warning('Could not read test file; skipping resolution tests.') return tester.startTest('Parse an XML Catalog supplied via an InputSource') fd = open(cat_path, 'rb') cat_data = fd.read() fd.close() isrc = NoCatalogFactory.fromString(cat_data, cat_uri) cat = Catalog() cat.isrc = isrc cat.parse() tester.testDone() # The catalog object should map 'urn:bogus:include1.xml' to # 'include1.xml' relative to the catalog's base URI. tester.startTest('Resolve a relative URI reference in the catalog (1)') expected = Uri.Absolutize('include1.xml', cat_uri) tester.compare(expected, cat.uris['urn:bogus:include1.xml']) tester.testDone() # The catalog object should map 'urn:bogus:include1-from-parent.xml' # to 'Core/include1.xml' relative to the catalog's base URI. tester.startTest('Resolve a relative URI reference in the catalog (2)') expected = Uri.Absolutize('Core/include1.xml', cat_uri) tester.compare(expected, cat.uris['urn:bogus:include1-from-parent.xml']) tester.testDone() # Same as above but we'll change the base URI of the catalog and # see if the results are still correct tester.startTest('Resolve a relative URI reference in the catalog (3)') alt_cat_path = os.path.join('Xml', 'xcatalog.xml') alt_cat_uri = Uri.OsPathToUri(alt_cat_path, attemptAbsolute=1) alt_cat_isrc = NoCatalogFactory.fromString(cat_data, alt_cat_uri) alt_cat = Catalog() alt_cat.isrc = alt_cat_isrc alt_cat.uri = alt_cat_uri alt_cat.parse() expected = Uri.Absolutize('Core/include1.xml', alt_cat_uri) tester.compare(expected, alt_cat.uris['urn:bogus:include1-from-parent.xml']) tester.testDone() # Make sure the default catalog exists and isn't empty tester.startTest('4Suite default catalog exists') from Ft.Xml.Catalog import FT_CATALOG entries = FT_CATALOG.publicIds or FT_CATALOG.uris tester.compare(True, len(entries) > 0) tester.testDone() # A test of catalog support in Ft.Xml.InputSource # (actually try to resolve a document URI with a catalog) tester.startTest( 'Resolve doc via InputSource w/Catalog containing rel. URI (1)') factory = InputSourceFactory(catalog=cat) isrc = factory.fromUri('urn:bogus:include1.xml') data = isrc.read() isrc.close() tester.compare(orig, data) tester.testDone() # A test of catalog support in Ft.Xml.InputSource # (same as previous, just with the different catalog base URI) tester.startTest( 'Resolve doc via InputSource w/Catalog containing rel. URI (2)') factory = InputSourceFactory(catalog=alt_cat) isrc = factory.fromUri('urn:bogus:include1-from-parent.xml') data = isrc.read() isrc.close() tester.compare(orig, data) tester.testDone() # A test of catalog support in Ft.Xml.InputSource # and resolving all combinations of Public and System IDs tester.startTest('Resolve ext. entities w/Catalog') xml_uri = Uri.Absolutize('test_catalog_INTERNAL.xml', cat_uri) factory = InputSourceFactory(catalog=cat) isrc = factory.fromString(XML_1, xml_uri) doc = Domlette.NonvalidatingReader.parse(isrc) st = cStringIO.StringIO() Domlette.Print(doc, stream=st) tester.compare(XML_EXPECTED_1, st.getvalue(), func=TreeCompare) tester.testDone() tester.groupDone() return
class Catalog: """ Reads and provides access to a catalog, providing mappings of public and system IDs to URIs, etc. It is implemented as a SAX ContentHandler and is able to read OASIS TR 9401 Catalogs <http://www.oasis-open.org/specs/a401.htm> and OASIS XML Catalogs <http://www.oasis-open.org/committees/entity/spec.html> """ def __init__(self, uri, quiet=True): self.systemIds = {} self.publicIds = {} self.uris = {} self.publicDelegates = [] self.systemDelegates = [] self.uriDelegates = [] self.systemRewrites = [] self.uriRewrites = [] self.catalogs = [] self.uri = uri self.quiet = quiet if not Uri.IsAbsolute(uri): # Using a relative URI here makes it hard to reliably # locate the catalog. Also, if the catalog doesn't set # its own base URI with xml:base, then we won't be able # to resolve relative URI references within the catalog. # So we should warn that this situation is undesirable. warnings.warn("Catalog URI '%s' is not absolute.", FtWarning, 2) stream = Uri.BASIC_RESOLVER.resolve(uri) data = stream.read() stream.close() if IsXml(data): # cannot be a TR 9401 document, assume an XML Catalog self._parseXmlCat(data) else: # cannot be an XML Catalog, assume a TR 9401 file self._parseTr9401(data) # longest match first self.publicDelegates.sort() self.publicDelegates.reverse() self.systemDelegates.sort() self.systemDelegates.reverse() self.uriDelegates.sort() self.uriDelegates.reverse() self.systemRewrites.sort() self.systemRewrites.reverse() self.uriRewrites.sort() self.uriRewrites.reverse() if not quiet: sys.stderr.write('Catalog contents:\n') for key in self.__dict__.keys(): sys.stderr.write(' %s = %r\n' % (key, self.__dict__[key])) sys.stderr.flush() return def resolveEntity(self, publicId, systemId): """ Return the applicable URI. If an external identifier (PUBLIC or SYSTEM) entry exists in the Catalog for the identifier(s) specified, return the mapped value. External identifiers identify the external subset, entities, and notations of an XML document. """ unwrapped, publicId = UnwrapUrn(publicId) unwrapped, systemId = UnwrapUrn(systemId) # If the system identifier is a URN in the publicid namespace, it is # converted into a public identifier by "unwrapping" the URN. if unwrapped: # 1. No public identifier was provided. Resolution continues as if # the public identifier constructed by unwrapping the URN was # supplied as the original public identifier and no system # identifier was provided. if not publicId: publicId = systemId systemId = None # 2. The normalized public identifier provided is lexically # identical to the public identifier constructed by unwrapping # the URN. Resolution continues as if the system identifier had # not been supplied. elif publicId == systemId: systemId = None # 3. The normalized public identifier provided is different from # the public identifier constructed by unwrapping the URN. This # is an error. Applications may recover from this error by # discarding the system identifier and proceeding with the # original public identifier. else: warnings.warn( "publicId %r does not match the unwrapped " "systemId %r" % (publicId, systemId), FtWarning, 2) systemId = None # Resolution follows the steps listed below, proceeding to each # subsequent step if and only if no other action is indicated. # # 1. Resolution begins in the first catalog entry file in the # current catalog entry file list. if systemId is not None: # 2. If a system identifier is provided, and at least one matching # system entry exists, the (absolutized) value of the uri # attribute of the first matching system entry is returned. if systemId in self.systemIds: return self.systemIds[systemId] # 3. If a system identifier is provided, and at least one matching # rewriteSystem entry exists, rewriting is performed. # # Rewriting removes the matching prefix and replaces it with the # rewrite prefix identified by the matching rewriteSystem entry. # The rewritten string is returned. for length, start, rewrite in self.systemRewrites: if start == systemId[:length]: return rewrite + systemId[length:] # 4. If a system identifier is provided, and one or more # delegateSystem entries match, delegation is performed. # # If delegation is to be performed, a new catalog entry file list # is generated from the set of all matching delegateSystem # entries. The (absolutized) value of the catalog attribute of # each matching delegateSystem entry is inserted into the new # catalog entry file list such that the delegate entry with the # longest matching systemIdStartString is first on the list, the # entry with the second longest match is second, etc. # # These are the only catalog entry files on the list, the current # list is not considered for the purpose of delegation. If # delegation fails to find a match, resolution for this entity # does not resume with the current list. (A subsequent resolution # attempt for a different entity begins with the original list; in # other words the catalog entry file list used for delegation is # distinct and unrelated to the "normal" catalog entry file list.) # # Catalog resolution restarts using exclusively the catalog entry # files in this new list and the given system identifier; any # originally given public identifier is ignored during the # remainder of the resolution of this external identifier: return # to step 1. attempted = False for length, start, catalog in self.systemDelegates: if start == systemId[:length]: attempted = True result = catalog.resolveEntity(publicId, systemId) if result: return result if attempted: # delegation attempted but failed, resolution aborted return if publicId is not None: # 5. If a public identifier is provided, and at least one matching # public entry exists, the (absolutized) value of the uri # attribute of the first matching public entry is returned. If a # system identifier is also provided as part of the input to this # catalog lookup, only public entries that occur where the prefer # setting is public are considered for matching. if publicId in self.publicIds: uri, prefer = self.publicIds[publicId] if systemId is None or prefer: return uri # 6. If a public identifier is provided, and one or more # delegatePublic entries match, delegation is performed. If a # system identifier is also provided as part of the input to this # catalog lookup, only delegatePublic entries that occur where # the prefer setting is public are considered for matching. # # See #4 above for details on delegation. attempted = False for length, start, catalog, prefer in self.publicDelegates: if (systemId is None or prefer) and start == publicId[:length]: attempted = True result = catalog.resolveEntity(publicId, systemId) if result: return result if attempted: # delegation attempted but failed, resolution aborted return # 7. If the current catalog entry file contains one or more # nextCatalog entries, the catalog entry files referenced by each # nextCatalog entry's "catalog" attribute are inserted, in the order # that they appear in this catalog entry file, onto the current # catalog entry file list, immediately after the current catalog # entry file. # # 8. If there are one or more catalog entry files remaining on the # current catalog entry file list, load the next catalog entry file # and continue resolution efforts: return to step 2. for catalog in self.catalogs: result = catalog.resolveEntity(publicId, systemId) if result: return result # 9. Indicate to the calling application that no match was found. return def resolveURI(self, uri): """ Return the applicable URI. If a URI entry exists in the Catalog for the URI specified, return the mapped value. URI references, for example namespace names, stylesheets, included files, graphics, and hypertext references, simply identify other resources. """ # If the URI reference is a URN in the publicid namespace # ([RFC 3151]), it is converted into a public identifier by # "unwrapping" the URN (Section 6.4). Resolution continues by # following the semantics of external identifier resolution # (Section 7.1) as if the public identifier constructed by # unwrapping the URN had been provided and no system identifier had # been provided. unwrapped, publicId = UnwrapUrn(uri) if unwrapped: return self.resolveEntity(publicId, None) # Resolution of a generic URI reference follows the steps listed # below, proceeding to each subsequent step if and only if no other # action is indicated. # 1. Resolution begins in the first catalog entry file in the # current catalog list. # 2. If at least one matching uri entry exists, the (absolutized) # value of the uri attribute of the first matching uri entry is # returned. if uri in self.uris: return self.uris[uri] # 3. If at least one matching rewriteURI entry exists, rewriting is # performed. # # Rewriting removes the matching prefix and replaces it with the # rewrite prefix identified by the matching rewriteURI entry. The # rewritten string is returned. for length, start, rewrite in self.uriRewrites: if start == uri[:length]: return rewrite + uri[length:] # 4. If one or more delegateURI entries match, delegation is performed. # # If delegation is to be performed, a new catalog entry file list is # generated from the set of all matching delegateURI entries. The # (absolutized) value of the catalog attribute of each matching # delegateURI entry is inserted into the new catalog entry file list # such that the delegate entry with the longest matching # uriStartString is first on the list, the entry with the second # longest match is second, etc. # # These are the only catalog entry files on the list, the current list # is not considered for the purpose of delegation. If delegation fails # to find a match, resolution for this entity does not resume with the # current list. (A subsequent resolution attempt for a different # entity begins with the original list; in other words the catalog # entry file list used for delegation is distinct and unrelated to the # "normal" catalog entry file list.) # # Catalog resolution restarts using exclusively the catalog entry # files in this new list and the given URI reference: return to step 1. attempted = False for length, start, catalog in self.uriDelegates: if start == uri[:length]: attempted = True result = catalog.resolveURI(uri) if result: return result if attempted: # delegation attempted but failed, resolution aborted return # 5. If the current catalog entry file contains one or more # nextCatalog entries, the catalog entry files referenced by each # nextCatalog entry's "catalog" attribute are inserted, in the order # that they appear in this catalog entry file, onto the current # catalog entry file list, immediately after the current catalog # entry file. # # 6. If there are one or more catalog entry files remaining on the # current catalog entry file list, load the next catalog entry file # and continue resolution efforts: return to step 2. for catalog in self.catalogs: result = catalog.resolveURI(uri) if result: return result # 7. Indicate to the calling application that no match was found. return def _parseXmlCat(self, data): """ Parse an XML Catalog, as specified in http://www.oasis-open.org/committees/entity/spec-2001-08-06.html. Partially implemented. """ self.prefer_public = [True] self.base = [self.uri] # Since we have the catalog data already, parse it. source = xmlreader.InputSource(self.uri) source.setByteStream(cStringIO.StringIO(data)) from Ft.Xml.Sax import CreateParser p = CreateParser() p.setFeature('http://xml.org/sax/features/external-parameter-entities', False) p.setContentHandler(self) p.parse(source) # are these explicit dels needed? del self.prefer_public del self.base return def _parseTr9401(self, data): """ Parse a TR9401 Catalog, as specified in <http://www.oasis-open.org/specs/a401.htm>. Partially implemented. """ prefer_public = True base = self.uri for cmd in TR9401.findall(data): token = cmd[0].upper() if token == 'PUBLIC': if len(cmd) == 3: self.publicIds[cmd[1]] = (Uri.Absolutize(cmd[2], base), prefer_public) elif token == 'SYSTEM': if len(cmd) == 3: self.systemIds[cmd[1]] = Uri.Absolutize(cmd[2], base) elif token == 'BASE': base = cmd[1] elif token[:8] == 'OVERRIDE': prefer_public = token[8:].strip() == 'YES' elif token == 'DELEGATE': if len(cmd) == 3: self.publicDelegates[cmd[1]] = Uri.Absolutize(cmd[2], base) elif token == 'CATALOG': if len(cmd) == 2: catalog = Catalog(Uri.Absolutize(cmd[1], base), self.quiet) self.catalogs.append(catalog) return # methods used by the XML parser def startElementNS(self, (namespace, name), qualifiedName, attrs): """ Handle an element start event for the XML parser. This is a SAX ContentHandler method. """ # update current base URI base = self.base[-1] if name not in ('rewriteSystem', 'rewriteURI'): base = attrs.get((XML_NAMESPACE, 'base'), base) self.base.append(base) if name == 'public': # a publicId lookup if self.__ensure_attrs(name, attrs, 'publicId', 'uri'): # save the state of prefer_public also publicId = attrs[(None, 'publicId')] uri = Uri.Absolutize(attrs[(None, 'uri')], base) self.publicIds[publicId] = (uri, self.prefer_public[-1]) elif name == 'system': # a systemId lookup if self.__ensure_attrs(name, attrs, 'systemId', 'uri'): systemId = attrs[(None, 'systemId')] uri = Uri.Absolutize(attrs[(None, 'uri')], base) self.systemIds[systemId] = uri elif name == 'uri': # a URI lookup if self.__ensure_attrs(name, attrs, 'name', 'uri'): name = attrs[(None, 'name')] uri = Uri.Absolutize(attrs[(None, 'uri')], base) self.uris[name] = uri elif name == 'rewriteURI': # a URI rewrite if self.__ensure_attrs(name, attrs, 'uriStartString', 'rewritePrefix'): startString = attrs[(None, 'uriStartString')] rewritePrefix = Uri.Absolutize(attrs[(None, 'rewritePrefix')], base) rewriteRule = (len(startString), startString, rewritePrefix) self.uriRewrites.append(rewriteRule) elif name == 'rewriteSystem': # a systemId rewrite if self.__ensure_attrs(name, attrs, 'systemIdStartString', 'rewritePrefix'): startString = attrs[(None, 'systemIdStartString')] rewritePrefix = Uri.Absolutize(attrs[(None, 'rewritePrefix')], base) rewriteRule = (len(startString), startString, rewritePrefix) self.systemRewrites.append(rewriteRule) elif name == 'delegateSystem': # delegate systemId to specific catalog if self.__ensure_attrs(name, attrs, 'systemIdStartString', 'catalog '): startString = attrs[(None, 'systemIdStartString')] catalog = Uri.Absolutize(attrs[(None, 'catalog')], base) delegate = Catalog(catalog, self.quiet) delegateRule = (len(startString), startString, delegate) self.systemDelegates.append(delegateRule) elif name == 'delegatePublic': # delegate publicId to specific catalog if self.__ensure_attrs(name, attrs, 'publicIdStartString', 'catalog '): # save the state of prefer_public also startString = attrs[(None, 'publicIdStartString')] catalog = Uri.Absolutize(attrs[(None, 'catalog')], base) delegate = Catalog(catalog, self.quiet) delegateRule = (len(startString), startString, delegate, self.prefer_public[-1]) self.publicDelegates.append(delegateRule) elif name == 'delegateURI': # delegate URI to specific catalog if self.__ensure_attrs(name, attrs, 'uriStartString', 'catalog '): startString = attrs[(None, 'uriStartString')] catalog = Uri.Absolutize(attrs[(None, 'catalog')], base) delegate = Catalog(catalog, self.quiet) delegateRule = (len(startString), startString, delegate) self.uriDelegates.append(delegateRule) elif name == 'nextCatalog': # the next catalog in a chain if self.__ensure_attrs(name, attrs, 'catalog'): catalog = Uri.Absolutize(attrs[(None, 'catalog')], base) self.catalogs.append(Catalog(catalog, self.quiet)) elif name in ('catalog', 'group'): # look for prefer attribute and update the stack prefer = self.prefer_public[-1] and 'public' or 'system' prefer = attrs.get((None, 'prefer'), prefer) == 'public' self.prefer_public.append(prefer) return
<document xmlns:xi="http://www.w3.org/2001/XInclude"> <p>120 Mz is adequate for an average home user.</p> <xi:include href="disclaimer.xml"> <xi:fallback><foo/></xi:fallback> </xi:include> </document>""" SPEC_EXPECTED_1 = """<?xml version="1.0" encoding="UTF-8"?> <document xmlns:xi="http://www.w3.org/2001/XInclude"> <p>120 Mz is adequate for an average home user.</p> <disclaimer xml:base="%s"> <p>The opinions represented herein represent those of the individual and should not be interpreted as official policy endorsed by this organization.</p> </disclaimer> </document>""" % Uri.Absolutize("disclaimer.xml", BASE_URI) SPEC_SRC_2 = """<?xml version='1.0'?> <document xmlns:xi="http://www.w3.org/2001/XInclude"> <p>This document has been accessed <xi:include href="count.txt" parse="text"/> times.</p> </document>""" SPEC_EXPECTED_2 = """<?xml version="1.0" encoding="UTF-8"?> <document xmlns:xi="http://www.w3.org/2001/XInclude"> <p>This document has been accessed 324387 times.</p> </document>""" SPEC_SRC_3 = """<?xml version='1.0'?> <document xmlns:xi="http://www.w3.org/2001/XInclude">
def normalize(self, uri_ref, base_uri): return Uri.Absolutize(uri_ref, base_uri)
#Thomas Guettler <*****@*****.**> wants to use XInclude in his stylesheets from Xml.Xslt import test_harness import os from Ft.Lib import Uri BASE_URI = Uri.OsPathToUri(os.path.abspath(__file__), attemptAbsolute=True) INCLUDE_URI = Uri.Absolutize('tg_20010628-include.xml', BASE_URI) sheet_1 = """\ <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xinclude="http://www.w3.org/2001/XInclude"> <xsl:output method="html" indent="yes" encoding="iso-8859-1"/> <!-- copy source nodes to result nodes --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="body"> <body bgcolor='#ffbf00'> <xsl:apply-templates/> <xinclude:include href="%(uri)s"/> </body> </xsl:template>
def test_extent_xinclude(tester, domMod): tester.startGroup("Reader + External Entities + XInclude") SRC_1 = """\ <?xml version='1.0'?> <!DOCTYPE x [ <!ENTITY inc SYSTEM "include1.xml"> ]> <x> &inc; </x>""" expected_1 = """<?xml version='1.0' encoding='UTF-8'?><x> <foo xml:base="%s"/> </x>""" % Uri.Absolutize("include1.xml", BASE_PATH) tester.startTest("External entity") src = InputSource.DefaultFactory.fromString(SRC_1, BASE_PATH) doc = domMod.NonvalParse(src) stream = cStringIO.StringIO() Domlette.Print(doc, stream) tester.compare(expected_1, stream.getvalue(), func=TreeCompare.TreeCompare) tester.testDone() SRC_2 = """\ <?xml version='1.0'?> <x xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="include1.xml"/> </x>""" expected_2 = """<?xml version='1.0' encoding='UTF-8'?> <x xmlns:xi='http://www.w3.org/2001/XInclude'> <foo xml:base="%s"/> </x>""" % Uri.Absolutize("include1.xml", BASE_PATH) tester.startTest("Basic XInclude") src = InputSource.DefaultFactory.fromString(SRC_2, BASE_PATH) doc = domMod.NonvalParse(src) stream = cStringIO.StringIO() Domlette.Print(doc, stream) tester.compare(expected_2, stream.getvalue(), func=TreeCompare.NoWsTreeCompare) tester.testDone() SRC_3 = """\ <?xml version='1.0'?> <x xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="include2.xml"/> </x>""" expected_3 = """<?xml version='1.0' encoding='UTF-8'?> <x xmlns:xi='http://www.w3.org/2001/XInclude'> <foo xml:base="%s"> <foo xml:base="%s"/> </foo> </x> """ % (Uri.Absolutize("include2.xml", BASE_PATH), Uri.Absolutize("include1.xml", BASE_PATH)) tester.startTest("Recursive XInclude") src = InputSource.DefaultFactory.fromString(SRC_3, BASE_PATH) doc = domMod.NonvalParse(src) stream = cStringIO.StringIO() Domlette.Print(doc, stream) tester.compare(expected_3, stream.getvalue(), func=TreeCompare.NoWsTreeCompare) tester.testDone() SRC_4 = """\ <?xml version='1.0'?> <x xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="include2.xml" parse='text'/> </x>""" from test_xinclude import LINESEP expected_4 = """<?xml version='1.0' encoding='UTF-8'?> <x xmlns:xi='http://www.w3.org/2001/XInclude'> <?xml version='1.0' encoding='utf-8'?>%(linesep)s<foo xmlns:xi="http://www.w3.org/2001/XInclude">%(linesep)s <xi:include href="include1.xml"/>%(linesep)s</foo> </x> """ % { 'linesep': LINESEP } tester.startTest("XInclude text attribute") src = InputSource.DefaultFactory.fromString(SRC_4, BASE_PATH) doc = domMod.NonvalParse(src) stream = cStringIO.StringIO() Domlette.Print(doc, stream) tester.compare(expected_4, stream.getvalue(), func=TreeCompare.TreeCompare) tester.testDone() tester.groupDone() return
def Test(tester): base = Uri.OsPathToUri(__file__, attemptAbsolute=True) uri = Uri.Absolutize('od_20000608.xml', base) test1(tester, uri, '//author', 'no match') test1(tester, uri, '//date', 'Some Matches') return