[ENH] XML namespace handling, take two
Simon Dobson
simon.dobson at computer.org
Mon May 26 16:28:09 UTC 2003
...and this time he remembers the attachment...
--
-- Simon
--
-------------- next part --------------
'From Squeak3.4 of 1 March 2003 [latest update: #5170] on 26 May 2003 at 12:15:05 pm'!
XMLTokenizer subclass: #SAXDriver
instanceVariableNames: 'saxHandler namespaces defaultNamespace level '
classVariableNames: ''
poolDictionaries: ''
category: 'XML-Parser'!
XMLNodeWithElements subclass: #XMLElement
instanceVariableNames: 'name namespace contents attributes uri '
classVariableNames: ''
poolDictionaries: ''
category: 'XML-Parser'!
!SAXDriver methodsFor: 'handling tokens' stamp: 'sd 5/25/2003 17:35'!
handleStartDocument
self saxHandler startDocument! !
!SAXDriver methodsFor: 'handling tokens' stamp: 'sd 5/26/2003 12:11'!
handleStartTag: elementName attributes: attributeList
| ns uri localName qualifiedName |
self indent.
(self hasNamespace: elementName) ifTrue: [
qualifiedName _ elementName.
ns _ self namespaceOf: elementName.
localName _ self localNameOf: elementName.
"declare any namespaces"
attributeList keysAndValuesDo: [ :k :v |
((self namespaceOf: k) = 'xmlns') ifTrue: [
| n |
n _ self localNameOf: k.
self declareNamespace: n URI: v.
]
].
"ensure our namespace is defined"
(self namespaceURIOf: ns) ifNil: [ self error: 'Start tag ' , elementName , ' refers to undefined namespace' ].
self defaultNamespace: ns.
] ifFalse: [
"qualify the name"
ns _ self defaultNamespace.
qualifiedName _ self qualify: elementName withNamespace: ns.
localName _ elementName.
].
uri _ self namespaceURIOf: ns.
"check all attribute namespaces are defined"
attributeList keysAndValuesDo: [ :k :v |
(self hasNamespace: k) ifTrue: [
| kns |
kns _ self namespaceOf: k.
(self namespaceURIOf: kns) ifNil: [ self error: 'Attribute ' , k , ' refers to undefined namespace' ].
]
].
"call the handler"
self saxHandler
checkEOD;
startElement: localName namespaceURI: uri qualifiedName: qualifiedName attributeList: attributeList! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/26/2003 12:14'!
declareDefaultNamespaces
"Declare any namespaces that should be visible automagically"
self declareNamespace: 'xmlns' URI: 'http://www.w3.org/TR/REC-xml-names'! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 18:59'!
declareNamespace: ns URI: uri
"Declare the given name space prefix with the given URL"
| nss |
nss _ namespaces at: level ifAbsent: [
| dic |
dic _ Dictionary new.
namespaces at: level put: dic.
dic
].
nss at: ns put: uri! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 18:39'!
defaultNamespace
"Retrieve the default namespace at the current parse level"
| nss ns |
level to: 1 by: -1 do: [ :l |
nss _ namespaces at: l ifAbsent: [ nil ].
nss ifNotNil: [
ns _ nss at: '__default__' ifAbsent: [ nil ].
ns ifNotNil: [ ^ ns ].
]
].
"if we get here we didn't find one"
^ nil
! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 18:59'!
defaultNamespace: ns
"Declare the default namespace. This is a it dangerous as it makes use of the
fact that __defualt__ isn't a legal XML namespace prefix to store a value that
isn't a URI....however, it lets us get away without using a parallel stack just to hold
the default, so it's probably worth it"
self declareNamespace: '__default__' URI: ns! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 19:02'!
handleEndTag: elementName
| ns qualifiedName uri localName |
(self hasNamespace: elementName) ifTrue: [
qualifiedName _ elementName.
localName _ self localNameOf: elementName.
ns _ self namespaceOf: elementName.
"ensure our namespace is defined"
(self namespaceURIOf: ns) ifNil: [ self error: 'End tag /' , elementName , ' refers to undefined namespace' ].
] ifFalse: [
"qualify the name"
ns _ self defaultNamespace.
localName _ elementName.
qualifiedName _ self qualify: elementName withNamespace: ns.
].
uri _ self namespaceURIOf: ns.
"call the handler"
self saxHandler
checkEOD;
endElement: localName namespaceURI: uri qualifiedName: qualifiedName.
self outdent
! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 16:55'!
hasNamespace: elem
"Test whether the element or tag name has a namespace part"
^ ((elem findString: ':') > 0)
! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 16:59'!
indent
"Enter a new parsing level"
level _ level + 1
! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 17:33'!
localNameOf: elem
"Extract the local name part of a tag or attribute name"
| i |
i _ elem findString: ':'.
^ (i > 0) ifTrue: [ elem copyFrom: (i + 1) to: elem size ] ifFalse: [ elem ]! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 17:33'!
namespaceOf: elem
"Extract the name space part of a tag or attribute name, if any"
| i |
i _ elem findString: ':'.
^ (i > 0) ifTrue: [ elem copyFrom: 1 to: (i - 1) ] ifFalse: [ nil ]! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 19:00'!
namespaceURI: ns
"Retrieve the URI for the given namespace"
^ self namespaceURI: ns ifAbsent: [ nil ]! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 19:01'!
namespaceURI: ns ifAbsent: b
"Retrieve the URI for the given namespace of the value of the block if not defined"
^ namespaces at: ns ifAbsent: [ b value ]! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 19:01'!
namespaceURIOf: ns
"Retrieve the URI of the given namespace prefix, if it is defined"
| nss uri |
level to: 0 by: -1 do: [ :l |
nss _ namespaces at: l ifAbsent: [ nil ].
nss ifNotNil: [
uri _ nss at: ns ifAbsent: [ nil ].
uri ifNotNil: [ ^ uri ].
]
].
"if we get here we didn't find one"
^ nil! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 16:59'!
outdent
"Move out a parsing level"
namespaces removeKey: level ifAbsent: [].
level _ level - 1
! !
!SAXDriver methodsFor: 'name spaces' stamp: 'sd 5/25/2003 17:33'!
qualify: n withNamespace: ns
"Qualify the name with the namespace (if present)"
| ln |
ln _ self localNameOf: n.
^ ns ifNil: [ ln ] ifNotNil: [ ns , ':' , ln ]! !
!SAXDriver methodsFor: 'initialization' stamp: 'sd 5/25/2003 17:42'!
initialize
super initialize.
namespaces _ Dictionary new.
level _ 0.
self declareDefaultNamespaces! !
!SAXHandler methodsFor: 'accessing' stamp: 'sd 5/23/2003 15:58'!
namespaces
^ self driver namespaces! !
!SAXHandler class methodsFor: 'instance creation' stamp: 'sd 5/23/2003 15:19'!
on: aStream
| driver parser |
driver _ SAXDriver on: aStream.
driver validating: true.
parser _ self new driver: driver.
^parser! !
!XMLDOMParser methodsFor: 'content' stamp: 'sd 5/25/2003 18:31'!
endElement: localName namespaceURI: uri qualifiedName: qualifiedName
| currentElement |
currentElement _ self pop.
currentElement qualifiedName = qualifiedName
ifFalse: [self driver errorExpected: 'End tag "', qualifiedName , '" doesn''t match "' , currentElement qualifiedName , '".']! !
!XMLDOMParser methodsFor: 'content' stamp: 'sd 5/25/2003 18:28'!
startElement: localName namespaceURI: namespaceUri qualifiedName: qualifiedName attributeList: attributeList
| newElement |
newElement _ XMLElement named: localName namespace: (self driver namespaceOf: qualifiedName) uri: namespaceUri attributes: attributeList.
self incremental
ifFalse: [self stack isEmpty
ifFalse: [self top addElement: newElement]].
self push: newElement! !
!XMLElement methodsFor: 'accessing' stamp: 'sd 5/25/2003 18:25'!
name
^ self qualifiedName! !
!XMLElement methodsFor: 'accessing' stamp: 'sd 5/25/2003 18:25'!
tag
^ self name asSymbol! !
!XMLElement methodsFor: 'name space' stamp: 'sd 5/25/2003 18:24'!
localName
^ name! !
!XMLElement methodsFor: 'name space' stamp: 'sd 5/25/2003 18:24'!
namespace
^ namespace! !
!XMLElement methodsFor: 'name space' stamp: 'sd 5/25/2003 18:59'!
namespace: ns URI: u
namespace _ ns.
uri _ u! !
!XMLElement methodsFor: 'name space' stamp: 'sd 5/25/2003 18:24'!
namespaceURI
^ uri! !
!XMLElement methodsFor: 'name space' stamp: 'sd 5/25/2003 18:26'!
qualifiedName
^ namespace ifNil: [ self localName ] ifNotNil: [ namespace , ':' , self localName ]! !
!XMLElement class methodsFor: 'instance creation' stamp: 'sd 5/25/2003 18:58'!
named: aString namespace: ns uri: uri attributes: attributeList
^self new
name: aString;
namespace: ns URI: uri;
setAttributes: attributeList! !
XMLElement removeSelector: #namespace:!
XMLElement removeSelector: #namespace:URL:!
XMLElement removeSelector: #namespace:uri:!
XMLNodeWithElements subclass: #XMLElement
instanceVariableNames: 'name namespace uri contents attributes '
classVariableNames: ''
poolDictionaries: ''
category: 'XML-Parser'!
XMLDOMParser removeSelector: #endElement:!
SAXDriver removeSelector: #declareNamespace:uri:!
SAXDriver removeSelector: #namespaceUri:!
SAXDriver removeSelector: #namespaceUri:ifAbsent:!
SAXDriver removeSelector: #namespaceUriOf:!
XMLTokenizer subclass: #SAXDriver
instanceVariableNames: 'saxHandler namespaces level '
classVariableNames: ''
poolDictionaries: ''
category: 'XML-Parser'!
More information about the Squeak-dev
mailing list
|