From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../classpath/gnu/xml/aelfred2/JAXPFactory.java | 230 + libjava/classpath/gnu/xml/aelfred2/SAXDriver.java | 1609 ++++++ libjava/classpath/gnu/xml/aelfred2/XmlParser.java | 5831 ++++++++++++++++++++ libjava/classpath/gnu/xml/aelfred2/XmlReader.java | 373 ++ libjava/classpath/gnu/xml/aelfred2/package.html | 506 ++ libjava/classpath/gnu/xml/dom/Consumer.java | 352 ++ .../gnu/xml/dom/DTDAttributeTypeInfo.java | 83 + .../classpath/gnu/xml/dom/DTDElementTypeInfo.java | 111 + libjava/classpath/gnu/xml/dom/DomAttr.java | 411 ++ libjava/classpath/gnu/xml/dom/DomCDATASection.java | 90 + .../classpath/gnu/xml/dom/DomCharacterData.java | 344 ++ libjava/classpath/gnu/xml/dom/DomComment.java | 80 + libjava/classpath/gnu/xml/dom/DomDOMException.java | 174 + libjava/classpath/gnu/xml/dom/DomDoctype.java | 455 ++ libjava/classpath/gnu/xml/dom/DomDocument.java | 1555 ++++++ .../classpath/gnu/xml/dom/DomDocumentBuilder.java | 227 + .../gnu/xml/dom/DomDocumentBuilderFactory.java | 181 + .../gnu/xml/dom/DomDocumentConfiguration.java | 260 + .../classpath/gnu/xml/dom/DomDocumentFragment.java | 75 + libjava/classpath/gnu/xml/dom/DomElement.java | 582 ++ libjava/classpath/gnu/xml/dom/DomEntity.java | 146 + .../classpath/gnu/xml/dom/DomEntityReference.java | 130 + libjava/classpath/gnu/xml/dom/DomEvent.java | 351 ++ libjava/classpath/gnu/xml/dom/DomExtern.java | 116 + libjava/classpath/gnu/xml/dom/DomImpl.java | 277 + libjava/classpath/gnu/xml/dom/DomIterator.java | 380 ++ .../gnu/xml/dom/DomNSResolverContext.java | 90 + libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java | 421 ++ libjava/classpath/gnu/xml/dom/DomNode.java | 2222 ++++++++ libjava/classpath/gnu/xml/dom/DomNodeIterator.java | 328 ++ libjava/classpath/gnu/xml/dom/DomNotation.java | 102 + libjava/classpath/gnu/xml/dom/DomNsNode.java | 226 + .../gnu/xml/dom/DomProcessingInstruction.java | 146 + libjava/classpath/gnu/xml/dom/DomText.java | 222 + .../classpath/gnu/xml/dom/DomXPathExpression.java | 147 + .../classpath/gnu/xml/dom/DomXPathNSResolver.java | 64 + libjava/classpath/gnu/xml/dom/DomXPathResult.java | 233 + .../classpath/gnu/xml/dom/ImplementationList.java | 70 + .../gnu/xml/dom/ImplementationSource.java | 167 + libjava/classpath/gnu/xml/dom/JAXPFactory.java | 308 ++ .../gnu/xml/dom/html2/DomHTMLAnchorElement.java | 188 + .../gnu/xml/dom/html2/DomHTMLAppletElement.java | 187 + .../gnu/xml/dom/html2/DomHTMLAreaElement.java | 138 + .../gnu/xml/dom/html2/DomHTMLBRElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLBaseElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLBaseFontElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLBodyElement.java | 118 + .../gnu/xml/dom/html2/DomHTMLButtonElement.java | 119 + .../gnu/xml/dom/html2/DomHTMLCollection.java | 225 + .../gnu/xml/dom/html2/DomHTMLDListElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDirectoryElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDivElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDocument.java | 426 ++ .../gnu/xml/dom/html2/DomHTMLElement.java | 286 + .../gnu/xml/dom/html2/DomHTMLEmbedElement.java | 129 + .../gnu/xml/dom/html2/DomHTMLFieldSetElement.java | 64 + .../gnu/xml/dom/html2/DomHTMLFontElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLFormElement.java | 149 + .../gnu/xml/dom/html2/DomHTMLFrameElement.java | 145 + .../gnu/xml/dom/html2/DomHTMLFrameSetElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLHRElement.java | 98 + .../gnu/xml/dom/html2/DomHTMLHeadElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLHeadingElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLHtmlElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLIFrameElement.java | 165 + .../gnu/xml/dom/html2/DomHTMLImageElement.java | 178 + .../classpath/gnu/xml/dom/html2/DomHTMLImpl.java | 66 + .../gnu/xml/dom/html2/DomHTMLInputElement.java | 265 + .../gnu/xml/dom/html2/DomHTMLIsIndexElement.java | 74 + .../gnu/xml/dom/html2/DomHTMLLIElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLLabelElement.java | 84 + .../gnu/xml/dom/html2/DomHTMLLegendElement.java | 84 + .../gnu/xml/dom/html2/DomHTMLLinkElement.java | 148 + .../gnu/xml/dom/html2/DomHTMLMapElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLMenuElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLMetaElement.java | 98 + .../gnu/xml/dom/html2/DomHTMLModElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLOListElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLObjectElement.java | 320 ++ .../gnu/xml/dom/html2/DomHTMLOptGroupElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLOptionElement.java | 130 + .../gnu/xml/dom/html2/DomHTMLParagraphElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLParamElement.java | 98 + .../classpath/gnu/xml/dom/html2/DomHTMLParser.java | 264 + .../gnu/xml/dom/html2/DomHTMLPreElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLQuoteElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLScriptElement.java | 128 + .../gnu/xml/dom/html2/DomHTMLSelectElement.java | 210 + .../gnu/xml/dom/html2/DomHTMLStyleElement.java | 88 + .../xml/dom/html2/DomHTMLTableCaptionElement.java | 69 + .../gnu/xml/dom/html2/DomHTMLTableCellElement.java | 204 + .../gnu/xml/dom/html2/DomHTMLTableColElement.java | 119 + .../gnu/xml/dom/html2/DomHTMLTableElement.java | 397 ++ .../gnu/xml/dom/html2/DomHTMLTableRowElement.java | 228 + .../xml/dom/html2/DomHTMLTableSectionElement.java | 162 + .../gnu/xml/dom/html2/DomHTMLTextAreaElement.java | 181 + .../gnu/xml/dom/html2/DomHTMLTitleElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLUListElement.java | 78 + .../classpath/gnu/xml/dom/ls/DomLSException.java | 57 + libjava/classpath/gnu/xml/dom/ls/DomLSInput.java | 159 + libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java | 98 + libjava/classpath/gnu/xml/dom/ls/DomLSParser.java | 567 ++ .../classpath/gnu/xml/dom/ls/DomLSSerializer.java | 353 ++ .../gnu/xml/dom/ls/FilteredSAXEventSink.java | 353 ++ .../gnu/xml/dom/ls/ReaderInputStream.java | 236 + libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java | 603 ++ .../gnu/xml/dom/ls/WriterOutputStream.java | 97 + libjava/classpath/gnu/xml/dom/package.html | 273 + .../classpath/gnu/xml/libxmlj/dom/GnomeAttr.java | 117 + .../gnu/xml/libxmlj/dom/GnomeCDATASection.java | 57 + .../gnu/xml/libxmlj/dom/GnomeCharacterData.java | 119 + .../gnu/xml/libxmlj/dom/GnomeComment.java | 57 + .../gnu/xml/libxmlj/dom/GnomeDOMException.java | 98 + .../gnu/xml/libxmlj/dom/GnomeDOMStringList.java | 84 + .../gnu/xml/libxmlj/dom/GnomeDocument.java | 562 ++ .../gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java | 326 ++ .../libxmlj/dom/GnomeDocumentBuilderFactory.java | 118 + .../gnu/xml/libxmlj/dom/GnomeDocumentFragment.java | 57 + .../gnu/xml/libxmlj/dom/GnomeDocumentType.java | 98 + .../gnu/xml/libxmlj/dom/GnomeElement.java | 184 + .../classpath/gnu/xml/libxmlj/dom/GnomeEntity.java | 104 + .../gnu/xml/libxmlj/dom/GnomeEntityReference.java | 57 + .../gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java | 92 + .../classpath/gnu/xml/libxmlj/dom/GnomeNode.java | 501 ++ .../gnu/xml/libxmlj/dom/GnomeNodeList.java | 66 + .../gnu/xml/libxmlj/dom/GnomeNotation.java | 80 + .../libxmlj/dom/GnomeProcessingInstruction.java | 79 + .../classpath/gnu/xml/libxmlj/dom/GnomeText.java | 132 + .../gnu/xml/libxmlj/dom/GnomeTypeInfo.java | 65 + .../gnu/xml/libxmlj/dom/GnomeXPathExpression.java | 86 + .../gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java | 64 + .../gnu/xml/libxmlj/dom/GnomeXPathNodeList.java | 73 + .../gnu/xml/libxmlj/dom/GnomeXPathResult.java | 134 + .../gnu/xml/libxmlj/sax/GnomeLocator.java | 99 + .../gnu/xml/libxmlj/sax/GnomeSAXParser.java | 105 + .../gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java | 92 + .../gnu/xml/libxmlj/sax/GnomeXMLReader.java | 1065 ++++ .../classpath/gnu/xml/libxmlj/sax/Namespaces.java | 122 + .../gnu/xml/libxmlj/sax/StringArrayAttributes.java | 170 + libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java | 92 + .../transform/ErrorListenerErrorHandler.java | 111 + .../xml/libxmlj/transform/GnomeTransformer.java | 572 ++ .../libxmlj/transform/GnomeTransformerFactory.java | 349 ++ .../transform/URIResolverEntityResolver.java | 87 + .../gnu/xml/libxmlj/transform/package.html | 14 + .../gnu/xml/libxmlj/util/EmptyNodeList.java | 62 + .../gnu/xml/libxmlj/util/NamedInputStream.java | 99 + .../xml/libxmlj/util/StandaloneDocumentType.java | 294 + .../gnu/xml/libxmlj/util/StandaloneLocator.java | 89 + libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java | 280 + libjava/classpath/gnu/xml/pipeline/CallFilter.java | 257 + .../classpath/gnu/xml/pipeline/DomConsumer.java | 967 ++++ .../classpath/gnu/xml/pipeline/EventConsumer.java | 95 + .../classpath/gnu/xml/pipeline/EventFilter.java | 796 +++ libjava/classpath/gnu/xml/pipeline/LinkFilter.java | 242 + libjava/classpath/gnu/xml/pipeline/NSFilter.java | 341 ++ .../gnu/xml/pipeline/PipelineFactory.java | 723 +++ .../classpath/gnu/xml/pipeline/TeeConsumer.java | 417 ++ .../classpath/gnu/xml/pipeline/TextConsumer.java | 117 + .../gnu/xml/pipeline/ValidationConsumer.java | 1928 +++++++ .../gnu/xml/pipeline/WellFormednessFilter.java | 363 ++ .../classpath/gnu/xml/pipeline/XIncludeFilter.java | 579 ++ libjava/classpath/gnu/xml/pipeline/XsltFilter.java | 130 + libjava/classpath/gnu/xml/pipeline/package.html | 255 + .../classpath/gnu/xml/stream/AttributeImpl.java | 123 + .../classpath/gnu/xml/stream/BufferedReader.java | 198 + libjava/classpath/gnu/xml/stream/CRLFReader.java | 180 + .../classpath/gnu/xml/stream/CharactersImpl.java | 119 + libjava/classpath/gnu/xml/stream/CommentImpl.java | 91 + libjava/classpath/gnu/xml/stream/DTDImpl.java | 114 + .../classpath/gnu/xml/stream/EndDocumentImpl.java | 70 + .../classpath/gnu/xml/stream/EndElementImpl.java | 107 + .../gnu/xml/stream/EntityDeclarationImpl.java | 163 + .../gnu/xml/stream/EntityReferenceImpl.java | 101 + .../gnu/xml/stream/FilteredEventReader.java | 114 + .../gnu/xml/stream/FilteredStreamReader.java | 90 + .../classpath/gnu/xml/stream/NamespaceImpl.java | 137 + .../gnu/xml/stream/NotationDeclarationImpl.java | 125 + .../gnu/xml/stream/ProcessingInstructionImpl.java | 104 + libjava/classpath/gnu/xml/stream/SAXParser.java | 1041 ++++ .../classpath/gnu/xml/stream/SAXParserFactory.java | 104 + .../gnu/xml/stream/StartDocumentImpl.java | 143 + .../classpath/gnu/xml/stream/StartElementImpl.java | 152 + .../classpath/gnu/xml/stream/UnicodeReader.java | 205 + .../classpath/gnu/xml/stream/XIncludeFilter.java | 931 ++++ .../gnu/xml/stream/XMLEventAllocatorImpl.java | 204 + .../gnu/xml/stream/XMLEventFactoryImpl.java | 269 + libjava/classpath/gnu/xml/stream/XMLEventImpl.java | 198 + .../gnu/xml/stream/XMLEventReaderImpl.java | 157 + .../gnu/xml/stream/XMLEventWriterImpl.java | 190 + .../gnu/xml/stream/XMLInputFactoryImpl.java | 397 ++ .../gnu/xml/stream/XMLOutputFactoryImpl.java | 187 + libjava/classpath/gnu/xml/stream/XMLParser.java | 5434 ++++++++++++++++++ .../gnu/xml/stream/XMLStreamWriterImpl.java | 1016 ++++ .../gnu/xml/transform/AbstractNumberNode.java | 330 ++ .../gnu/xml/transform/ApplyImportsNode.java | 82 + .../gnu/xml/transform/ApplyTemplatesNode.java | 219 + .../classpath/gnu/xml/transform/AttributeNode.java | 244 + .../classpath/gnu/xml/transform/AttributeSet.java | 66 + libjava/classpath/gnu/xml/transform/Bindings.java | 346 ++ .../gnu/xml/transform/CallTemplateNode.java | 156 + .../classpath/gnu/xml/transform/ChooseNode.java | 88 + .../classpath/gnu/xml/transform/CommentNode.java | 103 + libjava/classpath/gnu/xml/transform/CopyNode.java | 168 + .../classpath/gnu/xml/transform/CopyOfNode.java | 174 + .../gnu/xml/transform/CurrentFunction.java | 103 + .../gnu/xml/transform/DOMSourceLocator.java | 84 + .../gnu/xml/transform/DocumentFunction.java | 244 + .../xml/transform/ElementAvailableFunction.java | 181 + .../classpath/gnu/xml/transform/ElementNode.java | 261 + .../xml/transform/ErrorListenerErrorHandler.java | 101 + .../classpath/gnu/xml/transform/ForEachNode.java | 159 + .../gnu/xml/transform/FormatNumberFunction.java | 145 + .../xml/transform/FunctionAvailableFunction.java | 192 + .../gnu/xml/transform/GenerateIdFunction.java | 139 + libjava/classpath/gnu/xml/transform/IfNode.java | 112 + libjava/classpath/gnu/xml/transform/Key.java | 70 + .../classpath/gnu/xml/transform/KeyFunction.java | 227 + .../classpath/gnu/xml/transform/LiteralNode.java | 202 + .../classpath/gnu/xml/transform/MessageNode.java | 110 + .../gnu/xml/transform/NamespaceProxy.java | 77 + .../gnu/xml/transform/NodeNumberNode.java | 269 + .../classpath/gnu/xml/transform/NumberNode.java | 88 + .../classpath/gnu/xml/transform/OtherwiseNode.java | 83 + .../classpath/gnu/xml/transform/ParameterNode.java | 172 + .../xml/transform/ProcessingInstructionNode.java | 118 + .../classpath/gnu/xml/transform/SAXSerializer.java | 305 + .../gnu/xml/transform/SAXTemplatesHandler.java | 97 + .../gnu/xml/transform/SAXTransformerHandler.java | 111 + libjava/classpath/gnu/xml/transform/SortKey.java | 239 + .../gnu/xml/transform/StreamSerializer.java | 854 +++ .../gnu/xml/transform/StrippingInstruction.java | 73 + .../classpath/gnu/xml/transform/Stylesheet.java | 1772 ++++++ .../gnu/xml/transform/SystemPropertyFunction.java | 140 + libjava/classpath/gnu/xml/transform/Template.java | 263 + .../classpath/gnu/xml/transform/TemplateNode.java | 130 + .../classpath/gnu/xml/transform/TemplatesImpl.java | 95 + libjava/classpath/gnu/xml/transform/TextNode.java | 121 + .../gnu/xml/transform/TransformerFactoryImpl.java | 438 ++ .../gnu/xml/transform/TransformerImpl.java | 805 +++ .../xml/transform/TransformerOutputProperties.java | 186 + .../xml/transform/URIResolverEntityResolver.java | 83 + .../xml/transform/UnparsedEntityUriFunction.java | 132 + .../classpath/gnu/xml/transform/ValueOfNode.java | 141 + libjava/classpath/gnu/xml/transform/WhenNode.java | 115 + libjava/classpath/gnu/xml/transform/WithParam.java | 127 + .../classpath/gnu/xml/transform/XSLComparator.java | 118 + .../gnu/xml/transform/XSLURIResolver.java | 321 ++ libjava/classpath/gnu/xml/transform/package.html | 77 + libjava/classpath/gnu/xml/util/DoParse.java | 302 + libjava/classpath/gnu/xml/util/DomParser.java | 804 +++ libjava/classpath/gnu/xml/util/Resolver.java | 263 + .../gnu/xml/util/SAXNullTransformerFactory.java | 676 +++ libjava/classpath/gnu/xml/util/XCat.java | 1611 ++++++ libjava/classpath/gnu/xml/util/XHTMLWriter.java | 114 + libjava/classpath/gnu/xml/util/XMLWriter.java | 1931 +++++++ libjava/classpath/gnu/xml/util/package.html | 20 + .../gnu/xml/validation/datatype/Annotation.java | 60 + .../gnu/xml/validation/datatype/AnySimpleType.java | 58 + .../gnu/xml/validation/datatype/AnyType.java | 57 + .../gnu/xml/validation/datatype/AnyURIType.java | 93 + .../xml/validation/datatype/AtomicSimpleType.java | 77 + .../xml/validation/datatype/Base64BinaryType.java | 128 + .../gnu/xml/validation/datatype/BooleanType.java | 89 + .../gnu/xml/validation/datatype/ByteType.java | 132 + .../gnu/xml/validation/datatype/DateTimeType.java | 334 ++ .../gnu/xml/validation/datatype/DateType.java | 221 + .../gnu/xml/validation/datatype/DecimalType.java | 118 + .../gnu/xml/validation/datatype/DoubleType.java | 110 + .../gnu/xml/validation/datatype/DurationType.java | 238 + .../gnu/xml/validation/datatype/EntitiesType.java | 108 + .../gnu/xml/validation/datatype/EntityType.java | 87 + .../xml/validation/datatype/EnumerationFacet.java | 68 + .../gnu/xml/validation/datatype/Facet.java | 77 + .../gnu/xml/validation/datatype/FloatType.java | 110 + .../validation/datatype/FractionDigitsFacet.java | 71 + .../gnu/xml/validation/datatype/GDayType.java | 174 + .../gnu/xml/validation/datatype/GMonthDayType.java | 183 + .../gnu/xml/validation/datatype/GMonthType.java | 163 + .../xml/validation/datatype/GYearMonthType.java | 176 + .../gnu/xml/validation/datatype/GYearType.java | 151 + .../gnu/xml/validation/datatype/HexBinaryType.java | 89 + .../gnu/xml/validation/datatype/IDRefType.java | 86 + .../gnu/xml/validation/datatype/IDRefsType.java | 86 + .../gnu/xml/validation/datatype/IDType.java | 86 + .../gnu/xml/validation/datatype/IntType.java | 132 + .../gnu/xml/validation/datatype/IntegerType.java | 109 + .../gnu/xml/validation/datatype/LanguageType.java | 86 + .../gnu/xml/validation/datatype/LengthFacet.java | 71 + .../xml/validation/datatype/ListSimpleType.java | 82 + .../gnu/xml/validation/datatype/LongType.java | 132 + .../xml/validation/datatype/MaxExclusiveFacet.java | 110 + .../xml/validation/datatype/MaxInclusiveFacet.java | 111 + .../xml/validation/datatype/MaxLengthFacet.java | 71 + .../xml/validation/datatype/MinExclusiveFacet.java | 110 + .../xml/validation/datatype/MinInclusiveFacet.java | 111 + .../xml/validation/datatype/MinLengthFacet.java | 71 + .../gnu/xml/validation/datatype/NCNameType.java | 110 + .../gnu/xml/validation/datatype/NMTokenType.java | 101 + .../gnu/xml/validation/datatype/NMTokensType.java | 125 + .../gnu/xml/validation/datatype/NameType.java | 103 + .../validation/datatype/NegativeIntegerType.java | 110 + .../datatype/NonNegativeIntegerType.java | 120 + .../datatype/NonPositiveIntegerType.java | 120 + .../validation/datatype/NormalizedStringType.java | 87 + .../gnu/xml/validation/datatype/NotationType.java | 87 + .../gnu/xml/validation/datatype/PatternFacet.java | 70 + .../validation/datatype/PositiveIntegerType.java | 110 + .../gnu/xml/validation/datatype/QNameType.java | 121 + .../gnu/xml/validation/datatype/ShortType.java | 132 + .../gnu/xml/validation/datatype/SimpleType.java | 255 + .../gnu/xml/validation/datatype/StringType.java | 72 + .../gnu/xml/validation/datatype/TimeType.java | 302 + .../gnu/xml/validation/datatype/TokenType.java | 95 + .../xml/validation/datatype/TotalDigitsFacet.java | 71 + .../gnu/xml/validation/datatype/Type.java | 62 + .../gnu/xml/validation/datatype/TypeBuilder.java | 278 + .../gnu/xml/validation/datatype/TypeLibrary.java | 173 + .../validation/datatype/TypeLibraryFactory.java | 60 + .../xml/validation/datatype/UnionSimpleType.java | 82 + .../xml/validation/datatype/UnsignedByteType.java | 120 + .../xml/validation/datatype/UnsignedIntType.java | 120 + .../xml/validation/datatype/UnsignedLongType.java | 120 + .../xml/validation/datatype/UnsignedShortType.java | 121 + .../xml/validation/datatype/WhiteSpaceFacet.java | 74 + .../xml/validation/relaxng/AnyNameNameClass.java | 57 + .../xml/validation/relaxng/AttributePattern.java | 52 + .../xml/validation/relaxng/ChoiceNameClass.java | 58 + .../gnu/xml/validation/relaxng/ChoicePattern.java | 52 + .../gnu/xml/validation/relaxng/DataPattern.java | 59 + .../gnu/xml/validation/relaxng/Define.java | 51 + .../gnu/xml/validation/relaxng/ElementPattern.java | 52 + .../gnu/xml/validation/relaxng/EmptyPattern.java | 51 + .../xml/validation/relaxng/FullSyntaxBuilder.java | 1650 ++++++ .../gnu/xml/validation/relaxng/Grammar.java | 69 + .../xml/validation/relaxng/GrammarException.java | 56 + .../xml/validation/relaxng/GrammarValidator.java | 97 + .../gnu/xml/validation/relaxng/GroupPattern.java | 52 + .../xml/validation/relaxng/InterleavePattern.java | 52 + .../gnu/xml/validation/relaxng/ListPattern.java | 51 + .../xml/validation/relaxng/NSNameNameClass.java | 60 + .../gnu/xml/validation/relaxng/NameClass.java | 50 + .../gnu/xml/validation/relaxng/NameNameClass.java | 59 + .../xml/validation/relaxng/NotAllowedPattern.java | 51 + .../xml/validation/relaxng/OneOrMorePattern.java | 51 + .../gnu/xml/validation/relaxng/Param.java | 51 + .../gnu/xml/validation/relaxng/Pattern.java | 47 + .../validation/relaxng/RELAXNGSchemaFactory.java | 163 + .../gnu/xml/validation/relaxng/RefPattern.java | 51 + .../gnu/xml/validation/relaxng/TextPattern.java | 51 + .../gnu/xml/validation/relaxng/ValuePattern.java | 57 + .../gnu/xml/validation/xmlschema/AnyAttribute.java | 66 + .../validation/xmlschema/AttributeDeclaration.java | 98 + .../gnu/xml/validation/xmlschema/AttributeUse.java | 78 + .../gnu/xml/validation/xmlschema/ComplexType.java | 101 + .../validation/xmlschema/ElementDeclaration.java | 124 + .../gnu/xml/validation/xmlschema/Particle.java | 60 + .../validation/xmlschema/ValidationException.java | 57 + .../gnu/xml/validation/xmlschema/XMLSchema.java | 133 + .../xmlschema/XMLSchemaAttributeTypeInfo.java | 98 + .../xml/validation/xmlschema/XMLSchemaBuilder.java | 839 +++ .../xmlschema/XMLSchemaElementTypeInfo.java | 91 + .../xmlschema/XMLSchemaSchemaFactory.java | 171 + .../validation/xmlschema/XMLSchemaTypeInfo.java | 76 + .../xmlschema/XMLSchemaTypeInfoProvider.java | 81 + .../validation/xmlschema/XMLSchemaValidator.java | 97 + .../xmlschema/XMLSchemaValidatorHandler.java | 393 ++ libjava/classpath/gnu/xml/xpath/AndExpr.java | 87 + .../classpath/gnu/xml/xpath/ArithmeticExpr.java | 170 + .../classpath/gnu/xml/xpath/BooleanFunction.java | 95 + .../classpath/gnu/xml/xpath/CeilingFunction.java | 89 + .../classpath/gnu/xml/xpath/ConcatFunction.java | 115 + libjava/classpath/gnu/xml/xpath/Constant.java | 98 + .../classpath/gnu/xml/xpath/ContainsFunction.java | 93 + libjava/classpath/gnu/xml/xpath/CountFunction.java | 89 + .../gnu/xml/xpath/DocumentOrderComparator.java | 57 + libjava/classpath/gnu/xml/xpath/EqualityExpr.java | 274 + libjava/classpath/gnu/xml/xpath/Expr.java | 549 ++ libjava/classpath/gnu/xml/xpath/FalseFunction.java | 72 + libjava/classpath/gnu/xml/xpath/FloorFunction.java | 90 + libjava/classpath/gnu/xml/xpath/Function.java | 56 + libjava/classpath/gnu/xml/xpath/FunctionCall.java | 169 + libjava/classpath/gnu/xml/xpath/IdFunction.java | 103 + libjava/classpath/gnu/xml/xpath/LangFunction.java | 123 + libjava/classpath/gnu/xml/xpath/LastFunction.java | 73 + .../classpath/gnu/xml/xpath/LocalNameFunction.java | 98 + libjava/classpath/gnu/xml/xpath/NameFunction.java | 109 + libjava/classpath/gnu/xml/xpath/NameTest.java | 143 + libjava/classpath/gnu/xml/xpath/NamespaceTest.java | 120 + .../gnu/xml/xpath/NamespaceUriFunction.java | 98 + libjava/classpath/gnu/xml/xpath/NegativeExpr.java | 81 + libjava/classpath/gnu/xml/xpath/NodeTypeTest.java | 141 + .../gnu/xml/xpath/NormalizeSpaceFunction.java | 108 + libjava/classpath/gnu/xml/xpath/NotFunction.java | 88 + .../classpath/gnu/xml/xpath/NumberFunction.java | 103 + libjava/classpath/gnu/xml/xpath/OrExpr.java | 87 + .../classpath/gnu/xml/xpath/ParenthesizedExpr.java | 95 + libjava/classpath/gnu/xml/xpath/Path.java | 54 + libjava/classpath/gnu/xml/xpath/Pattern.java | 53 + .../classpath/gnu/xml/xpath/PositionFunction.java | 73 + libjava/classpath/gnu/xml/xpath/Predicate.java | 85 + .../classpath/gnu/xml/xpath/RelationalExpr.java | 107 + libjava/classpath/gnu/xml/xpath/Root.java | 91 + libjava/classpath/gnu/xml/xpath/RoundFunction.java | 97 + libjava/classpath/gnu/xml/xpath/Selector.java | 503 ++ .../gnu/xml/xpath/StartsWithFunction.java | 92 + libjava/classpath/gnu/xml/xpath/Steps.java | 260 + .../classpath/gnu/xml/xpath/StringFunction.java | 119 + .../gnu/xml/xpath/StringLengthFunction.java | 92 + .../gnu/xml/xpath/SubstringAfterFunction.java | 98 + .../gnu/xml/xpath/SubstringBeforeFunction.java | 97 + .../classpath/gnu/xml/xpath/SubstringFunction.java | 119 + libjava/classpath/gnu/xml/xpath/SumFunction.java | 104 + libjava/classpath/gnu/xml/xpath/Test.java | 58 + .../classpath/gnu/xml/xpath/TranslateFunction.java | 135 + libjava/classpath/gnu/xml/xpath/TrueFunction.java | 72 + libjava/classpath/gnu/xml/xpath/UnionExpr.java | 117 + .../classpath/gnu/xml/xpath/VariableReference.java | 102 + .../classpath/gnu/xml/xpath/XPathFactoryImpl.java | 90 + libjava/classpath/gnu/xml/xpath/XPathImpl.java | 164 + libjava/classpath/gnu/xml/xpath/XPathParser.java | 1475 +++++ libjava/classpath/gnu/xml/xpath/XPathParser.y | 794 +++ .../classpath/gnu/xml/xpath/XPathTokenizer.java | 594 ++ 423 files changed, 97550 insertions(+) create mode 100644 libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/SAXDriver.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/XmlParser.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/XmlReader.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/package.html create mode 100644 libjava/classpath/gnu/xml/dom/Consumer.java create mode 100644 libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/dom/DomAttr.java create mode 100644 libjava/classpath/gnu/xml/dom/DomCDATASection.java create mode 100644 libjava/classpath/gnu/xml/dom/DomCharacterData.java create mode 100644 libjava/classpath/gnu/xml/dom/DomComment.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDOMException.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDoctype.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocument.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentFragment.java create mode 100644 libjava/classpath/gnu/xml/dom/DomElement.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEntity.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEntityReference.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEvent.java create mode 100644 libjava/classpath/gnu/xml/dom/DomExtern.java create mode 100644 libjava/classpath/gnu/xml/dom/DomImpl.java create mode 100644 libjava/classpath/gnu/xml/dom/DomIterator.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNSResolverContext.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNode.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNodeIterator.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNotation.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNsNode.java create mode 100644 libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java create mode 100644 libjava/classpath/gnu/xml/dom/DomText.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathExpression.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathResult.java create mode 100644 libjava/classpath/gnu/xml/dom/ImplementationList.java create mode 100644 libjava/classpath/gnu/xml/dom/ImplementationSource.java create mode 100644 libjava/classpath/gnu/xml/dom/JAXPFactory.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSException.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSInput.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSParser.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java create mode 100644 libjava/classpath/gnu/xml/dom/package.html create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/package.html create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java create mode 100644 libjava/classpath/gnu/xml/pipeline/CallFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/DomConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/EventConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/EventFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/LinkFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/NSFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/PipelineFactory.java create mode 100644 libjava/classpath/gnu/xml/pipeline/TeeConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/TextConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/XsltFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/package.html create mode 100644 libjava/classpath/gnu/xml/stream/AttributeImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/BufferedReader.java create mode 100644 libjava/classpath/gnu/xml/stream/CRLFReader.java create mode 100644 libjava/classpath/gnu/xml/stream/CharactersImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/CommentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/DTDImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EndDocumentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EndElementImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/FilteredEventReader.java create mode 100644 libjava/classpath/gnu/xml/stream/FilteredStreamReader.java create mode 100644 libjava/classpath/gnu/xml/stream/NamespaceImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/SAXParser.java create mode 100644 libjava/classpath/gnu/xml/stream/SAXParserFactory.java create mode 100644 libjava/classpath/gnu/xml/stream/StartDocumentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/StartElementImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/UnicodeReader.java create mode 100644 libjava/classpath/gnu/xml/stream/XIncludeFilter.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLParser.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/AbstractNumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ApplyImportsNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java create mode 100644 libjava/classpath/gnu/xml/transform/AttributeNode.java create mode 100644 libjava/classpath/gnu/xml/transform/AttributeSet.java create mode 100644 libjava/classpath/gnu/xml/transform/Bindings.java create mode 100644 libjava/classpath/gnu/xml/transform/CallTemplateNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ChooseNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CommentNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CopyNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CopyOfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CurrentFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/DOMSourceLocator.java create mode 100644 libjava/classpath/gnu/xml/transform/DocumentFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ElementNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/ForEachNode.java create mode 100644 libjava/classpath/gnu/xml/transform/FormatNumberFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/GenerateIdFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/IfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/Key.java create mode 100644 libjava/classpath/gnu/xml/transform/KeyFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/LiteralNode.java create mode 100644 libjava/classpath/gnu/xml/transform/MessageNode.java create mode 100644 libjava/classpath/gnu/xml/transform/NamespaceProxy.java create mode 100644 libjava/classpath/gnu/xml/transform/NodeNumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/NumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/OtherwiseNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ParameterNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXSerializer.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/SortKey.java create mode 100644 libjava/classpath/gnu/xml/transform/StreamSerializer.java create mode 100644 libjava/classpath/gnu/xml/transform/StrippingInstruction.java create mode 100644 libjava/classpath/gnu/xml/transform/Stylesheet.java create mode 100644 libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/Template.java create mode 100644 libjava/classpath/gnu/xml/transform/TemplateNode.java create mode 100644 libjava/classpath/gnu/xml/transform/TemplatesImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TextNode.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java create mode 100644 libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java create mode 100644 libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ValueOfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/WhenNode.java create mode 100644 libjava/classpath/gnu/xml/transform/WithParam.java create mode 100644 libjava/classpath/gnu/xml/transform/XSLComparator.java create mode 100644 libjava/classpath/gnu/xml/transform/XSLURIResolver.java create mode 100644 libjava/classpath/gnu/xml/transform/package.html create mode 100644 libjava/classpath/gnu/xml/util/DoParse.java create mode 100644 libjava/classpath/gnu/xml/util/DomParser.java create mode 100644 libjava/classpath/gnu/xml/util/Resolver.java create mode 100644 libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java create mode 100644 libjava/classpath/gnu/xml/util/XCat.java create mode 100644 libjava/classpath/gnu/xml/util/XHTMLWriter.java create mode 100644 libjava/classpath/gnu/xml/util/XMLWriter.java create mode 100644 libjava/classpath/gnu/xml/util/package.html create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Annotation.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnyType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/BooleanType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ByteType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DateType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DecimalType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DoubleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DurationType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EntityType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Facet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/FloatType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GDayType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GMonthType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GYearType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDRefType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IntType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LanguageType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LongType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NCNameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NotationType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/QNameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ShortType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/SimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/StringType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TimeType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TokenType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Type.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Define.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Grammar.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Param.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Pattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/Particle.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java create mode 100644 libjava/classpath/gnu/xml/xpath/AndExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/BooleanFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/CeilingFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/ConcatFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Constant.java create mode 100644 libjava/classpath/gnu/xml/xpath/ContainsFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/CountFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java create mode 100644 libjava/classpath/gnu/xml/xpath/EqualityExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Expr.java create mode 100644 libjava/classpath/gnu/xml/xpath/FalseFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/FloorFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Function.java create mode 100644 libjava/classpath/gnu/xml/xpath/FunctionCall.java create mode 100644 libjava/classpath/gnu/xml/xpath/IdFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LangFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LastFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LocalNameFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NameFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NameTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NamespaceTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NegativeExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/NodeTypeTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NotFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NumberFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/OrExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Path.java create mode 100644 libjava/classpath/gnu/xml/xpath/Pattern.java create mode 100644 libjava/classpath/gnu/xml/xpath/PositionFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Predicate.java create mode 100644 libjava/classpath/gnu/xml/xpath/RelationalExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Root.java create mode 100644 libjava/classpath/gnu/xml/xpath/RoundFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Selector.java create mode 100644 libjava/classpath/gnu/xml/xpath/StartsWithFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Steps.java create mode 100644 libjava/classpath/gnu/xml/xpath/StringFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/StringLengthFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SumFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Test.java create mode 100644 libjava/classpath/gnu/xml/xpath/TranslateFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/TrueFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/UnionExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/VariableReference.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathImpl.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathParser.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathParser.y create mode 100644 libjava/classpath/gnu/xml/xpath/XPathTokenizer.java (limited to 'libjava/classpath/gnu/xml') diff --git a/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java new file mode 100644 index 000000000..094442765 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java @@ -0,0 +1,230 @@ +/* JAXPFactory.java -- + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.aelfred2; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.xml.sax.Parser; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.XMLReaderAdapter; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + + +/** + * Configurable factory to create an Ælfred2 JAXP parser; required + * to bootstrap using JAXP. You should use SAX2 directly where possible, + * rather than through JAXP, since that gives you better control. + * This class would normally be configured as a platform default factory. + * + * @author David Brownell + */ +public final class JAXPFactory + extends SAXParserFactory +{ + + private Hashtable flags = new Hashtable(); + + /** + * Constructs a factory which normally returns a non-validating + * parser. + */ + public JAXPFactory() + { + } + + public SAXParser newSAXParser() + throws ParserConfigurationException, SAXException + { + JaxpParser jaxp = new JaxpParser(); + Enumeration e = flags.keys(); + XMLReader parser = jaxp.getXMLReader(); + + parser.setFeature(SAXDriver.FEATURE + "namespaces", + isNamespaceAware()); + parser.setFeature(SAXDriver.FEATURE + "validation", + isValidating()); + // that makes SAX2 feature flags trump JAXP + + while (e.hasMoreElements()) + { + String uri = (String) e.nextElement(); + Boolean value = (Boolean) flags.get(uri); + parser.setFeature(uri, value.booleanValue()); + } + + return jaxp; + } + + // yes, this "feature transfer" mechanism doesn't play well + + public void setFeature(String name, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException + { + try + { + // force "early" detection of errors where possible + // (flags can't necessarily be set before parsing) + new JaxpParser().getXMLReader().setFeature(name, value); + + flags.put(name, Boolean.valueOf(value)); + } + catch (SAXNotRecognizedException e) + { + throw new SAXNotRecognizedException(name); + } + catch (SAXNotSupportedException e) + { + throw new SAXNotSupportedException(name); + } + catch (Exception e) + { + throw new ParserConfigurationException(e.getClass().getName() + + ": " + + e.getMessage()); + } + } + + public boolean getFeature(String name) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException + { + Boolean value = (Boolean) flags.get(name); + + if (value != null) + { + return value.booleanValue(); + } + else + { + try + { + return new JaxpParser().getXMLReader().getFeature(name); + } + catch (SAXNotRecognizedException e) + { + throw new SAXNotRecognizedException(name); + } + catch (SAXNotSupportedException e) + { + throw new SAXNotSupportedException(name); + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getClass().getName() + + ": " + + e.getMessage()); + } + } + } + + private static class JaxpParser + extends SAXParser + { + + private XmlReader ae2 = new XmlReader(); + private XMLReaderAdapter parser = null; + + JaxpParser() + { + } + + public void setProperty(String id, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + ae2.setProperty(id, value); + } + + public Object getProperty(String id) + throws SAXNotRecognizedException, SAXNotSupportedException + { + return ae2.getProperty(id); + } + + public Parser getParser() + throws SAXException + { + if (parser == null) + { + parser = new XMLReaderAdapter(ae2); + } + return parser; + } + + public XMLReader getXMLReader () + throws SAXException + { + return ae2; + } + + public boolean isNamespaceAware() + { + try + { + return ae2.getFeature(SAXDriver.FEATURE + "namespaces"); + } + catch (Exception e) + { + throw new Error(); + } + } + + public boolean isValidating() + { + try + { + return ae2.getFeature(SAXDriver.FEATURE + "validation"); + } + catch (Exception e) + { + throw new Error(); + } + } + + // TODO isXIncludeAware() + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java new file mode 100644 index 000000000..6ce14707b --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java @@ -0,0 +1,1609 @@ +/* SAXDriver.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +Portions derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program 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. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.aelfred2; + +import java.io.*; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; +import java.util.Stack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.NamespaceSupport; + + +/** + * An enhanced SAX2 version of Microstar's Ælfred XML parser. + * The enhancements primarily relate to significant improvements in + * conformance to the XML specification, and SAX2 support. Performance + * has been improved. See the package level documentation for more + * information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameNotes
Features ... URL prefix is + * http://xml.org/sax/features/
(URL)/external-general-entitiesValue defaults to true
(URL)/external-parameter-entitiesValue defaults to true
(URL)/is-standalone(PRELIMINARY) Returns true iff the document's parsing + * has started (some non-error event after startDocument() + * was reported) and the document's standalone flag is set.
(URL)/namespace-prefixesValue defaults to false (but XML 1.0 names are + * always reported)
(URL)/lexical-handler/parameter-entitiesValue is fixed at true
(URL)/namespacesValue defaults to true
(URL)/resolve-dtd-uris(PRELIMINARY) Value defaults to true
(URL)/string-interningValue is fixed at true
(URL)/use-attributes2(PRELIMINARY) Value is fixed at true
(URL)/use-entity-resolver2(PRELIMINARY) Value defaults to true
(URL)/validationValue is fixed at false
Handler Properties ... URL prefix is + * http://xml.org/sax/properties/
(URL)/declaration-handlerA declaration handler may be provided.
(URL)/lexical-handlerA lexical handler may be provided.
+ * + *

This parser currently implements the SAX1 Parser API, but + * it may not continue to do so in the future. + * + * @author Written by David Megginson (version 1.2a from Microstar) + * @author Updated by David Brownell <dbrownell@users.sourceforge.net> + * @see org.xml.sax.Parser + */ +final public class SAXDriver + implements Locator, Attributes2, XMLReader, Parser, AttributeList +{ + + private final DefaultHandler2 base = new DefaultHandler2(); + private XmlParser parser; + + private EntityResolver entityResolver = base; + private EntityResolver2 resolver2 = null; + private ContentHandler contentHandler = base; + private DTDHandler dtdHandler = base; + private ErrorHandler errorHandler = base; + private DeclHandler declHandler = base; + private LexicalHandler lexicalHandler = base; + + private String elementName; + private Stack entityStack; + + // one vector (of object/struct): faster, smaller + private List attributesList; + + private boolean namespaces = true; + private boolean xmlNames = false; + private boolean extGE = true; + private boolean extPE = true; + private boolean resolveAll = true; + private boolean useResolver2 = true; + + // package private to allow (read-only) access in XmlParser + boolean stringInterning = true; + + private int attributeCount; + private boolean attributes; + private String[] nsTemp; + private NamespaceSupport prefixStack; + + // + // Constructor. + // + + /** + * Constructs a SAX Parser. + */ + public SAXDriver() + { + reset(); + } + + private void reset() + { + elementName = null; + entityStack = new Stack(); + attributesList = Collections.synchronizedList(new ArrayList()); + attributeCount = 0; + attributes = false; + nsTemp = new String[3]; + prefixStack = null; + } + + + // + // Implementation of org.xml.sax.Parser. + // + + /** + * SAX1: Sets the locale used for diagnostics; currently, + * only locales using the English language are supported. + * @param locale The locale for which diagnostics will be generated + */ + public void setLocale(Locale locale) + throws SAXException + { + if ("en".equals(locale.getLanguage())) + { + return; + } + throw new SAXException ("AElfred2 only supports English locales."); + } + + /** + * SAX2: Returns the object used when resolving external + * entities during parsing (both general and parameter entities). + */ + public EntityResolver getEntityResolver() + { + return (entityResolver == base) ? null : entityResolver; + } + + /** + * SAX1, SAX2: Set the entity resolver for this parser. + * @param handler The object to receive entity events. + */ + public void setEntityResolver(EntityResolver resolver) + { + if (resolver instanceof EntityResolver2) + { + resolver2 = (EntityResolver2) resolver; + } + else + { + resolver2 = null; + } + if (resolver == null) + { + resolver = base; + } + entityResolver = resolver; + } + + /** + * SAX2: Returns the object used to process declarations related + * to notations and unparsed entities. + */ + public DTDHandler getDTDHandler() + { + return (dtdHandler == base) ? null : dtdHandler; + } + + /** + * SAX1, SAX2: Set the DTD handler for this parser. + * @param handler The object to receive DTD events. + */ + public void setDTDHandler(DTDHandler handler) + { + if (handler == null) + { + handler = base; + } + this.dtdHandler = handler; + } + + + /** + * SAX1: Set the document handler for this parser. If a + * content handler was set, this document handler will supplant it. + * The parser is set to report all XML 1.0 names rather than to + * filter out "xmlns" attributes (the "namespace-prefixes" feature + * is set to true). + * + * @deprecated SAX2 programs should use the XMLReader interface + * and a ContentHandler. + * + * @param handler The object to receive document events. + */ + public void setDocumentHandler(DocumentHandler handler) + { + contentHandler = new Adapter(handler); + xmlNames = true; + } + + /** + * SAX2: Returns the object used to report the logical + * content of an XML document. + */ + public ContentHandler getContentHandler() + { + return (contentHandler == base) ? null : contentHandler; + } + + /** + * SAX2: Assigns the object used to report the logical + * content of an XML document. If a document handler was set, + * this content handler will supplant it (but XML 1.0 style name + * reporting may remain enabled). + */ + public void setContentHandler(ContentHandler handler) + { + if (handler == null) + { + handler = base; + } + contentHandler = handler; + } + + /** + * SAX1, SAX2: Set the error handler for this parser. + * @param handler The object to receive error events. + */ + public void setErrorHandler(ErrorHandler handler) + { + if (handler == null) + { + handler = base; + } + this.errorHandler = handler; + } + + /** + * SAX2: Returns the object used to receive callbacks for XML + * errors of all levels (fatal, nonfatal, warning); this is never null; + */ + public ErrorHandler getErrorHandler() + { + return (errorHandler == base) ? null : errorHandler; + } + + /** + * SAX1, SAX2: Auxiliary API to parse an XML document, used mostly + * when no URI is available. + * If you want anything useful to happen, you should set + * at least one type of handler. + * @param source The XML input source. Don't set 'encoding' unless + * you know for a fact that it's correct. + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + * @exception SAXException The handlers may throw any SAXException, + * and the parser normally throws SAXParseException objects. + * @exception IOException IOExceptions are normally through through + * the parser if there are problems reading the source document. + */ + public void parse(InputSource source) + throws SAXException, IOException + { + synchronized (base) + { + parser = new XmlParser(); + if (namespaces) + { + prefixStack = new NamespaceSupport(); + } + else if (!xmlNames) + { + throw new IllegalStateException(); + } + parser.setHandler(this); + + try + { + Reader r = source.getCharacterStream(); + InputStream in = source.getByteStream(); + + parser.doParse(source.getSystemId(), + source.getPublicId(), + r, + in, + source.getEncoding()); + } + catch (SAXException e) + { + throw e; + } + catch (IOException e) + { + throw e; + } + catch (RuntimeException e) + { + throw e; + } + catch (Exception e) + { + throw new SAXParseException(e.getMessage(), this, e); + } + finally + { + contentHandler.endDocument(); + reset(); + } + } + } + + /** + * SAX1, SAX2: Preferred API to parse an XML document, using a + * system identifier (URI). + */ + public void parse(String systemId) + throws SAXException, IOException + { + parse(new InputSource(systemId)); + } + + // + // Implementation of SAX2 "XMLReader" interface + // + static final String FEATURE = "http://xml.org/sax/features/"; + static final String PROPERTY = "http://xml.org/sax/properties/"; + + /** + * SAX2: Tells the value of the specified feature flag. + * + * @exception SAXNotRecognizedException thrown if the feature flag + * is neither built in, nor yet assigned. + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if ((FEATURE + "validation").equals(featureId)) + { + return false; + } + + // external entities (both types) are optionally included + if ((FEATURE + "external-general-entities").equals(featureId)) + { + return extGE; + } + if ((FEATURE + "external-parameter-entities").equals(featureId)) + { + return extPE; + } + + // element/attribute names are as written in document; no mangling + if ((FEATURE + "namespace-prefixes").equals(featureId)) + { + return xmlNames; + } + + // report element/attribute namespaces? + if ((FEATURE + "namespaces").equals(featureId)) + { + return namespaces; + } + + // all PEs and GEs are reported + if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId)) + { + return true; + } + + // default is true + if ((FEATURE + "string-interning").equals(featureId)) + { + return stringInterning; + } + + // EXTENSIONS 1.1 + + // always returns isSpecified info + if ((FEATURE + "use-attributes2").equals(featureId)) + { + return true; + } + + // meaningful between startDocument/endDocument + if ((FEATURE + "is-standalone").equals(featureId)) + { + if (parser == null) + { + throw new SAXNotSupportedException(featureId); + } + return parser.isStandalone(); + } + + // optionally don't absolutize URIs in declarations + if ((FEATURE + "resolve-dtd-uris").equals(featureId)) + { + return resolveAll; + } + + // optionally use resolver2 interface methods, if possible + if ((FEATURE + "use-entity-resolver2").equals(featureId)) + { + return useResolver2; + } + + throw new SAXNotRecognizedException(featureId); + } + + // package private + DeclHandler getDeclHandler() + { + return declHandler; + } + + // package private + boolean resolveURIs() + { + return resolveAll; + } + + /** + * SAX2: Returns the specified property. + * + * @exception SAXNotRecognizedException thrown if the property value + * is neither built in, nor yet stored. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException + { + if ((PROPERTY + "declaration-handler").equals(propertyId)) + { + return (declHandler == base) ? null : declHandler; + } + + if ((PROPERTY + "lexical-handler").equals(propertyId)) + { + return (lexicalHandler == base) ? null : lexicalHandler; + } + + // unknown properties + throw new SAXNotRecognizedException(propertyId); + } + + /** + * SAX2: Sets the state of feature flags in this parser. Some + * built-in feature flags are mutable. + */ + public void setFeature(String featureId, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + boolean state; + + // Features with a defined value, we just change it if we can. + state = getFeature (featureId); + + if (state == value) + { + return; + } + if (parser != null) + { + throw new SAXNotSupportedException("not while parsing"); + } + + if ((FEATURE + "namespace-prefixes").equals(featureId)) + { + // in this implementation, this only affects xmlns reporting + xmlNames = value; + // forcibly prevent illegal parser state + if (!xmlNames) + { + namespaces = true; + } + return; + } + + if ((FEATURE + "namespaces").equals(featureId)) + { + namespaces = value; + // forcibly prevent illegal parser state + if (!namespaces) + { + xmlNames = true; + } + return; + } + + if ((FEATURE + "external-general-entities").equals(featureId)) + { + extGE = value; + return; + } + if ((FEATURE + "external-parameter-entities").equals(featureId)) + { + extPE = value; + return; + } + if ((FEATURE + "resolve-dtd-uris").equals(featureId)) + { + resolveAll = value; + return; + } + + if ((FEATURE + "use-entity-resolver2").equals(featureId)) + { + useResolver2 = value; + return; + } + + throw new SAXNotRecognizedException(featureId); + } + + /** + * SAX2: Assigns the specified property. Like SAX1 handlers, + * these may be changed at any time. + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + // see if the property is recognized + getProperty(propertyId); + + // Properties with a defined value, we just change it if we can. + + if ((PROPERTY + "declaration-handler").equals(propertyId)) + { + if (value == null) + { + declHandler = base; + } + else if (!(value instanceof DeclHandler)) + { + throw new SAXNotSupportedException(propertyId); + } + else + { + declHandler = (DeclHandler) value; + } + return ; + } + + if ((PROPERTY + "lexical-handler").equals(propertyId)) + { + if (value == null) + { + lexicalHandler = base; + } + else if (!(value instanceof LexicalHandler)) + { + throw new SAXNotSupportedException(propertyId); + } + else + { + lexicalHandler = (LexicalHandler) value; + } + return; + } + + throw new SAXNotSupportedException(propertyId); + } + + // + // This is where the driver receives XmlParser callbacks and translates + // them into SAX callbacks. Some more callbacks have been added for + // SAX2 support. + // + + void startDocument() + throws SAXException + { + contentHandler.setDocumentLocator(this); + contentHandler.startDocument(); + attributesList.clear(); + } + + void skippedEntity(String name) + throws SAXException + { + contentHandler.skippedEntity(name); + } + + InputSource getExternalSubset(String name, String baseURI) + throws SAXException, IOException + { + if (resolver2 == null || !useResolver2 || !extPE) + { + return null; + } + return resolver2.getExternalSubset(name, baseURI); + } + + InputSource resolveEntity(boolean isPE, String name, + InputSource in, String baseURI) + throws SAXException, IOException + { + InputSource source; + + // external entities might be skipped + if (isPE && !extPE) + { + return null; + } + if (!isPE && !extGE) + { + return null; + } + + // ... or not + lexicalHandler.startEntity(name); + if (resolver2 != null && useResolver2) + { + source = resolver2.resolveEntity(name, in.getPublicId(), + baseURI, in.getSystemId()); + if (source == null) + { + in.setSystemId(absolutize(baseURI, + in.getSystemId(), false)); + source = in; + } + } + else + { + in.setSystemId(absolutize(baseURI, + in.getSystemId(), + entityResolver != base)); + source = entityResolver.resolveEntity(in.getPublicId(), + in.getSystemId()); + if (source == null) + { + source = in; + } + } + startExternalEntity(name, source.getSystemId(), true); + return source; + } + + // absolutize a system ID relative to the specified base URI + // (temporarily) package-visible for external entity decls + String absolutize(String baseURI, String systemId, boolean nice) + throws MalformedURLException, SAXException + { + // FIXME normalize system IDs -- when? + // - Convert to UTF-8 + // - Map reserved and non-ASCII characters to %HH + + try + { + if (baseURI == null) + { + if (XmlParser.uriWarnings) + { + warn ("No base URI; hope this SYSTEM id is absolute: " + + systemId); + } + return new URL(systemId).toString(); + } + else + { + return new URL(new URL(baseURI), systemId).toString(); + } + } + catch (MalformedURLException e) + { + // Let unknown URI schemes pass through unless we need + // the JVM to map them to i/o streams for us... + if (!nice) + { + throw e; + } + + // sometimes sysids for notations or unparsed entities + // aren't really URIs... + warn("Can't absolutize SYSTEM id: " + e.getMessage()); + return systemId; + } + } + + void startExternalEntity(String name, String systemId, boolean stackOnly) + throws SAXException + { + // The following warning was deleted because the application has the + // option of not setting systemId. Sun's JAXP or Xerces seems to + // ignore this case. + /* + if (systemId == null) + warn ("URI was not reported to parser for entity " + name); + */ + if (!stackOnly) // spliced [dtd] needs startEntity + { + lexicalHandler.startEntity(name); + } + entityStack.push(systemId); + } + + void endExternalEntity(String name) + throws SAXException + { + if (!"[document]".equals(name)) + { + lexicalHandler.endEntity(name); + } + entityStack.pop(); + } + + void startInternalEntity(String name) + throws SAXException + { + lexicalHandler.startEntity(name); + } + + void endInternalEntity(String name) + throws SAXException + { + lexicalHandler.endEntity(name); + } + + void doctypeDecl(String name, String publicId, String systemId) + throws SAXException + { + lexicalHandler.startDTD(name, publicId, systemId); + + // ... the "name" is a declaration and should be given + // to the DeclHandler (but sax2 doesn't). + + // the IDs for the external subset are lexical details, + // as are the contents of the internal subset; but sax2 + // doesn't provide the internal subset "pre-parse" + } + + void notationDecl(String name, String publicId, String systemId, + String baseUri) + throws SAXException + { + try + { + dtdHandler.notationDecl(name, publicId, + (resolveAll && systemId != null) + ? absolutize(baseUri, systemId, true) + : systemId); + } + catch (IOException e) + { + // "can't happen" + throw new SAXParseException(e.getMessage(), this, e); + } + } + + void unparsedEntityDecl(String name, String publicId, String systemId, + String baseUri, String notation) + throws SAXException + { + try + { + dtdHandler.unparsedEntityDecl(name, publicId, + resolveAll + ? absolutize(baseUri, systemId, true) + : systemId, + notation); + } + catch (IOException e) + { + // "can't happen" + throw new SAXParseException(e.getMessage(), this, e); + } + } + + void endDoctype() + throws SAXException + { + lexicalHandler.endDTD(); + } + + private void declarePrefix(String prefix, String uri) + throws SAXException + { + int index = uri.indexOf(':'); + + // many versions of nwalsh docbook stylesheets + // have bogus URLs; so this can't be an error... + if (index < 1 && uri.length() != 0) + { + warn("relative URI for namespace: " + uri); + } + + // FIXME: char [0] must be ascii alpha; chars [1..index] + // must be ascii alphanumeric or in "+-." [RFC 2396] + + //Namespace Constraints + //name for xml prefix must be http://www.w3.org/XML/1998/namespace + boolean prefixEquality = prefix.equals("xml"); + boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace"); + if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality)) + { + fatal("xml is by definition bound to the namespace name " + + "http://www.w3.org/XML/1998/namespace"); + } + + //xmlns prefix declaration is illegal but xml prefix declaration is llegal... + if (prefixEquality && uriEquality) + { + return; + } + + //name for xmlns prefix must be http://www.w3.org/2000/xmlns/ + prefixEquality = prefix.equals("xmlns"); + uriEquality = uri.equals("http://www.w3.org/2000/xmlns/"); + if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality)) + { + fatal("http://www.w3.org/2000/xmlns/ is by definition bound" + + " to prefix xmlns"); + } + + //even if the uri is http://www.w3.org/2000/xmlns/ + // it is illegal to declare it + if (prefixEquality && uriEquality) + { + fatal ("declaring the xmlns prefix is illegal"); + } + + uri = uri.intern(); + prefixStack.declarePrefix(prefix, uri); + contentHandler.startPrefixMapping(prefix, uri); + } + + void attribute(String qname, String value, boolean isSpecified) + throws SAXException + { + if (!attributes) + { + attributes = true; + if (namespaces) + { + prefixStack.pushContext(); + } + } + + // process namespace decls immediately; + // then maybe forget this as an attribute + if (namespaces) + { + int index; + + // default NS declaration? + if (stringInterning) + { + if ("xmlns" == qname) + { + declarePrefix("", value); + if (!xmlNames) + { + return; + } + } + // NS prefix declaration? + else if ((index = qname.indexOf(':')) == 5 + && qname.startsWith("xmlns")) + { + String prefix = qname.substring(6); + + if (prefix.equals("")) + { + fatal("missing prefix " + + "in namespace declaration attribute"); + } + if (value.length() == 0) + { + verror("missing URI in namespace declaration attribute: " + + qname); + } + else + { + declarePrefix(prefix, value); + } + if (!xmlNames) + { + return; + } + } + } + else + { + if ("xmlns".equals(qname)) + { + declarePrefix("", value); + if (!xmlNames) + { + return; + } + } + // NS prefix declaration? + else if ((index = qname.indexOf(':')) == 5 + && qname.startsWith("xmlns")) + { + String prefix = qname.substring(6); + + if (value.length() == 0) + { + verror("missing URI in namespace decl attribute: " + + qname); + } + else + { + declarePrefix(prefix, value); + } + if (!xmlNames) + { + return; + } + } + } + } + // remember this attribute ... + attributeCount++; + + // attribute type comes from querying parser's DTD records + attributesList.add(new Attribute(qname, value, isSpecified)); + + } + + void startElement(String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + // + // NOTE: this implementation of namespace support adds something + // like six percent to parsing CPU time, in a large (~50 MB) + // document that doesn't use namespaces at all. (Measured by PC + // sampling, with a bug where endElement processing was omitted.) + // [Measurement referred to older implementation, older JVM ...] + // + // It ought to become notably faster in such cases. Most + // costs are the prefix stack calling Hashtable.get() (2%), + // String.hashCode() (1.5%) and about 1.3% each for pushing + // the context, and two chunks of name processing. + // + + if (!attributes) + { + if (namespaces) + { + prefixStack.pushContext(); + } + } + else if (namespaces) + { + + // now we can patch up namespace refs; we saw all the + // declarations, so now we'll do the Right Thing + Iterator itt = attributesList.iterator(); + while (itt.hasNext()) + { + Attribute attribute = (Attribute) itt.next(); + String qname = attribute.name; + int index; + + // default NS declaration? + if (stringInterning) + { + if ("xmlns" == qname) + { + continue; + } + } + else + { + if ("xmlns".equals(qname)) + { + continue; + } + } + //Illegal in the new Namespaces Draft + //should it be only in 1.1 docs?? + if (qname.equals (":")) + { + fatal("namespace names consisting of a single colon " + + "character are invalid"); + } + index = qname.indexOf(':'); + + // NS prefix declaration? + if (index == 5 && qname.startsWith("xmlns")) + { + continue; + } + + // it's not a NS decl; patch namespace info items + if (prefixStack.processName(qname, nsTemp, true) == null) + { + fatal("undeclared attribute prefix in: " + qname); + } + else + { + attribute.nameSpace = nsTemp[0]; + attribute.localName = nsTemp[1]; + } + } + } + + // save element name so attribute callbacks work + elementName = elname; + if (namespaces) + { + if (prefixStack.processName(elname, nsTemp, false) == null) + { + fatal("undeclared element prefix in: " + elname); + nsTemp[0] = nsTemp[1] = ""; + } + handler.startElement(nsTemp[0], nsTemp[1], elname, this); + } + else + { + handler.startElement("", "", elname, this); + } + // elementName = null; + + // elements with no attributes are pretty common! + if (attributes) + { + attributesList.clear(); + attributeCount = 0; + attributes = false; + } + } + + void endElement(String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + if (!namespaces) + { + handler.endElement("", "", elname); + return; + } + prefixStack.processName(elname, nsTemp, false); + handler.endElement(nsTemp[0], nsTemp[1], elname); + + Enumeration prefixes = prefixStack.getDeclaredPrefixes(); + + while (prefixes.hasMoreElements()) + { + handler.endPrefixMapping((String) prefixes.nextElement()); + } + prefixStack.popContext(); + } + + void startCDATA() + throws SAXException + { + lexicalHandler.startCDATA(); + } + + void charData(char[] ch, int start, int length) + throws SAXException + { + contentHandler.characters(ch, start, length); + } + + void endCDATA() + throws SAXException + { + lexicalHandler.endCDATA(); + } + + void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException + { + contentHandler.ignorableWhitespace(ch, start, length); + } + + void processingInstruction(String target, String data) + throws SAXException + { + contentHandler.processingInstruction(target, data); + } + + void comment(char[] ch, int start, int length) + throws SAXException + { + if (lexicalHandler != base) + { + lexicalHandler.comment(ch, start, length); + } + } + + void fatal(String message) + throws SAXException + { + SAXParseException fatal; + + fatal = new SAXParseException(message, this); + errorHandler.fatalError(fatal); + + // Even if the application can continue ... we can't! + throw fatal; + } + + // We can safely report a few validity errors that + // make layered SAX2 DTD validation more conformant + void verror(String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException(message, this); + errorHandler.error(err); + } + + void warn(String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException(message, this); + errorHandler.warning(err); + } + + // + // Implementation of org.xml.sax.Attributes. + // + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public int getLength() + { + return attributesList.size(); + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getURI(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + return ((Attribute) attributesList.get(index)).nameSpace; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getLocalName(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + Attribute attr = (Attribute) attributesList.get(index); + // FIXME attr.localName is sometimes null, why? + if (namespaces && attr.localName == null) + { + // XXX fix this here for now + int ci = attr.name.indexOf(':'); + attr.localName = (ci == -1) ? attr.name : + attr.name.substring(ci + 1); + } + return (attr.localName == null) ? "" : attr.localName; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getQName(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + Attribute attr = (Attribute) attributesList.get(index); + return (attr.name == null) ? "" : attr.name; + } + + /** + * SAX1 AttributeList method (don't invoke on parser); + */ + public String getName(int index) + { + return getQName(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getType(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + String type = parser.getAttributeType(elementName, getQName(index)); + if (type == null) + { + return "CDATA"; + } + // ... use DeclHandler.attributeDecl to see enumerations + if (type == "ENUMERATION") + { + return "NMTOKEN"; + } + return type; + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getValue(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + return ((Attribute) attributesList.get(index)).value; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public int getIndex(String uri, String local) + { + int length = getLength(); + + for (int i = 0; i < length; i++) + { + if (!getURI(i).equals(uri)) + { + continue; + } + if (getLocalName(i).equals(local)) + { + return i; + } + } + return -1; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public int getIndex(String xmlName) + { + int length = getLength(); + + for (int i = 0; i < length; i++) + { + if (getQName(i).equals(xmlName)) + { + return i; + } + } + return -1; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getType(String uri, String local) + { + int index = getIndex(uri, local); + + if (index < 0) + { + return null; + } + return getType(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getType(String xmlName) + { + int index = getIndex(xmlName); + + if (index < 0) + { + return null; + } + return getType(index); + } + + /** + * SAX Attributes method (don't invoke on parser); + */ + public String getValue(String uri, String local) + { + int index = getIndex(uri, local); + + if (index < 0) + { + return null; + } + return getValue(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getValue(String xmlName) + { + int index = getIndex(xmlName); + + if (index < 0) + { + return null; + } + return getValue(index); + } + + // + // Implementation of org.xml.sax.ext.Attributes2 + // + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.ArrayIndexOutOfBoundsException + * When the supplied index does not identify an attribute. + */ + public boolean isDeclared(int index) + { + if (index < 0 || index >= attributeCount) + { + throw new ArrayIndexOutOfBoundsException(); + } + String type = parser.getAttributeType(elementName, getQName(index)); + return (type != null); + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared(String qName) + { + int index = getIndex(qName); + if (index < 0) + { + throw new IllegalArgumentException(); + } + String type = parser.getAttributeType(elementName, qName); + return (type != null); + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared(String uri, String localName) + { + int index = getIndex(uri, localName); + return isDeclared(index); + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(int index) + { + return ((Attribute) attributesList.get(index)).specified; + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(String uri, String local) + { + int index = getIndex (uri, local); + return isSpecified(index); + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(String xmlName) + { + int index = getIndex (xmlName); + return isSpecified(index); + } + + // + // Implementation of org.xml.sax.Locator. + // + + /** + * SAX Locator method (don't invoke on parser); + */ + public String getPublicId() + { + return null; // FIXME track public IDs too + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public String getSystemId() + { + if (entityStack.empty()) + { + return null; + } + else + { + return (String) entityStack.peek(); + } + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public int getLineNumber() + { + return parser.getLineNumber(); + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public int getColumnNumber() + { + return parser.getColumnNumber(); + } + + // adapter between SAX2 content handler and SAX1 document handler callbacks + private static class Adapter + implements ContentHandler + { + + private DocumentHandler docHandler; + + Adapter(DocumentHandler dh) + { + docHandler = dh; + } + + public void setDocumentLocator(Locator l) + { + docHandler.setDocumentLocator(l); + } + + public void startDocument() + throws SAXException + { + docHandler.startDocument(); + } + + public void processingInstruction(String target, String data) + throws SAXException + { + docHandler.processingInstruction(target, data); + } + + public void startPrefixMapping(String prefix, String uri) + { + /* ignored */ + } + + public void startElement(String namespace, + String local, + String name, + Attributes attrs) + throws SAXException + { + docHandler.startElement(name, (AttributeList) attrs); + } + + public void characters(char[] buf, int offset, int len) + throws SAXException + { + docHandler.characters(buf, offset, len); + } + + public void ignorableWhitespace(char[] buf, int offset, int len) + throws SAXException + { + docHandler.ignorableWhitespace(buf, offset, len); + } + + public void skippedEntity(String name) + { + /* ignored */ + } + + public void endElement(String u, String l, String name) + throws SAXException + { + docHandler.endElement(name); + } + + public void endPrefixMapping(String prefix) + { + /* ignored */ + } + + public void endDocument() + throws SAXException + { + docHandler.endDocument(); + } + } + + private static class Attribute + { + + String name; + String value; + String nameSpace; + String localName; + boolean specified; + + Attribute(String name, String value, boolean specified) + { + this.name = name; + this.value = value; + this.nameSpace = ""; + this.specified = specified; + } + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlParser.java b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java new file mode 100644 index 000000000..813593d93 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java @@ -0,0 +1,5831 @@ +/* XmlParser.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +Partly derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program 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. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.aelfred2; + +import gnu.java.security.action.GetPropertyAction; + +import java.io.BufferedInputStream; +import java.io.CharConversionException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; + +import java.util.Iterator; +import java.util.HashMap; +import java.util.LinkedList; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +/** + * Parse XML documents and return parse events through call-backs. + * Use the SAXDriver class as your entry point, as all + * internal parser interfaces are subject to change. + * + * @author Written by David Megginson <dmeggins@microstar.com> + * (version 1.2a with bugfixes) + * @author Updated by David Brownell <dbrownell@users.sourceforge.net> + * @see SAXDriver + */ +final class XmlParser +{ + + // avoid slow per-character readCh() + private final static boolean USE_CHEATS = true; + + //////////////////////////////////////////////////////////////////////// + // Constants. + //////////////////////////////////////////////////////////////////////// + + // + // Constants for element content type. + // + + /** + * Constant: an element has not been declared. + * @see #getElementContentType + */ + public final static int CONTENT_UNDECLARED = 0; + + /** + * Constant: the element has a content model of ANY. + * @see #getElementContentType + */ + public final static int CONTENT_ANY = 1; + + /** + * Constant: the element has declared content of EMPTY. + * @see #getElementContentType + */ + public final static int CONTENT_EMPTY = 2; + + /** + * Constant: the element has mixed content. + * @see #getElementContentType + */ + public final static int CONTENT_MIXED = 3; + + /** + * Constant: the element has element content. + * @see #getElementContentType + */ + public final static int CONTENT_ELEMENTS = 4; + + + // + // Constants for the entity type. + // + + /** + * Constant: the entity has not been declared. + * @see #getEntityType + */ + public final static int ENTITY_UNDECLARED = 0; + + /** + * Constant: the entity is internal. + * @see #getEntityType + */ + public final static int ENTITY_INTERNAL = 1; + + /** + * Constant: the entity is external, non-parsable data. + * @see #getEntityType + */ + public final static int ENTITY_NDATA = 2; + + /** + * Constant: the entity is external XML data. + * @see #getEntityType + */ + public final static int ENTITY_TEXT = 3; + + // + // Attribute type constants are interned literal strings. + // + + // + // Constants for supported encodings. "external" is just a flag. + // + private final static int ENCODING_EXTERNAL = 0; + private final static int ENCODING_UTF_8 = 1; + private final static int ENCODING_ISO_8859_1 = 2; + private final static int ENCODING_UCS_2_12 = 3; + private final static int ENCODING_UCS_2_21 = 4; + private final static int ENCODING_UCS_4_1234 = 5; + private final static int ENCODING_UCS_4_4321 = 6; + private final static int ENCODING_UCS_4_2143 = 7; + private final static int ENCODING_UCS_4_3412 = 8; + private final static int ENCODING_ASCII = 9; + + // + // Constants for attribute default value. + // + + /** + * Constant: the attribute is not declared. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30; + + /** + * Constant: the attribute has a literal default value specified. + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + */ + public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31; + + /** + * Constant: the attribute was declared #IMPLIED. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32; + + /** + * Constant: the attribute was declared #REQUIRED. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33; + + /** + * Constant: the attribute was declared #FIXED. + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + */ + public final static int ATTRIBUTE_DEFAULT_FIXED = 34; + + // + // Constants for input. + // + private final static int INPUT_NONE = 0; + private final static int INPUT_INTERNAL = 1; + private final static int INPUT_STREAM = 3; + private final static int INPUT_READER = 5; + + // + // Flags for reading literals. + // + // expand general entity refs (attribute values in dtd and content) + private final static int LIT_ENTITY_REF = 2; + // normalize this value (space chars) (attributes, public ids) + private final static int LIT_NORMALIZE = 4; + // literal is an attribute value + private final static int LIT_ATTRIBUTE = 8; + // don't expand parameter entities + private final static int LIT_DISABLE_PE = 16; + // don't expand [or parse] character refs + private final static int LIT_DISABLE_CREF = 32; + // don't parse general entity refs + private final static int LIT_DISABLE_EREF = 64; + // literal is a public ID value + private final static int LIT_PUBID = 256; + + // + // Flags affecting PE handling in DTDs (if expandPE is true). + // PEs expand with space padding, except inside literals. + // + private final static int CONTEXT_NORMAL = 0; + private final static int CONTEXT_LITERAL = 1; + + // Emit warnings for relative URIs with no base URI. + static boolean uriWarnings; + static + { + String key = "gnu.xml.aelfred2.XmlParser.uriWarnings"; + GetPropertyAction a = new GetPropertyAction(key); + uriWarnings = "true".equals(AccessController.doPrivileged(a)); + } + + // + // The current XML handler interface. + // + private SAXDriver handler; + + // + // I/O information. + // + private Reader reader; // current reader + private InputStream is; // current input stream + private int line; // current line number + private int column; // current column number + private int sourceType; // type of input source + private LinkedList inputStack; // stack of input soruces + private URLConnection externalEntity; // current external entity + private int encoding; // current character encoding + private int currentByteCount; // bytes read from current source + private InputSource scratch; // temporary + + // + // Buffers for decoded but unparsed character input. + // + private char[] readBuffer; + private int readBufferPos; + private int readBufferLength; + private int readBufferOverflow; // overflow from last data chunk. + + // + // Buffer for undecoded raw byte input. + // + private final static int READ_BUFFER_MAX = 16384; + private byte[] rawReadBuffer; + + + // + // Buffer for attribute values, char refs, DTD stuff. + // + private static int DATA_BUFFER_INITIAL = 4096; + private char[] dataBuffer; + private int dataBufferPos; + + // + // Buffer for parsed names. + // + private static int NAME_BUFFER_INITIAL = 1024; + private char[] nameBuffer; + private int nameBufferPos; + + // + // Save any standalone flag + // + private boolean docIsStandalone; + + // + // Hashtables for DTD information on elements, entities, and notations. + // Populated until we start ignoring decls (because of skipping a PE) + // + private HashMap elementInfo; + private HashMap entityInfo; + private HashMap notationInfo; + private boolean skippedPE; + + // + // Element type currently in force. + // + private String currentElement; + private int currentElementContent; + + // + // Stack of entity names, to detect recursion. + // + private LinkedList entityStack; + + // + // PE expansion is enabled in most chunks of the DTD, not all. + // When it's enabled, literals are treated differently. + // + private boolean inLiteral; + private boolean expandPE; + private boolean peIsError; + + // + // can't report entity expansion inside two constructs: + // - attribute expansions (internal entities only) + // - markup declarations (parameter entities only) + // + private boolean doReport; + + // + // Symbol table, for caching interned names. + // + // These show up wherever XML names or nmtokens are used: naming elements, + // attributes, PIs, notations, entities, and enumerated attribute values. + // + // NOTE: This hashtable doesn't grow. The default size is intended to be + // rather large for most documents. Example: one snapshot of the DocBook + // XML 4.1 DTD used only about 350 such names. As a rule, only pathological + // documents (ones that don't reuse names) should ever see much collision. + // + // Be sure that SYMBOL_TABLE_LENGTH always stays prime, for best hashing. + // "2039" keeps the hash table size at about two memory pages on typical + // 32 bit hardware. + // + private final static int SYMBOL_TABLE_LENGTH = 2039; + + private Object[][] symbolTable; + + // + // Hash table of attributes found in current start tag. + // + private String[] tagAttributes; + private int tagAttributePos; + + // + // Utility flag: have we noticed a CR while reading the last + // data chunk? If so, we will have to go back and normalise + // CR or CR/LF line ends. + // + private boolean sawCR; + + // + // Utility flag: are we in CDATA? If so, whitespace isn't ignorable. + // + private boolean inCDATA; + + // + // Xml version. + // + private static final int XML_10 = 0; + private static final int XML_11 = 1; + private int xmlVersion = XML_10; + + ////////////////////////////////////////////////////////////////////// + // Constructors. + //////////////////////////////////////////////////////////////////////// + + /** + * Construct a new parser with no associated handler. + * @see #setHandler + * @see #parse + */ + // package private + XmlParser() + { + } + + /** + * Set the handler that will receive parsing events. + * @param handler The handler to receive callback events. + * @see #parse + */ + // package private + void setHandler(SAXDriver handler) + { + this.handler = handler; + } + + /** + * Parse an XML document from the character stream, byte stream, or URI + * that you provide (in that order of preference). Any URI that you + * supply will become the base URI for resolving relative URI, and may + * be used to acquire a reader or byte stream. + * + *

Only one thread at a time may use this parser; since it is + * private to this package, post-parse cleanup is done by the caller, + * which MUST NOT REUSE the parser (just null it). + * + * @param systemId Absolute URI of the document; should never be null, + * but may be so iff a reader or a stream is provided. + * @param publicId The public identifier of the document, or null. + * @param reader A character stream; must be null if stream isn't. + * @param stream A byte input stream; must be null if reader isn't. + * @param encoding The suggested encoding, or null if unknown. + * @exception java.lang.Exception Basically SAXException or IOException + */ + // package private + void doParse(String systemId, String publicId, Reader reader, + InputStream stream, String encoding) + throws Exception + { + if (handler == null) + { + throw new IllegalStateException("no callback handler"); + } + + initializeVariables(); + + // predeclare the built-in entities here (replacement texts) + // we don't need to intern(), since we're guaranteed literals + // are always (globally) interned. + setInternalEntity("amp", "&"); + setInternalEntity("lt", "<"); + setInternalEntity("gt", ">"); + setInternalEntity("apos", "'"); + setInternalEntity("quot", """); + + try + { + // pushURL first to ensure locator is correct in startDocument + // ... it might report an IO or encoding exception. + handler.startDocument(); + pushURL(false, "[document]", + // default baseURI: null + new ExternalIdentifiers(publicId, systemId, null), + reader, stream, encoding, false); + + parseDocument(); + } + catch (EOFException e) + { + //empty input + error("empty document, with no root element."); + } + finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + if (stream != null) + { + try + { + stream.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + if (is != null) + { + try + { + is.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + scratch = null; + } + } + + ////////////////////////////////////////////////////////////////////// + // Error reporting. + ////////////////////////////////////////////////////////////////////// + + /** + * Report an error. + * @param message The error message. + * @param textFound The text that caused the error (or null). + * @see SAXDriver#error + * @see #line + */ + private void error(String message, String textFound, String textExpected) + throws SAXException + { + if (textFound != null) + { + message = message + " (found \"" + textFound + "\")"; + } + if (textExpected != null) + { + message = message + " (expected \"" + textExpected + "\")"; + } + handler.fatal(message); + + // "can't happen" + throw new SAXException(message); + } + + /** + * Report a serious error. + * @param message The error message. + * @param textFound The text that caused the error (or null). + */ + private void error(String message, char textFound, String textExpected) + throws SAXException + { + error(message, Character.toString(textFound), textExpected); + } + + /** + * Report typical case fatal errors. + */ + private void error(String message) + throws SAXException + { + handler.fatal(message); + } + + ////////////////////////////////////////////////////////////////////// + // Major syntactic productions. + ////////////////////////////////////////////////////////////////////// + + /** + * Parse an XML document. + *

+   * [1] document ::= prolog element Misc*
+   * 
+ *

This is the top-level parsing function for a single XML + * document. As a minimum, a well-formed document must have + * a document element, and a valid document must have a prolog + * (one with doctype) as well. + */ + private void parseDocument() + throws Exception + { + try + { // added by MHK + boolean sawDTD = parseProlog(); + require('<'); + parseElement(!sawDTD); + } + catch (EOFException ee) + { // added by MHK + error("premature end of file", "[EOF]", null); + } + + try + { + parseMisc(); //skip all white, PIs, and comments + char c = readCh(); //if this doesn't throw an exception... + error("unexpected characters after document end", c, null); + } + catch (EOFException e) + { + return; + } + } + + static final char[] startDelimComment = { '<', '!', '-', '-' }; + static final char[] endDelimComment = { '-', '-' }; + + /** + * Skip a comment. + *

+   * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
+   * 
+ *

(The <!-- has already been read.) + */ + private void parseComment() + throws Exception + { + char c; + boolean saved = expandPE; + + expandPE = false; + parseUntil(endDelimComment); + require('>'); + expandPE = saved; + handler.comment(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + + static final char[] startDelimPI = { '<', '?' }; + static final char[] endDelimPI = { '?', '>' }; + + /** + * Parse a processing instruction and do a call-back. + *

+   * [16] PI ::= '<?' PITarget
+   *    (S (Char* - (Char* '?>' Char*)))?
+   *    '?>'
+   * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
+   * 
+ *

(The <? has already been read.) + */ + private void parsePI() + throws SAXException, IOException + { + String name; + boolean saved = expandPE; + + expandPE = false; + name = readNmtoken(true); + //NE08 + if (name.indexOf(':') >= 0) + { + error("Illegal character(':') in processing instruction name ", + name, null); + } + if ("xml".equalsIgnoreCase(name)) + { + error("Illegal processing instruction target", name, null); + } + if (!tryRead(endDelimPI)) + { + requireWhitespace(); + parseUntil(endDelimPI); + } + expandPE = saved; + handler.processingInstruction(name, dataBufferToString()); + } + + static final char[] endDelimCDATA = { ']', ']', '>' }; + + private boolean isDirtyCurrentElement; + + /** + * Parse a CDATA section. + *

+   * [18] CDSect ::= CDStart CData CDEnd
+   * [19] CDStart ::= '<![CDATA['
+   * [20] CData ::= (Char* - (Char* ']]>' Char*))
+   * [21] CDEnd ::= ']]>'
+   * 
+ *

(The '<![CDATA[' has already been read.) + */ + private void parseCDSect() + throws Exception + { + parseUntil(endDelimCDATA); + dataBufferFlush(); + } + + /** + * Parse the prolog of an XML document. + *

+   * [22] prolog ::= XMLDecl? Misc* (Doctypedecl Misc*)?
+   * 
+ *

We do not look for the XML declaration here, because it was + * handled by pushURL (). + * @see pushURL + * @return true if a DTD was read. + */ + private boolean parseProlog() + throws Exception + { + parseMisc(); + + if (tryRead(" + * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' + * [24] VersionInfo ::= S 'version' Eq + * ("'" VersionNum "'" | '"' VersionNum '"' ) + * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')* + * [32] SDDecl ::= S 'standalone' Eq + * ( "'"" ('yes' | 'no') "'"" | '"' ("yes" | "no") '"' ) + * [80] EncodingDecl ::= S 'encoding' Eq + * ( "'" EncName "'" | "'" EncName "'" ) + * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + * + *

(The <?xml and whitespace have already been read.) + * @return the encoding in the declaration, uppercased; or null + * @see #parseTextDecl + * @see #setupDecoding + */ + private String parseXMLDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + String version; + String encodingName = null; + String standalone = null; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + String inputEncoding = null; + + switch (this.encoding) + { + case ENCODING_EXTERNAL: + case ENCODING_UTF_8: + inputEncoding = "UTF-8"; + break; + case ENCODING_ISO_8859_1: + inputEncoding = "ISO-8859-1"; + break; + case ENCODING_UCS_2_12: + inputEncoding = "UTF-16BE"; + break; + case ENCODING_UCS_2_21: + inputEncoding = "UTF-16LE"; + break; + } + + // Read the version. + require("version"); + parseEq(); + checkLegalVersion(version = readLiteral(flags)); + if (!version.equals("1.0")) + { + if (version.equals("1.1")) + { + handler.warn("expected XML version 1.0, not: " + version); + xmlVersion = XML_11; + } + else + { + error("illegal XML version", version, "1.0 or 1.1"); + } + } + else + { + xmlVersion = XML_10; + } + // Try reading an encoding declaration. + boolean white = tryWhitespace(); + + if (tryRead("encoding")) + { + if (!white) + { + error("whitespace required before 'encoding='"); + } + parseEq(); + encodingName = readLiteral(flags); + if (!ignoreEncoding) + { + setupDecoding(encodingName); + } + } + + // Try reading a standalone declaration + if (encodingName != null) + { + white = tryWhitespace(); + } + if (tryRead("standalone")) + { + if (!white) + { + error("whitespace required before 'standalone='"); + } + parseEq(); + standalone = readLiteral(flags); + if ("yes".equals(standalone)) + { + docIsStandalone = true; + } + else if (!"no".equals(standalone)) + { + error("standalone flag must be 'yes' or 'no'"); + } + } + + skipWhitespace(); + require("?>"); + + if (inputEncoding == null) + { + inputEncoding = encodingName; + } + return encodingName; + } + + /** + * Parse a text declaration. + *

+   * [79] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
+   * [80] EncodingDecl ::= S 'encoding' Eq
+   *    ( '"' EncName '"' | "'" EncName "'" )
+   * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+   * 
+ *

(The <?xml' and whitespace have already been read.) + * @return the encoding in the declaration, uppercased; or null + * @see #parseXMLDecl + * @see #setupDecoding + */ + private String parseTextDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + String encodingName = null; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + // Read an optional version. + if (tryRead ("version")) + { + String version; + parseEq(); + checkLegalVersion(version = readLiteral(flags)); + + if (version.equals("1.1")) + { + if (xmlVersion == XML_10) + { + error("external subset has later version number.", "1.0", + version); + } + handler.warn("expected XML version 1.0, not: " + version); + xmlVersion = XML_11; + } + else if (!version.equals("1.0")) + { + error("illegal XML version", version, "1.0 or 1.1"); + } + requireWhitespace(); + } + + // Read the encoding. + require("encoding"); + parseEq(); + encodingName = readLiteral(flags); + if (!ignoreEncoding) + { + setupDecoding(encodingName); + } + skipWhitespace(); + require("?>"); + + return encodingName; + } + + /** + * Sets up internal state so that we can decode an entity using the + * specified encoding. This is used when we start to read an entity + * and we have been given knowledge of its encoding before we start to + * read any data (e.g. from a SAX input source or from a MIME type). + * + *

It is also used after autodetection, at which point only very + * limited adjustments to the encoding may be used (switching between + * related builtin decoders). + * + * @param encodingName The name of the encoding specified by the user. + * @exception IOException if the encoding isn't supported either + * internally to this parser, or by the hosting JVM. + * @see #parseXMLDecl + * @see #parseTextDecl + */ + private void setupDecoding(String encodingName) + throws SAXException, IOException + { + encodingName = encodingName.toUpperCase(); + + // ENCODING_EXTERNAL indicates an encoding that wasn't + // autodetected ... we can use builtin decoders, or + // ones from the JVM (InputStreamReader). + + // Otherwise we can only tweak what was autodetected, and + // only for single byte (ASCII derived) builtin encodings. + + // ASCII-derived encodings + if (encoding == ENCODING_UTF_8 || encoding == ENCODING_EXTERNAL) + { + if (encodingName.equals("ISO-8859-1") + || encodingName.equals("8859_1") + || encodingName.equals("ISO8859_1")) + { + encoding = ENCODING_ISO_8859_1; + return; + } + else if (encodingName.equals("US-ASCII") + || encodingName.equals("ASCII")) + { + encoding = ENCODING_ASCII; + return; + } + else if (encodingName.equals("UTF-8") + || encodingName.equals("UTF8")) + { + encoding = ENCODING_UTF_8; + return; + } + else if (encoding != ENCODING_EXTERNAL) + { + // used to start with a new reader ... + throw new UnsupportedEncodingException(encodingName); + } + // else fallthrough ... + // it's ASCII-ish and something other than a builtin + } + + // Unicode and such + if (encoding == ENCODING_UCS_2_12 || encoding == ENCODING_UCS_2_21) + { + if (!(encodingName.equals("ISO-10646-UCS-2") + || encodingName.equals("UTF-16") + || encodingName.equals("UTF-16BE") + || encodingName.equals("UTF-16LE"))) + { + error("unsupported Unicode encoding", encodingName, "UTF-16"); + } + return; + } + + // four byte encodings + if (encoding == ENCODING_UCS_4_1234 + || encoding == ENCODING_UCS_4_4321 + || encoding == ENCODING_UCS_4_2143 + || encoding == ENCODING_UCS_4_3412) + { + // Strictly: "UCS-4" == "UTF-32BE"; also, "UTF-32LE" exists + if (!encodingName.equals("ISO-10646-UCS-4")) + { + error("unsupported 32-bit encoding", encodingName, + "ISO-10646-UCS-4"); + } + return; + } + + // assert encoding == ENCODING_EXTERNAL + // if (encoding != ENCODING_EXTERNAL) + // throw new RuntimeException ("encoding = " + encoding); + + if (encodingName.equals("UTF-16BE")) + { + encoding = ENCODING_UCS_2_12; + return; + } + if (encodingName.equals("UTF-16LE")) + { + encoding = ENCODING_UCS_2_21; + return; + } + + // We couldn't use the builtin decoders at all. But we can try to + // create a reader, since we haven't messed up buffering. Tweak + // the encoding name if necessary. + + if (encodingName.equals("UTF-16") + || encodingName.equals("ISO-10646-UCS-2")) + { + encodingName = "Unicode"; + } + // Ignoring all the EBCDIC aliases here + + reader = new InputStreamReader(is, encodingName); + sourceType = INPUT_READER; + } + + /** + * Parse miscellaneous markup outside the document element and DOCTYPE + * declaration. + *

+   * [27] Misc ::= Comment | PI | S
+   * 
+ */ + private void parseMisc() + throws Exception + { + while (true) + { + skipWhitespace(); + if (tryRead(startDelimPI)) + { + parsePI(); + } + else if (tryRead(startDelimComment)) + { + parseComment(); + } + else + { + return; + } + } + } + + /** + * Parse a document type declaration. + *
+   * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
+   *    ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
+   * 
+ *

(The <!DOCTYPE has already been read.) + */ + private void parseDoctypedecl() + throws Exception + { + String rootName; + ExternalIdentifiers ids; + + // Read the document type name. + requireWhitespace(); + rootName = readNmtoken(true); + + // Read the External subset's IDs + skipWhitespace(); + ids = readExternalIds(false, true); + + // report (a) declaration of name, (b) lexical info (ids) + handler.doctypeDecl(rootName, ids.publicId, ids.systemId); + + // Internal subset is parsed first, if present + skipWhitespace(); + if (tryRead('[')) + { + + // loop until the subset ends + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead(']')) + { + break; // end of subset + } + else + { + // WFC, PEs in internal subset (only between decls) + peIsError = expandPE = true; + parseMarkupdecl(); + peIsError = expandPE = false; + } + } + } + skipWhitespace(); + require('>'); + + // Read the external subset, if any + InputSource subset; + + if (ids.systemId == null) + { + subset = handler.getExternalSubset(rootName, + handler.getSystemId()); + } + else + { + subset = null; + } + if (ids.systemId != null || subset != null) + { + pushString(null, ">"); + + // NOTE: [dtd] is so we say what SAX2 expects, + // though it's misleading (subset, not entire dtd) + if (ids.systemId != null) + { + pushURL(true, "[dtd]", ids, null, null, null, true); + } + else + { + handler.warn("modifying document by adding external subset"); + pushURL(true, "[dtd]", + new ExternalIdentifiers(subset.getPublicId(), + subset.getSystemId(), + null), + subset.getCharacterStream(), + subset.getByteStream(), + subset.getEncoding(), + false); + } + + // Loop until we end up back at '>' + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead('>')) + { + break; + } + else + { + expandPE = true; + parseMarkupdecl(); + expandPE = false; + } + } + + // the ">" string isn't popped yet + if (inputStack.size() != 1) + { + error("external subset has unmatched '>'"); + } + } + + // done dtd + handler.endDoctype(); + expandPE = false; + doReport = true; + } + + /** + * Parse a markup declaration in the internal or external DTD subset. + *

+   * [29] markupdecl ::= elementdecl | Attlistdecl | EntityDecl
+   *    | NotationDecl | PI | Comment
+   * [30] extSubsetDecl ::= (markupdecl | conditionalSect
+   *    | PEReference | S) *
+   * 
+ *

Reading toplevel PE references is handled as a lexical issue + * by the caller, as is whitespace. + */ + private void parseMarkupdecl() + throws Exception + { + char[] saved = null; + boolean savedPE = expandPE; + + // prevent "<%foo;" and ensures saved entity is right + require('<'); + unread('<'); + expandPE = false; + + if (tryRead(" 0) + { + parseConditionalSect(saved); + } + else + { + error("conditional sections illegal in internal subset"); + } + } + else + { + error("expected markup declaration"); + } + + // VC: Proper Decl/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Declaration/PE nesting"); + } + } + + /** + * Parse an element, with its tags. + *

+   * [39] element ::= EmptyElementTag | STag content ETag
+   * [40] STag ::= '<' Name (S Attribute)* S? '>'
+   * [44] EmptyElementTag ::= '<' Name (S Attribute)* S? '/>'
+   * 
+ *

(The '<' has already been read.) + *

NOTE: this method actually chains onto parseContent (), if necessary, + * and parseContent () will take care of calling parseETag (). + */ + private void parseElement(boolean maybeGetSubset) + throws Exception + { + String gi; + char c; + int oldElementContent = currentElementContent; + String oldElement = currentElement; + ElementDecl element; + + // This is the (global) counter for the + // array of specified attributes. + tagAttributePos = 0; + + // Read the element type name. + gi = readNmtoken(true); + + // If we saw no DTD, and this is the document root element, + // let the application modify the input stream by providing one. + if (maybeGetSubset) + { + InputSource subset = handler.getExternalSubset(gi, + handler.getSystemId()); + if (subset != null) + { + String publicId = subset.getPublicId(); + String systemId = subset.getSystemId(); + + handler.warn("modifying document by adding DTD"); + handler.doctypeDecl(gi, publicId, systemId); + pushString(null, ">"); + + // NOTE: [dtd] is so we say what SAX2 expects, + // though it's misleading (subset, not entire dtd) + pushURL(true, "[dtd]", + new ExternalIdentifiers(publicId, systemId, null), + subset.getCharacterStream(), + subset.getByteStream(), + subset.getEncoding(), + false); + + // Loop until we end up back at '>' + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead('>')) + { + break; + } + else + { + expandPE = true; + parseMarkupdecl(); + expandPE = false; + } + } + + // the ">" string isn't popped yet + if (inputStack.size() != 1) + { + error("external subset has unmatched '>'"); + } + + handler.endDoctype(); + } + } + + // Determine the current content type. + currentElement = gi; + element = (ElementDecl) elementInfo.get(gi); + currentElementContent = getContentType(element, CONTENT_ANY); + + // Read the attributes, if any. + // After this loop, "c" is the closing delimiter. + boolean white = tryWhitespace(); + c = readCh(); + while (c != '/' && c != '>') + { + unread(c); + if (!white) + { + error("need whitespace between attributes"); + } + parseAttribute(gi); + white = tryWhitespace(); + c = readCh(); + } + + // Supply any defaulted attributes. + Iterator atts = declaredAttributes(element); + if (atts != null) + { + String aname; +loop: + while (atts.hasNext()) + { + aname = (String) atts.next(); + // See if it was specified. + for (int i = 0; i < tagAttributePos; i++) + { + if (tagAttributes[i] == aname) + { + continue loop; + } + } + // ... or has a default + String value = getAttributeDefaultValue(gi, aname); + + if (value == null) + { + continue; + } + handler.attribute(aname, value, false); + } + } + + // Figure out if this is a start tag + // or an empty element, and dispatch an + // event accordingly. + switch (c) + { + case '>': + handler.startElement(gi); + parseContent(); + break; + case '/': + require('>'); + handler.startElement(gi); + handler.endElement(gi); + break; + } + + // Restore the previous state. + currentElement = oldElement; + currentElementContent = oldElementContent; + } + + /** + * Parse an attribute assignment. + *

+   * [41] Attribute ::= Name Eq AttValue
+   * 
+ * @param name The name of the attribute's element. + * @see SAXDriver#attribute + */ + private void parseAttribute(String name) + throws Exception + { + String aname; + String type; + String value; + int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF; + + // Read the attribute name. + aname = readNmtoken(true); + type = getAttributeType(name, aname); + + // Parse '=' + parseEq(); + + // Read the value, normalizing whitespace + // unless it is CDATA. + if (handler.stringInterning) + { + if (type == "CDATA" || type == null) + { + value = readLiteral(flags); + } + else + { + value = readLiteral(flags | LIT_NORMALIZE); + } + } + else + { + if (type == null || type.equals("CDATA")) + { + value = readLiteral(flags); + } + else + { + value = readLiteral(flags | LIT_NORMALIZE); + } + } + + // WFC: no duplicate attributes + for (int i = 0; i < tagAttributePos; i++) + { + if (aname.equals(tagAttributes [i])) + { + error("duplicate attribute", aname, null); + } + } + + // Inform the handler about the + // attribute. + handler.attribute(aname, value, true); + dataBufferPos = 0; + + // Note that the attribute has been + // specified. + if (tagAttributePos == tagAttributes.length) + { + String newAttrib[] = new String[tagAttributes.length * 2]; + System.arraycopy(tagAttributes, 0, newAttrib, 0, tagAttributePos); + tagAttributes = newAttrib; + } + tagAttributes[tagAttributePos++] = aname; + } + + /** + * Parse an equals sign surrounded by optional whitespace. + *
+   * [25] Eq ::= S? '=' S?
+   * 
+ */ + private void parseEq() + throws SAXException, IOException + { + skipWhitespace(); + require('='); + skipWhitespace(); + } + + /** + * Parse an end tag. + *
+   * [42] ETag ::= ''
+   * 
+ *

NOTE: parseContent () chains to here, we already read the + * "</". + */ + private void parseETag() + throws Exception + { + require(currentElement); + skipWhitespace(); + require('>'); + handler.endElement(currentElement); + // not re-reporting any SAXException re bogus end tags, + // even though that diagnostic might be clearer ... + } + + /** + * Parse the content of an element. + *

+   * [43] content ::= (element | CharData | Reference
+   *    | CDSect | PI | Comment)*
+   * [67] Reference ::= EntityRef | CharRef
+   * 
+ *

NOTE: consumes ETtag. + */ + private void parseContent() + throws Exception + { + char c; + + while (true) + { + // consume characters (or ignorable whitspace) until delimiter + parseCharData(); + + // Handle delimiters + c = readCh(); + switch (c) + { + case '&': // Found "&" + c = readCh(); + if (c == '#') + { + parseCharRef(); + } + else + { + unread(c); + parseEntityRef(true); + } + isDirtyCurrentElement = true; + break; + + case '<': // Found "<" + dataBufferFlush(); + c = readCh(); + switch (c) + { + case '!': // Found " + * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' + * + *

NOTE: the '<!ELEMENT' has already been read. + */ + private void parseElementDecl() + throws Exception + { + String name; + + requireWhitespace(); + // Read the element type name. + name = readNmtoken(true); + + requireWhitespace(); + // Read the content model. + parseContentspec(name); + + skipWhitespace(); + require('>'); + } + + /** + * Content specification. + *

+   * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | elements
+   * 
+ */ + private void parseContentspec(String name) + throws Exception + { + // FIXME: move elementDecl() into setElement(), pass EMTPY/ANY ... + if (tryRead("EMPTY")) + { + setElement(name, CONTENT_EMPTY, null, null); + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, "EMPTY"); + } + return; + } + else if (tryRead("ANY")) + { + setElement(name, CONTENT_ANY, null, null); + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, "ANY"); + } + return; + } + else + { + String model; + char[] saved; + + require('('); + saved = readBuffer; + dataBufferAppend('('); + skipWhitespace(); + if (tryRead("#PCDATA")) + { + dataBufferAppend("#PCDATA"); + parseMixed(saved); + model = dataBufferToString(); + setElement(name, CONTENT_MIXED, model, null); + } + else + { + parseElements(saved); + model = dataBufferToString(); + setElement(name, CONTENT_ELEMENTS, model, null); + } + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, model); + } + } + } + + /** + * Parse an element-content model. + *
+   * [47] elements ::= (choice | seq) ('?' | '*' | '+')?
+   * [49] choice ::= '(' S? cp (S? '|' S? cp)+ S? ')'
+   * [50] seq ::= '(' S? cp (S? ',' S? cp)* S? ')'
+   * 
+ * + *

NOTE: the opening '(' and S have already been read. + * + * @param saved Buffer for entity that should have the terminal ')' + */ + private void parseElements(char[] saved) + throws Exception + { + char c; + char sep; + + // Parse the first content particle + skipWhitespace(); + parseCp(); + + // Check for end or for a separator. + skipWhitespace(); + c = readCh(); + switch (c) + { + case ')': + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(')'); + c = readCh(); + switch (c) + { + case '*': + case '+': + case '?': + dataBufferAppend(c); + break; + default: + unread(c); + } + return; + case ',': // Register the separator. + case '|': + sep = c; + dataBufferAppend(c); + break; + default: + error("bad separator in content model", c, null); + return; + } + + // Parse the rest of the content model. + while (true) + { + skipWhitespace(); + parseCp(); + skipWhitespace(); + c = readCh(); + if (c == ')') + { + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(')'); + break; + } + else if (c != sep) + { + error("bad separator in content model", c, null); + return; + } + else + { + dataBufferAppend(c); + } + } + + // Check for the occurrence indicator. + c = readCh(); + switch (c) + { + case '?': + case '*': + case '+': + dataBufferAppend(c); + return; + default: + unread(c); + return; + } + } + + /** + * Parse a content particle. + *

+   * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
+   * 
+ */ + private void parseCp() + throws Exception + { + if (tryRead('(')) + { + dataBufferAppend('('); + parseElements(readBuffer); + } + else + { + dataBufferAppend(readNmtoken(true)); + char c = readCh(); + switch (c) + { + case '?': + case '*': + case '+': + dataBufferAppend(c); + break; + default: + unread(c); + break; + } + } + } + + /** + * Parse mixed content. + *
+   * [51] Mixed ::= '(' S? ( '#PCDATA' (S? '|' S? Name)*) S? ')*'
+   *        | '(' S? ('#PCDATA') S? ')'
+   * 
+ * + * @param saved Buffer for entity that should have the terminal ')' + */ + private void parseMixed(char[] saved) + throws Exception + { + // Check for PCDATA alone. + skipWhitespace(); + if (tryRead(')')) + { + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(")*"); + tryRead('*'); + return; + } + + // Parse mixed content. + skipWhitespace(); + while (!tryRead(")")) + { + require('|'); + dataBufferAppend('|'); + skipWhitespace(); + dataBufferAppend(readNmtoken(true)); + skipWhitespace(); + } + + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + require('*'); + dataBufferAppend(")*"); + } + + /** + * Parse an attribute list declaration. + *
+   * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
+   * 
+ *

NOTE: the '<!ATTLIST' has already been read. + */ + private void parseAttlistDecl() + throws Exception + { + String elementName; + + requireWhitespace(); + elementName = readNmtoken(true); + boolean white = tryWhitespace(); + while (!tryRead('>')) + { + if (!white) + { + error("whitespace required before attribute definition"); + } + parseAttDef(elementName); + white = tryWhitespace(); + } + } + + /** + * Parse a single attribute definition. + *

+   * [53] AttDef ::= S Name S AttType S DefaultDecl
+   * 
+ */ + private void parseAttDef(String elementName) + throws Exception + { + String name; + String type; + String enumer = null; + + // Read the attribute name. + name = readNmtoken(true); + + // Read the attribute type. + requireWhitespace(); + type = readAttType(); + + // Get the string of enumerated values if necessary. + if (handler.stringInterning) + { + if ("ENUMERATION" == type || "NOTATION" == type) + { + enumer = dataBufferToString(); + } + } + else + { + if ("ENUMERATION".equals(type) || "NOTATION".equals(type)) + { + enumer = dataBufferToString(); + } + } + + // Read the default value. + requireWhitespace(); + parseDefault(elementName, name, type, enumer); + } + + /** + * Parse the attribute type. + *
+   * [54] AttType ::= StringType | TokenizedType | EnumeratedType
+   * [55] StringType ::= 'CDATA'
+   * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY'
+   *    | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
+   * [57] EnumeratedType ::= NotationType | Enumeration
+   * 
+ */ + private String readAttType() + throws Exception + { + if (tryRead('(')) + { + parseEnumeration(false); + return "ENUMERATION"; + } + else + { + String typeString = readNmtoken(true); + if (handler.stringInterning) + { + if ("NOTATION" == typeString) + { + parseNotationType(); + return typeString; + } + else if ("CDATA" == typeString + || "ID" == typeString + || "IDREF" == typeString + || "IDREFS" == typeString + || "ENTITY" == typeString + || "ENTITIES" == typeString + || "NMTOKEN" == typeString + || "NMTOKENS" == typeString) + { + return typeString; + } + } + else + { + if ("NOTATION".equals(typeString)) + { + parseNotationType(); + return typeString; + } + else if ("CDATA".equals(typeString) + || "ID".equals(typeString) + || "IDREF".equals(typeString) + || "IDREFS".equals(typeString) + || "ENTITY".equals(typeString) + || "ENTITIES".equals(typeString) + || "NMTOKEN".equals(typeString) + || "NMTOKENS".equals(typeString)) + { + return typeString; + } + } + error("illegal attribute type", typeString, null); + return null; + } + } + + /** + * Parse an enumeration. + *
+   * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
+   * 
+ *

NOTE: the '(' has already been read. + */ + private void parseEnumeration(boolean isNames) + throws Exception + { + dataBufferAppend('('); + + // Read the first token. + skipWhitespace(); + dataBufferAppend(readNmtoken(isNames)); + // Read the remaining tokens. + skipWhitespace(); + while (!tryRead(')')) + { + require('|'); + dataBufferAppend('|'); + skipWhitespace(); + dataBufferAppend(readNmtoken (isNames)); + skipWhitespace(); + } + dataBufferAppend(')'); + } + + /** + * Parse a notation type for an attribute. + *

+   * [58] NotationType ::= 'NOTATION' S '(' S? NameNtoks
+   *    (S? '|' S? name)* S? ')'
+   * 
+ *

NOTE: the 'NOTATION' has already been read + */ + private void parseNotationType() + throws Exception + { + requireWhitespace(); + require('('); + + parseEnumeration(true); + } + + /** + * Parse the default value for an attribute. + *

+   * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
+   *    | (('#FIXED' S)? AttValue)
+   * 
+ */ + private void parseDefault(String elementName, String name, + String type, String enumer) + throws Exception + { + int valueType = ATTRIBUTE_DEFAULT_SPECIFIED; + String value = null; + int flags = LIT_ATTRIBUTE; + boolean saved = expandPE; + String defaultType = null; + + // LIT_ATTRIBUTE forces '<' checks now (ASAP) and turns whitespace + // chars to spaces (doesn't matter when that's done if it doesn't + // interfere with char refs expanding to whitespace). + + if (!skippedPE) + { + flags |= LIT_ENTITY_REF; + if (handler.stringInterning) + { + if ("CDATA" != type) + { + flags |= LIT_NORMALIZE; + } + } + else + { + if (!"CDATA".equals(type)) + { + flags |= LIT_NORMALIZE; + } + } + } + + expandPE = false; + if (tryRead('#')) + { + if (tryRead("FIXED")) + { + defaultType = "#FIXED"; + valueType = ATTRIBUTE_DEFAULT_FIXED; + requireWhitespace(); + value = readLiteral(flags); + } + else if (tryRead("REQUIRED")) + { + defaultType = "#REQUIRED"; + valueType = ATTRIBUTE_DEFAULT_REQUIRED; + } + else if (tryRead("IMPLIED")) + { + defaultType = "#IMPLIED"; + valueType = ATTRIBUTE_DEFAULT_IMPLIED; + } + else + { + error("illegal keyword for attribute default value"); + } + } + else + { + value = readLiteral(flags); + } + expandPE = saved; + setAttribute(elementName, name, type, enumer, value, valueType); + if (handler.stringInterning) + { + if ("ENUMERATION" == type) + { + type = enumer; + } + else if ("NOTATION" == type) + { + type = "NOTATION " + enumer; + } + } + else + { + if ("ENUMERATION".equals(type)) + { + type = enumer; + } + else if ("NOTATION".equals(type)) + { + type = "NOTATION " + enumer; + } + } + if (!skippedPE) + { + handler.getDeclHandler().attributeDecl(elementName, name, type, + defaultType, value); + } + } + + /** + * Parse a conditional section. + *
+   * [61] conditionalSect ::= includeSect || ignoreSect
+   * [62] includeSect ::= '<![' S? 'INCLUDE' S? '['
+   *    extSubsetDecl ']]>'
+   * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '['
+   *    ignoreSectContents* ']]>'
+   * [64] ignoreSectContents ::= Ignore
+   *    ('<![' ignoreSectContents* ']]>' Ignore )*
+   * [65] Ignore ::= Char* - (Char* ( '<![' | ']]>') Char* )
+   * 
+ *

NOTE: the '>![' has already been read. + */ + private void parseConditionalSect(char[] saved) + throws Exception + { + skipWhitespace(); + if (tryRead("INCLUDE")) + { + skipWhitespace(); + require('['); + // VC: Proper Conditional Section/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Conditional Section/PE nesting"); + } + skipWhitespace(); + while (!tryRead("]]>")) + { + parseMarkupdecl(); + skipWhitespace(); + } + } + else if (tryRead("IGNORE")) + { + skipWhitespace(); + require('['); + // VC: Proper Conditional Section/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Conditional Section/PE nesting"); + } + int nesting = 1; + char c; + expandPE = false; + for (int nest = 1; nest > 0; ) + { + c = readCh(); + switch (c) + { + case '<': + if (tryRead("![")) + { + nest++; + } + break; + case ']': + if (tryRead("]>")) + { + nest--; + } + } + } + expandPE = true; + } + else + { + error("conditional section must begin with INCLUDE or IGNORE"); + } + } + + private void parseCharRef() + throws SAXException, IOException + { + parseCharRef(true /* do flushDataBuffer by default */); + } + + /** + * Try to read a character reference without consuming data from buffer. + *

+   * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+   * 
+ *

NOTE: the '&#' has already been read. + */ + private void tryReadCharRef() + throws SAXException, IOException + { + int value = 0; + char c; + + if (tryRead('x')) + { +loop1: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop1; + } + else + { + int n = Character.digit(c, 16); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop1; + } + value *= 16; + value += n; + } + } + } + else + { +loop2: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop2; + } + else + { + int n = Character.digit(c, 10); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop2; + } + value *= 10; + value += n; + } + } + } + + // check for character refs being legal XML + if ((value < 0x0020 + && ! (value == '\n' || value == '\t' || value == '\r')) + || (value >= 0xD800 && value <= 0xDFFF) + || value == 0xFFFE || value == 0xFFFF + || value > 0x0010ffff) + { + error("illegal XML character reference U+" + + Integer.toHexString(value)); + } + + // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz + // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz: + if (value > 0x0010ffff) + { + // too big for surrogate + error("character reference " + value + " is too large for UTF-16", + Integer.toString(value), null); + } + + } + + /** + * Read and interpret a character reference. + *

+   * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+   * 
+ *

NOTE: the '&#' has already been read. + */ + private void parseCharRef(boolean doFlush) + throws SAXException, IOException + { + int value = 0; + char c; + + if (tryRead('x')) + { +loop1: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop1; + } + else + { + int n = Character.digit(c, 16); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop1; + } + value *= 16; + value += n; + } + } + } + else + { +loop2: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop2; + } + else + { + int n = Character.digit(c, 10); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop2; + } + value *= 10; + value += c - '0'; + } + } + } + + // check for character refs being legal XML + if ((value < 0x0020 + && ! (value == '\n' || value == '\t' || value == '\r')) + || (value >= 0xD800 && value <= 0xDFFF) + || value == 0xFFFE || value == 0xFFFF + || value > 0x0010ffff) + { + error("illegal XML character reference U+" + + Integer.toHexString(value)); + } + + // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz + // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz: + if (value <= 0x0000ffff) + { + // no surrogates needed + dataBufferAppend((char) value); + } + else if (value <= 0x0010ffff) + { + value -= 0x10000; + // > 16 bits, surrogate needed + dataBufferAppend((char) (0xd800 | (value >> 10))); + dataBufferAppend((char) (0xdc00 | (value & 0x0003ff))); + } + else + { + // too big for surrogate + error("character reference " + value + " is too large for UTF-16", + Integer.toString(value), null); + } + if (doFlush) + { + dataBufferFlush(); + } + } + + /** + * Parse and expand an entity reference. + *

+   * [68] EntityRef ::= '&' Name ';'
+   * 
+ *

NOTE: the '&' has already been read. + * @param externalAllowed External entities are allowed here. + */ + private void parseEntityRef(boolean externalAllowed) + throws SAXException, IOException + { + String name; + + name = readNmtoken(true); + require(';'); + switch (getEntityType(name)) + { + case ENTITY_UNDECLARED: + // NOTE: XML REC describes amazingly convoluted handling for + // this case. Nothing as meaningful as being a WFness error + // unless the processor might _legitimately_ not have seen a + // declaration ... which is what this implements. + String message; + + message = "reference to undeclared general entity " + name; + if (skippedPE && !docIsStandalone) + { + handler.verror(message); + // we don't know this entity, and it might be external... + if (externalAllowed) + { + handler.skippedEntity(name); + } + } + else + { + error(message); + } + break; + case ENTITY_INTERNAL: + pushString(name, getEntityValue(name)); + + //workaround for possible input pop before marking + //the buffer reading position + char t = readCh(); + unread(t); + int bufferPosMark = readBufferPos; + + int end = readBufferPos + getEntityValue(name).length(); + for (int k = readBufferPos; k < end; k++) + { + t = readCh(); + if (t == '&') + { + t = readCh(); + if (t == '#') + { + //try to match a character ref + tryReadCharRef(); + + //everything has been read + if (readBufferPos >= end) + { + break; + } + k = readBufferPos; + continue; + } + else if (Character.isLetter(t)) + { + //looks like an entity ref + unread(t); + readNmtoken(true); + require(';'); + + //everything has been read + if (readBufferPos >= end) + { + break; + } + k = readBufferPos; + continue; + } + error(" malformed entity reference"); + } + + } + readBufferPos = bufferPosMark; + break; + case ENTITY_TEXT: + if (externalAllowed) + { + pushURL(false, name, getEntityIds(name), + null, null, null, true); + } + else + { + error("reference to external entity in attribute value.", + name, null); + } + break; + case ENTITY_NDATA: + if (externalAllowed) + { + error("unparsed entity reference in content", name, null); + } + else + { + error("reference to external entity in attribute value.", + name, null); + } + break; + default: + throw new RuntimeException(); + } + } + + /** + * Parse and expand a parameter entity reference. + *

+   * [69] PEReference ::= '%' Name ';'
+   * 
+ *

NOTE: the '%' has already been read. + */ + private void parsePEReference() + throws SAXException, IOException + { + String name; + + name = "%" + readNmtoken(true); + require(';'); + switch (getEntityType(name)) + { + case ENTITY_UNDECLARED: + // VC: Entity Declared + handler.verror("reference to undeclared parameter entity " + name); + + // we should disable handling of all subsequent declarations + // unless this is a standalone document (info discarded) + break; + case ENTITY_INTERNAL: + if (inLiteral) + { + pushString(name, getEntityValue(name)); + } + else + { + pushString(name, ' ' + getEntityValue(name) + ' '); + } + break; + case ENTITY_TEXT: + if (!inLiteral) + { + pushString(null, " "); + } + pushURL(true, name, getEntityIds(name), null, null, null, true); + if (!inLiteral) + { + pushString(null, " "); + } + break; + } + } + + /** + * Parse an entity declaration. + *

+   * [70] EntityDecl ::= GEDecl | PEDecl
+   * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
+   * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
+   * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
+   * [74] PEDef ::= EntityValue | ExternalID
+   * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
+   *       | 'PUBLIC' S PubidLiteral S SystemLiteral
+   * [76] NDataDecl ::= S 'NDATA' S Name
+   * 
+ *

NOTE: the '<!ENTITY' has already been read. + */ + private void parseEntityDecl() + throws Exception + { + boolean peFlag = false; + int flags = 0; + + // Check for a parameter entity. + expandPE = false; + requireWhitespace(); + if (tryRead('%')) + { + peFlag = true; + requireWhitespace(); + } + expandPE = true; + + // Read the entity name, and prepend + // '%' if necessary. + String name = readNmtoken(true); + //NE08 + if (name.indexOf(':') >= 0) + { + error("Illegal character(':') in entity name ", name, null); + } + if (peFlag) + { + name = "%" + name; + } + + // Read the entity value. + requireWhitespace(); + char c = readCh(); + unread (c); + if (c == '"' || c == '\'') + { + // Internal entity ... replacement text has expanded refs + // to characters and PEs, but not to general entities + String value = readLiteral(flags); + setInternalEntity(name, value); + } + else + { + // Read the external IDs + ExternalIdentifiers ids = readExternalIds(false, false); + + // Check for NDATA declaration. + boolean white = tryWhitespace(); + if (!peFlag && tryRead("NDATA")) + { + if (!white) + { + error("whitespace required before NDATA"); + } + requireWhitespace(); + String notationName = readNmtoken(true); + if (!skippedPE) + { + setExternalEntity(name, ENTITY_NDATA, ids, notationName); + handler.unparsedEntityDecl(name, ids.publicId, ids.systemId, + ids.baseUri, notationName); + } + } + else if (!skippedPE) + { + setExternalEntity(name, ENTITY_TEXT, ids, null); + handler.getDeclHandler() + .externalEntityDecl(name, ids.publicId, + handler.resolveURIs() + // FIXME: ASSUMES not skipped + // "false" forces error on bad URI + ? handler.absolutize(ids.baseUri, + ids.systemId, + false) + : ids.systemId); + } + } + + // Finish the declaration. + skipWhitespace(); + require('>'); + } + + /** + * Parse a notation declaration. + *

+   * [82] NotationDecl ::= '<!NOTATION' S Name S
+   *    (ExternalID | PublicID) S? '>'
+   * [83] PublicID ::= 'PUBLIC' S PubidLiteral
+   * 
+ *

NOTE: the '<!NOTATION' has already been read. + */ + private void parseNotationDecl() + throws Exception + { + String nname; + ExternalIdentifiers ids; + + requireWhitespace(); + nname = readNmtoken(true); + //NE08 + if (nname.indexOf(':') >= 0) + { + error("Illegal character(':') in notation name ", nname, null); + } + requireWhitespace(); + + // Read the external identifiers. + ids = readExternalIds(true, false); + + // Register the notation. + setNotation(nname, ids); + + skipWhitespace(); + require('>'); + } + + /** + * Parse character data. + *

+   * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
+   * 
+ */ + private void parseCharData() + throws Exception + { + char c; + int state = 0; + boolean pureWhite = false; + + // assert (dataBufferPos == 0); + + // are we expecting pure whitespace? it might be dirty... + if ((currentElementContent == CONTENT_ELEMENTS) && !isDirtyCurrentElement) + { + pureWhite = true; + } + + // always report right out of readBuffer + // to minimize (pointless) buffer copies + while (true) + { + int lineAugment = 0; + int columnAugment = 0; + int i; + +loop: + for (i = readBufferPos; i < readBufferLength; i++) + { + switch (c = readBuffer[i]) + { + case '\n': + lineAugment++; + columnAugment = 0; + // pureWhite unmodified + break; + case '\r': // should not happen!! + case '\t': + case ' ': + // pureWhite unmodified + columnAugment++; + break; + case '&': + case '<': + columnAugment++; + // pureWhite unmodified + // CLEAN end of text sequence + state = 1; + break loop; + case ']': + // that's not a whitespace char, and + // can not terminate pure whitespace either + pureWhite = false; + if ((i + 2) < readBufferLength) + { + if (readBuffer [i + 1] == ']' + && readBuffer [i + 2] == '>') + { + // ERROR end of text sequence + state = 2; + break loop; + } + } + else + { + // FIXME missing two end-of-buffer cases + } + columnAugment++; + break; + default: + if ((c < 0x0020 || c > 0xFFFD) + || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085) + && xmlVersion == XML_11)) + { + error("illegal XML character U+" + + Integer.toHexString(c)); + } + // that's not a whitespace char + pureWhite = false; + columnAugment++; + } + } + + // report text thus far + if (lineAugment > 0) + { + line += lineAugment; + column = columnAugment; + } + else + { + column += columnAugment; + } + + // report characters/whitspace + int length = i - readBufferPos; + + if (length != 0) + { + if (pureWhite) + { + handler.ignorableWhitespace(readBuffer, + readBufferPos, length); + } + else + { + handler.charData(readBuffer, readBufferPos, length); + } + readBufferPos = i; + } + + if (state != 0) + { + break; + } + + // fill next buffer from this entity, or + // pop stack and continue with previous entity + unread(readCh()); + } + if (!pureWhite) + { + isDirtyCurrentElement = true; + } + // finish, maybe with error + if (state != 1) // finish, no error + { + error("character data may not contain ']]>'"); + } + } + + ////////////////////////////////////////////////////////////////////// + // High-level reading and scanning methods. + ////////////////////////////////////////////////////////////////////// + + /** + * Require whitespace characters. + */ + private void requireWhitespace() + throws SAXException, IOException + { + char c = readCh(); + if (isWhitespace(c)) + { + skipWhitespace(); + } + else + { + error("whitespace required", c, null); + } + } + + /** + * Skip whitespace characters. + *
+   * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+   * 
+ */ + private void skipWhitespace() + throws SAXException, IOException + { + // Start with a little cheat. Most of + // the time, the white space will fall + // within the current read buffer; if + // not, then fall through. + if (USE_CHEATS) + { + int lineAugment = 0; + int columnAugment = 0; + +loop: + for (int i = readBufferPos; i < readBufferLength; i++) + { + switch (readBuffer[i]) + { + case ' ': + case '\t': + case '\r': + columnAugment++; + break; + case '\n': + lineAugment++; + columnAugment = 0; + break; + case '%': + if (expandPE) + { + break loop; + } + // else fall through... + default: + readBufferPos = i; + if (lineAugment > 0) + { + line += lineAugment; + column = columnAugment; + } + else + { + column += columnAugment; + } + return; + } + } + } + + // OK, do it the slow way. + char c = readCh (); + while (isWhitespace(c)) + { + c = readCh(); + } + unread(c); + } + + /** + * Read a name or (when parsing an enumeration) name token. + *
+   * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+   * [7] Nmtoken ::= (NameChar)+
+   * 
+ */ + private String readNmtoken(boolean isName) + throws SAXException, IOException + { + char c; + + if (USE_CHEATS) + { +loop: + for (int i = readBufferPos; i < readBufferLength; i++) + { + c = readBuffer[i]; + switch (c) + { + case '%': + if (expandPE) + { + break loop; + } + // else fall through... + + // What may legitimately come AFTER a name/nmtoken? + case '<': case '>': case '&': + case ',': case '|': case '*': case '+': case '?': + case ')': + case '=': + case '\'': case '"': + case '[': + case ' ': case '\t': case '\r': case '\n': + case ';': + case '/': + int start = readBufferPos; + if (i == start) + { + error("name expected", readBuffer[i], null); + } + readBufferPos = i; + return intern(readBuffer, start, i - start); + + default: + // FIXME ... per IBM's OASIS test submission, these: + // ? U+06dd + // Combining U+309B + //these switches are kind of ugly but at least we won't + //have to go over the whole lits for each char + if (isName && i == readBufferPos) + { + char c2 = (char) (c & 0x00f0); + switch (c & 0xff00) + { + //starting with 01 + case 0x0100: + switch (c2) + { + case 0x0030: + if (c == 0x0132 || c == 0x0133 || c == 0x013f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0040: + if (c == 0x0140 || c == 0x0149) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00c0: + if (c == 0x01c4 || c == 0x01cc) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00f0: + if (c == 0x01f1 || c == 0x01f3) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00b0: + if (c == 0x01f1 || c == 0x01f3) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + default: + if (c == 0x017f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + + break; + //starting with 11 + case 0x1100: + switch (c2) + { + case 0x0000: + if (c == 0x1104 || c == 0x1108 || + c == 0x110a || c == 0x110d) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0030: + if (c == 0x113b || c == 0x113f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0040: + if (c == 0x1141 || c == 0x114d + || c == 0x114f ) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0050: + if (c == 0x1151 || c == 0x1156) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0060: + if (c == 0x1162 || c == 0x1164 + || c == 0x1166 || c == 0x116b + || c == 0x116f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00b0: + if (c == 0x11b6 || c == 0x11b9 + || c == 0x11bb || c == 0x116f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + default: + if (c == 0x1174 || c == 0x119f + || c == 0x11ac || c == 0x11c3 + || c == 0x11f1) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + break; + default: + if (c == 0x0e46 || c == 0x1011 + || c == 0x212f || c == 0x0587 + || c == 0x0230 ) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + } + // punt on exact tests from Appendix A; approximate + // them using the Unicode ID start/part rules + if (i == readBufferPos && isName) + { + if (!Character.isUnicodeIdentifierStart(c) + && c != ':' && c != '_') + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + else if (!Character.isUnicodeIdentifierPart(c) + && c != '-' && c != ':' && c != '_' && c != '.' + && !isExtender(c)) + { + error("Not a name character, U+" + + Integer.toHexString(c)); + } + } + } + } + + nameBufferPos = 0; + + // Read the first character. + while (true) + { + c = readCh(); + switch (c) + { + case '%': + case '<': case '>': case '&': + case ',': case '|': case '*': case '+': case '?': + case ')': + case '=': + case '\'': case '"': + case '[': + case ' ': case '\t': case '\n': case '\r': + case ';': + case '/': + unread(c); + if (nameBufferPos == 0) + { + error ("name expected"); + } + // punt on exact tests from Appendix A, but approximate them + if (isName + && !Character.isUnicodeIdentifierStart(nameBuffer[0]) + && ":_".indexOf(nameBuffer[0]) == -1) + { + error("Not a name start character, U+" + + Integer.toHexString(nameBuffer[0])); + } + String s = intern(nameBuffer, 0, nameBufferPos); + nameBufferPos = 0; + return s; + default: + // punt on exact tests from Appendix A, but approximate them + + if ((nameBufferPos != 0 || !isName) + && !Character.isUnicodeIdentifierPart(c) + && ":-_.".indexOf(c) == -1 + && !isExtender(c)) + { + error("Not a name character, U+" + + Integer.toHexString(c)); + } + if (nameBufferPos >= nameBuffer.length) + { + nameBuffer = + (char[]) extendArray(nameBuffer, + nameBuffer.length, nameBufferPos); + } + nameBuffer[nameBufferPos++] = c; + } + } + } + + private static boolean isExtender(char c) + { + // [88] Extender ::= ... + return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 + || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 + || (c >= 0x3031 && c <= 0x3035) + || (c >= 0x309d && c <= 0x309e) + || (c >= 0x30fc && c <= 0x30fe); + } + + /** + * Read a literal. With matching single or double quotes as + * delimiters (and not embedded!) this is used to parse: + *
+   *  [9] EntityValue ::= ... ([^%&] | PEReference | Reference)* ...
+   *  [10] AttValue ::= ... ([^<&] | Reference)* ...
+   *  [11] SystemLiteral ::= ... (URLchar - "'")* ...
+   *  [12] PubidLiteral ::= ... (PubidChar - "'")* ...
+   * 
+ * as well as the quoted strings in XML and text declarations + * (for version, encoding, and standalone) which have their + * own constraints. + */ + private String readLiteral(int flags) + throws SAXException, IOException + { + char delim, c; + int startLine = line; + boolean saved = expandPE; + boolean savedReport = doReport; + + // Find the first delimiter. + delim = readCh(); + if (delim != '"' && delim != '\'') + { + error("expected '\"' or \"'\"", delim, null); + return null; + } + inLiteral = true; + if ((flags & LIT_DISABLE_PE) != 0) + { + expandPE = false; + } + doReport = false; + + // Each level of input source has its own buffer; remember + // ours, so we won't read the ending delimiter from any + // other input source, regardless of entity processing. + char[] ourBuf = readBuffer; + + // Read the literal. + try + { + c = readCh(); + boolean ampRead = false; +loop: + while (! (c == delim && readBuffer == ourBuf)) + { + switch (c) + { + // attributes and public ids are normalized + // in almost the same ways + case '\n': + case '\r': + if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0) + { + c = ' '; + } + break; + case '\t': + if ((flags & LIT_ATTRIBUTE) != 0) + { + c = ' '; + } + break; + case '&': + c = readCh(); + // Char refs are expanded immediately, except for + // all the cases where it's deferred. + if (c == '#') + { + if ((flags & LIT_DISABLE_CREF) != 0) + { + dataBufferAppend('&'); + break; + } + parseCharRef(false /* Do not do flushDataBuffer */); + + // exotic WFness risk: this is an entity literal, + // dataBuffer [dataBufferPos - 1] == '&', and + // following chars are a _partial_ entity/char ref + + // It looks like an entity ref ... + } + else + { + unread(c); + // Expand it? + if ((flags & LIT_ENTITY_REF) > 0) + { + parseEntityRef(false); + if (String.valueOf(readBuffer).equals("&")) + { + ampRead = true; + } + //Is it just data? + } + else if ((flags & LIT_DISABLE_EREF) != 0) + { + dataBufferAppend('&'); + + // OK, it will be an entity ref -- expanded later. + } + else + { + String name = readNmtoken(true); + require(';'); + dataBufferAppend('&'); + dataBufferAppend(name); + dataBufferAppend(';'); + } + } + c = readCh(); + continue loop; + + case '<': + // and why? Perhaps so "&foo;" expands the same + // inside and outside an attribute? + if ((flags & LIT_ATTRIBUTE) != 0) + { + error("attribute values may not contain '<'"); + } + break; + + // We don't worry about case '%' and PE refs, readCh does. + + default: + break; + } + dataBufferAppend(c); + c = readCh(); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter (started on line " + + startLine + ')', null, Character.toString(delim)); + } + inLiteral = false; + expandPE = saved; + doReport = savedReport; + + // Normalise whitespace if necessary. + if ((flags & LIT_NORMALIZE) > 0) + { + dataBufferNormalize(); + } + + // Return the value. + return dataBufferToString(); + } + + /** + * Try reading external identifiers. + * A system identifier is not required for notations. + * @param inNotation Are we parsing a notation decl? + * @param isSubset Parsing external subset decl (may be omitted)? + * @return A three-member String array containing the identifiers, + * or nulls. Order: public, system, baseURI. + */ + private ExternalIdentifiers readExternalIds(boolean inNotation, + boolean isSubset) + throws Exception + { + char c; + ExternalIdentifiers ids = new ExternalIdentifiers(); + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + if (tryRead("PUBLIC")) + { + requireWhitespace(); + ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags); + if (inNotation) + { + skipWhitespace(); + c = readCh(); + unread(c); + if (c == '"' || c == '\'') + { + ids.systemId = readLiteral(flags); + } + } + else + { + requireWhitespace(); + ids.systemId = readLiteral(flags); + } + + for (int i = 0; i < ids.publicId.length(); i++) + { + c = ids.publicId.charAt(i); + if (c >= 'a' && c <= 'z') + { + continue; + } + if (c >= 'A' && c <= 'Z') + { + continue; + } + if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(c) != -1) + { + continue; + } + error("illegal PUBLIC id character U+" + + Integer.toHexString(c)); + } + } + else if (tryRead("SYSTEM")) + { + requireWhitespace(); + ids.systemId = readLiteral(flags); + } + else if (!isSubset) + { + error("missing SYSTEM or PUBLIC keyword"); + } + + if (ids.systemId != null) + { + if (ids.systemId.indexOf('#') != -1) + { + handler.verror("SYSTEM id has a URI fragment: " + ids.systemId); + } + ids.baseUri = handler.getSystemId(); + if (ids.baseUri == null && uriWarnings) + { + handler.warn("No base URI; hope URI is absolute: " + + ids.systemId); + } + } + + return ids; + } + + /** + * Test if a character is whitespace. + *
+   * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+   * 
+ * @param c The character to test. + * @return true if the character is whitespace. + */ + private final boolean isWhitespace(char c) + { + if (c > 0x20) + { + return false; + } + if (c == 0x20 || c == 0x0a || c == 0x09 || c == 0x0d) + { + return true; + } + return false; // illegal ... + } + + ////////////////////////////////////////////////////////////////////// + // Utility routines. + ////////////////////////////////////////////////////////////////////// + + /** + * Add a character to the data buffer. + */ + private void dataBufferAppend(char c) + { + // Expand buffer if necessary. + if (dataBufferPos >= dataBuffer.length) + { + dataBuffer = (char[]) extendArray(dataBuffer, + dataBuffer.length, dataBufferPos); + } + dataBuffer[dataBufferPos++] = c; + } + + /** + * Add a string to the data buffer. + */ + private void dataBufferAppend(String s) + { + dataBufferAppend(s.toCharArray(), 0, s.length()); + } + + /** + * Append (part of) a character array to the data buffer. + */ + private void dataBufferAppend(char[] ch, int start, int length) + { + dataBuffer = (char[]) extendArray(dataBuffer, dataBuffer.length, + dataBufferPos + length); + + System.arraycopy(ch, start, dataBuffer, dataBufferPos, length); + dataBufferPos += length; + } + + /** + * Normalise space characters in the data buffer. + */ + private void dataBufferNormalize() + { + int i = 0; + int j = 0; + int end = dataBufferPos; + + // Skip spaces at the start. + while (j < end && dataBuffer[j] == ' ') + { + j++; + } + + // Skip whitespace at the end. + while (end > j && dataBuffer[end - 1] == ' ') + { + end --; + } + + // Start copying to the left. + while (j < end) + { + + char c = dataBuffer[j++]; + + // Normalise all other spaces to + // a single space. + if (c == ' ') + { + while (j < end && dataBuffer[j++] == ' ') + { + continue; + } + dataBuffer[i++] = ' '; + dataBuffer[i++] = dataBuffer[j - 1]; + } + else + { + dataBuffer[i++] = c; + } + } + + // The new length is <= the old one. + dataBufferPos = i; + } + + /** + * Convert the data buffer to a string. + */ + private String dataBufferToString() + { + String s = new String(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + return s; + } + + /** + * Flush the contents of the data buffer to the handler, as + * appropriate, and reset the buffer for new input. + */ + private void dataBufferFlush() + throws SAXException + { + if (currentElementContent == CONTENT_ELEMENTS + && dataBufferPos > 0 + && !inCDATA) + { + // We can't just trust the buffer to be whitespace, there + // are (error) cases when it isn't + for (int i = 0; i < dataBufferPos; i++) + { + if (!isWhitespace(dataBuffer[i])) + { + handler.charData(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + if (dataBufferPos > 0) + { + handler.ignorableWhitespace(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + else if (dataBufferPos > 0) + { + handler.charData(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + + /** + * Require a string to appear, or throw an exception. + *

Precondition: Entity expansion is not required. + *

Precondition: data buffer has no characters that + * will get sent to the application. + */ + private void require(String delim) + throws SAXException, IOException + { + int length = delim.length(); + char[] ch; + + if (length < dataBuffer.length) + { + ch = dataBuffer; + delim.getChars(0, length, ch, 0); + } + else + { + ch = delim.toCharArray(); + } + + if (USE_CHEATS && length <= (readBufferLength - readBufferPos)) + { + int offset = readBufferPos; + + for (int i = 0; i < length; i++, offset++) + { + if (ch[i] != readBuffer[offset]) + { + error ("required string", null, delim); + } + } + readBufferPos = offset; + + } + else + { + for (int i = 0; i < length; i++) + { + require(ch[i]); + } + } + } + + /** + * Require a character to appear, or throw an exception. + */ + private void require(char delim) + throws SAXException, IOException + { + char c = readCh(); + + if (c != delim) + { + error("required character", c, Character.toString(delim)); + } + } + + /** + * Create an interned string from a character array. + * Ælfred uses this method to create an interned version + * of all names and name tokens, so that it can test equality + * with == instead of String.equals (). + * + *

This is much more efficient than constructing a non-interned + * string first, and then interning it. + * + * @param ch an array of characters for building the string. + * @param start the starting position in the array. + * @param length the number of characters to place in the string. + * @return an interned string. + * @see #intern (String) + * @see java.lang.String#intern + */ + public String intern(char[] ch, int start, int length) + { + int index = 0; + int hash = 0; + Object[] bucket; + + // Generate a hash code. This is a widely used string hash, + // often attributed to Brian Kernighan. + for (int i = start; i < start + length; i++) + { + hash = 31 * hash + ch[i]; + } + hash = (hash & 0x7fffffff) % SYMBOL_TABLE_LENGTH; + + // Get the bucket -- consists of {array,String} pairs + if ((bucket = symbolTable[hash]) == null) + { + // first string in this bucket + bucket = new Object[8]; + + // Search for a matching tuple, and + // return the string if we find one. + } + else + { + while (index < bucket.length) + { + char[] chFound = (char[]) bucket[index]; + + // Stop when we hit an empty entry. + if (chFound == null) + { + break; + } + + // If they're the same length, check for a match. + if (chFound.length == length) + { + for (int i = 0; i < chFound.length; i++) + { + // continue search on failure + if (ch[start + i] != chFound[i]) + { + break; + } + else if (i == length - 1) + { + // That's it, we have a match! + return (String) bucket[index + 1]; + } + } + } + index += 2; + } + // Not found -- we'll have to add it. + + // Do we have to grow the bucket? + bucket = (Object[]) extendArray(bucket, bucket.length, index); + } + symbolTable[hash] = bucket; + + // OK, add it to the end of the bucket -- "local" interning. + // Intern "globally" to let applications share interning benefits. + // That is, "!=" and "==" work on our strings, not just equals(). + String s = new String(ch, start, length).intern(); + bucket[index] = s.toCharArray(); + bucket[index + 1] = s; + return s; + } + + /** + * Ensure the capacity of an array, allocating a new one if + * necessary. Usually extends only for name hash collisions. + */ + private Object extendArray(Object array, int currentSize, int requiredSize) + { + if (requiredSize < currentSize) + { + return array; + } + else + { + Object newArray = null; + int newSize = currentSize * 2; + + if (newSize <= requiredSize) + { + newSize = requiredSize + 1; + } + + if (array instanceof char[]) + { + newArray = new char[newSize]; + } + else if (array instanceof Object[]) + { + newArray = new Object[newSize]; + } + else + { + throw new RuntimeException(); + } + + System.arraycopy(array, 0, newArray, 0, currentSize); + return newArray; + } + } + + ////////////////////////////////////////////////////////////////////// + // XML query routines. + ////////////////////////////////////////////////////////////////////// + + boolean isStandalone() + { + return docIsStandalone; + } + + // + // Elements + // + + private int getContentType(ElementDecl element, int defaultType) + { + int retval; + + if (element == null) + { + return defaultType; + } + retval = element.contentType; + if (retval == CONTENT_UNDECLARED) + { + retval = defaultType; + } + return retval; + } + + /** + * Look up the content type of an element. + * @param name The element type name. + * @return An integer constant representing the content type. + * @see #CONTENT_UNDECLARED + * @see #CONTENT_ANY + * @see #CONTENT_EMPTY + * @see #CONTENT_MIXED + * @see #CONTENT_ELEMENTS + */ + public int getElementContentType(String name) + { + ElementDecl element = (ElementDecl) elementInfo.get(name); + return getContentType(element, CONTENT_UNDECLARED); + } + + /** + * Register an element. + * Array format: + * [0] element type name + * [1] content model (mixed, elements only) + * [2] attribute hash table + */ + private void setElement(String name, int contentType, + String contentModel, HashMap attributes) + throws SAXException + { + if (skippedPE) + { + return; + } + + ElementDecl element = (ElementDecl) elementInfo.get(name); + + // first or for this type? + if (element == null) + { + element = new ElementDecl(); + element.contentType = contentType; + element.contentModel = contentModel; + element.attributes = attributes; + elementInfo.put(name, element); + return; + } + + // declaration? + if (contentType != CONTENT_UNDECLARED) + { + // ... following an associated + if (element.contentType == CONTENT_UNDECLARED) + { + element.contentType = contentType; + element.contentModel = contentModel; + } + else + { + // VC: Unique Element Type Declaration + handler.verror("multiple declarations for element type: " + + name); + } + } + + // first , before ? + else if (attributes != null) + { + element.attributes = attributes; + } + } + + /** + * Look up the attribute hash table for an element. + * The hash table is the second item in the element array. + */ + private HashMap getElementAttributes(String name) + { + ElementDecl element = (ElementDecl) elementInfo.get(name); + return (element == null) ? null : element.attributes; + } + + // + // Attributes + // + + /** + * Get the declared attributes for an element type. + * @param elname The name of the element type. + * @return An iterator over all the attributes declared for + * a specific element type. The results will be valid only + * after the DTD (if any) has been parsed. + * @see #getAttributeType + * @see #getAttributeEnumeration + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + * @see #getAttributeExpandedValue + */ + private Iterator declaredAttributes(ElementDecl element) + { + HashMap attlist; + + if (element == null) + { + return null; + } + if ((attlist = element.attributes) == null) + { + return null; + } + return attlist.keySet().iterator(); + } + + /** + * Get the declared attributes for an element type. + * @param elname The name of the element type. + * @return An iterator over all the attributes declared for + * a specific element type. The results will be valid only + * after the DTD (if any) has been parsed. + * @see #getAttributeType + * @see #getAttributeEnumeration + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + * @see #getAttributeExpandedValue + */ + public Iterator declaredAttributes(String elname) + { + return declaredAttributes((ElementDecl) elementInfo.get(elname)); + } + + /** + * Retrieve the declared type of an attribute. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return An interend string denoting the type, or null + * indicating an undeclared attribute. + */ + public String getAttributeType(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? null : attribute.type; + } + + /** + * Retrieve the allowed values for an enumerated attribute type. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return A string containing the token list. + */ + public String getAttributeEnumeration(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + // assert: attribute.enumeration is "ENUMERATION" or "NOTATION" + return (attribute == null) ? null : attribute.enumeration; + } + + /** + * Retrieve the default value of a declared attribute. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return The default value, or null if the attribute was + * #IMPLIED or simply undeclared and unspecified. + * @see #getAttributeExpandedValue + */ + public String getAttributeDefaultValue(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? null : attribute.value; + } + + /* + +// FIXME: Leaving this in, until W3C finally resolves the confusion +// between parts of the XML 2nd REC about when entity declararations +// are guaranteed to be known. Current code matches what section 5.1 +// (conformance) describes, but some readings of the self-contradicting +// text in 4.1 (the "Entity Declared" WFC and VC) seem to expect that +// attribute expansion/normalization must be deferred in some cases +// (just TRY to identify them!). + + * Retrieve the expanded value of a declared attribute. + *

General entities (and char refs) will be expanded (once). + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return The expanded default value, or null if the attribute was + * #IMPLIED or simply undeclared + * @see #getAttributeDefaultValue + public String getAttributeExpandedValue (String name, String aname) + throws Exception + { + AttributeDecl attribute = getAttribute (name, aname); + + if (attribute == null) { + return null; + } else if (attribute.defaultValue == null && attribute.value != null) { + // we MUST use the same buf for both quotes else the literal + // can't be properly terminated + char buf [] = new char [1]; + int flags = LIT_ENTITY_REF | LIT_ATTRIBUTE; + String type = getAttributeType (name, aname); + + if (type != "CDATA" && type != null) + flags |= LIT_NORMALIZE; + buf [0] = '"'; + pushCharArray (null, buf, 0, 1); + pushString (null, attribute.value); + pushCharArray (null, buf, 0, 1); + attribute.defaultValue = readLiteral (flags); + } + return attribute.defaultValue; + } + */ + + /** + * Retrieve the default value mode of a declared attribute. + * @see #ATTRIBUTE_DEFAULT_SPECIFIED + * @see #ATTRIBUTE_DEFAULT_IMPLIED + * @see #ATTRIBUTE_DEFAULT_REQUIRED + * @see #ATTRIBUTE_DEFAULT_FIXED + */ + public int getAttributeDefaultValueType(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? ATTRIBUTE_DEFAULT_UNDECLARED : + attribute.valueType; + } + + /** + * Register an attribute declaration for later retrieval. + * Format: + * - String type + * - String default value + * - int value type + * - enumeration + * - processed default value + */ + private void setAttribute(String elName, String name, String type, + String enumeration, String value, int valueType) + throws Exception + { + HashMap attlist; + + if (skippedPE) + { + return; + } + + // Create a new hashtable if necessary. + attlist = getElementAttributes(elName); + if (attlist == null) + { + attlist = new HashMap(); + } + + // ignore multiple attribute declarations! + if (attlist.get(name) != null) + { + // warn ... + return; + } + else + { + AttributeDecl attribute = new AttributeDecl(); + attribute.type = type; + attribute.value = value; + attribute.valueType = valueType; + attribute.enumeration = enumeration; + attlist.put(name, attribute); + + // save; but don't overwrite any existing + setElement(elName, CONTENT_UNDECLARED, null, attlist); + } + } + + /** + * Retrieve the attribute declaration for the given element name and name. + */ + private AttributeDecl getAttribute(String elName, String name) + { + HashMap attlist = getElementAttributes(elName); + return (attlist == null) ? null : (AttributeDecl) attlist.get(name); + } + + // + // Entities + // + + /** + * Find the type of an entity. + * @returns An integer constant representing the entity type. + * @see #ENTITY_UNDECLARED + * @see #ENTITY_INTERNAL + * @see #ENTITY_NDATA + * @see #ENTITY_TEXT + */ + public int getEntityType(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? ENTITY_UNDECLARED : entity.type; + } + + /** + * Return an external entity's identifiers. + * @param ename The name of the external entity. + * @return The entity's public identifier, system identifier, and base URI. + * Null if the entity was not declared as an external entity. + * @see #getEntityType + */ + public ExternalIdentifiers getEntityIds(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? null : entity.ids; + } + + /** + * Return an internal entity's replacement text. + * @param ename The name of the internal entity. + * @return The entity's replacement text, or null if + * the entity was not declared as an internal entity. + * @see #getEntityType + */ + public String getEntityValue(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? null : entity.value; + } + + /** + * Register an entity declaration for later retrieval. + */ + private void setInternalEntity(String eName, String value) + throws SAXException + { + if (skippedPE) + { + return; + } + + if (entityInfo.get(eName) == null) + { + EntityInfo entity = new EntityInfo(); + entity.type = ENTITY_INTERNAL; + entity.value = value; + entityInfo.put(eName, entity); + } + if (handler.stringInterning) + { + if ("lt" == eName || "gt" == eName || "quot" == eName + || "apos" == eName || "amp" == eName) + { + return; + } + } + else + { + if ("lt".equals(eName) || "gt".equals(eName) || "quot".equals(eName) + || "apos".equals(eName) || "amp".equals(eName)) + { + return; + } + } + handler.getDeclHandler().internalEntityDecl(eName, value); + } + + /** + * Register an external entity declaration for later retrieval. + */ + private void setExternalEntity(String eName, int eClass, + ExternalIdentifiers ids, String nName) + { + if (entityInfo.get(eName) == null) + { + EntityInfo entity = new EntityInfo(); + entity.type = eClass; + entity.ids = ids; + entity.notationName = nName; + entityInfo.put(eName, entity); + } + } + + // + // Notations. + // + + /** + * Report a notation declaration, checking for duplicates. + */ + private void setNotation(String nname, ExternalIdentifiers ids) + throws SAXException + { + if (skippedPE) + { + return; + } + + handler.notationDecl(nname, ids.publicId, ids.systemId, ids.baseUri); + if (notationInfo.get(nname) == null) + { + notationInfo.put(nname, nname); + } + else + { + // VC: Unique Notation Name + handler.verror("Duplicate notation name decl: " + nname); + } + } + + // + // Location. + // + + /** + * Return the current line number. + */ + public int getLineNumber() + { + return line; + } + + /** + * Return the current column number. + */ + public int getColumnNumber() + { + return column; + } + + ////////////////////////////////////////////////////////////////////// + // High-level I/O. + ////////////////////////////////////////////////////////////////////// + + /** + * Read a single character from the readBuffer. + *

The readDataChunk () method maintains the buffer. + *

If we hit the end of an entity, try to pop the stack and + * keep going. + *

(This approach doesn't really enforce XML's rules about + * entity boundaries, but this is not currently a validating + * parser). + *

This routine also attempts to keep track of the current + * position in external entities, but it's not entirely accurate. + * @return The next available input character. + * @see #unread (char) + * @see #readDataChunk + * @see #readBuffer + * @see #line + * @return The next character from the current input source. + */ + private char readCh() + throws SAXException, IOException + { + // As long as there's nothing in the + // read buffer, try reading more data + // (for an external entity) or popping + // the entity stack (for either). + while (readBufferPos >= readBufferLength) + { + switch (sourceType) + { + case INPUT_READER: + case INPUT_STREAM: + readDataChunk(); + while (readBufferLength < 1) + { + popInput(); + if (readBufferLength < 1) + { + readDataChunk(); + } + } + break; + + default: + + popInput(); + break; + } + } + + char c = readBuffer[readBufferPos++]; + + if (c == '\n') + { + line++; + column = 0; + } + else + { + if (c == '<') + { + /* the most common return to parseContent () ... NOP */ + } + else if (((c < 0x0020 && (c != '\t') && (c != '\r')) || c > 0xFFFD) + || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085) + && xmlVersion == XML_11)) + { + error("illegal XML character U+" + Integer.toHexString(c)); + } + + // If we're in the DTD and in a context where PEs get expanded, + // do so ... 1/14/2000 errata identify those contexts. There + // are also spots in the internal subset where PE refs are fatal + // errors, hence yet another flag. + else if (c == '%' && expandPE) + { + if (peIsError) + { + error("PE reference within decl in internal subset."); + } + parsePEReference(); + return readCh(); + } + column++; + } + + return c; + } + + /** + * Push a single character back onto the current input stream. + *

This method usually pushes the character back onto + * the readBuffer. + *

I don't think that this would ever be called with + * readBufferPos = 0, because the methods always reads a character + * before unreading it, but just in case, I've added a boundary + * condition. + * @param c The character to push back. + * @see #readCh + * @see #unread (char[]) + * @see #readBuffer + */ + private void unread(char c) + throws SAXException + { + // Normal condition. + if (c == '\n') + { + line--; + column = -1; + } + if (readBufferPos > 0) + { + readBuffer[--readBufferPos] = c; + } + else + { + pushString(null, Character.toString(c)); + } + } + + /** + * Push a char array back onto the current input stream. + *

NOTE: you must never push back characters that you + * haven't actually read: use pushString () instead. + * @see #readCh + * @see #unread (char) + * @see #readBuffer + * @see #pushString + */ + private void unread(char[] ch, int length) + throws SAXException + { + for (int i = 0; i < length; i++) + { + if (ch[i] == '\n') + { + line--; + column = -1; + } + } + if (length < readBufferPos) + { + readBufferPos -= length; + } + else + { + pushCharArray(null, ch, 0, length); + } + } + + /** + * Push, or skip, a new external input source. + * The source will be some kind of parsed entity, such as a PE + * (including the external DTD subset) or content for the body. + * + * @param url The java.net.URL object for the entity. + * @see SAXDriver#resolveEntity + * @see #pushString + * @see #sourceType + * @see #pushInput + * @see #detectEncoding + * @see #sourceType + * @see #readBuffer + */ + private void pushURL(boolean isPE, + String ename, + ExternalIdentifiers ids, + Reader reader, + InputStream stream, + String encoding, + boolean doResolve) + throws SAXException, IOException + { + boolean ignoreEncoding; + String systemId; + InputSource source; + + if (!isPE) + { + dataBufferFlush(); + } + + scratch.setPublicId(ids.publicId); + scratch.setSystemId(ids.systemId); + + // See if we should skip or substitute the entity. + // If we're not skipping, resolving reports startEntity() + // and updates the (handler's) stack of URIs. + if (doResolve) + { + // assert (stream == null && reader == null && encoding == null) + source = handler.resolveEntity(isPE, ename, scratch, ids.baseUri); + if (source == null) + { + handler.warn("skipping entity: " + ename); + handler.skippedEntity(ename); + if (isPE) + { + skippedPE = true; + } + return; + } + + // we might be using alternate IDs/encoding + systemId = source.getSystemId(); + // The following warning and setting systemId was deleted bcause + // the application has the option of not setting systemId + // provided that it has set the characte/byte stream. + /* + if (systemId == null) { + handler.warn ("missing system ID, using " + ids.systemId); + systemId = ids.systemId; + } + */ + } + else + { + // "[document]", or "[dtd]" via getExternalSubset() + scratch.setCharacterStream(reader); + scratch.setByteStream(stream); + scratch.setEncoding(encoding); + source = scratch; + systemId = ids.systemId; + if (handler.stringInterning) + { + handler.startExternalEntity(ename, systemId, + "[document]" == ename); + } + else + { + handler.startExternalEntity(ename, systemId, + "[document]".equals(ename)); + } + } + + // we may have been given I/O streams directly + if (source.getCharacterStream() != null) + { + if (source.getByteStream() != null) + error("InputSource has two streams!"); + reader = source.getCharacterStream(); + } + else if (source.getByteStream() != null) + { + encoding = source.getEncoding(); + if (encoding == null) + { + stream = source.getByteStream(); + } + else + { + try + { + reader = new InputStreamReader(source.getByteStream(), + encoding); + } + catch (IOException e) + { + stream = source.getByteStream(); + } + } + } + else if (systemId == null) + { + error("InputSource has no URI!"); + } + scratch.setCharacterStream(null); + scratch.setByteStream(null); + scratch.setEncoding(null); + + // Push the existing status. + pushInput(ename); + + // Create a new read buffer. + // (Note the four-character margin) + readBuffer = new char[READ_BUFFER_MAX + 4]; + readBufferPos = 0; + readBufferLength = 0; + readBufferOverflow = -1; + is = null; + line = 1; + column = 0; + currentByteCount = 0; + + // If there's an explicit character stream, just + // ignore encoding declarations. + if (reader != null) + { + sourceType = INPUT_READER; + this.reader = reader; + tryEncodingDecl(true); + return; + } + + // Else we handle the conversion, and need to ensure + // it's done right. + sourceType = INPUT_STREAM; + if (stream != null) + { + is = stream; + } + else + { + // We have to open our own stream to the URL. + URL url = new URL(systemId); + + externalEntity = url.openConnection(); + externalEntity.connect(); + is = externalEntity.getInputStream(); + } + + // If we get to here, there must be + // an InputStream available. + if (!is.markSupported()) + { + is = new BufferedInputStream(is); + } + + // Get any external encoding label. + if (encoding == null && externalEntity != null) + { + // External labels can be untrustworthy; filesystems in + // particular often have the wrong default for content + // that wasn't locally originated. Those we autodetect. + if (!"file".equals(externalEntity.getURL().getProtocol())) + { + int temp; + + // application/xml;charset=something;otherAttr=... + // ... with many variants on 'something' + encoding = externalEntity.getContentType(); + + // MHK code (fix for Saxon 5.5.1/007): + // protect against encoding==null + if (encoding == null) + { + temp = -1; + } + else + { + temp = encoding.indexOf("charset"); + } + + // RFC 2376 sez MIME text defaults to ASCII, but since the + // JDK will create a MIME type out of thin air, we always + // autodetect when there's no explicit charset attribute. + if (temp < 0) + { + encoding = null; // autodetect + } + else + { + // only this one attribute + if ((temp = encoding.indexOf(';')) > 0) + { + encoding = encoding.substring(0, temp); + } + + if ((temp = encoding.indexOf('=', temp + 7)) > 0) + { + encoding = encoding.substring(temp + 1); + + // attributes can have comment fields (RFC 822) + if ((temp = encoding.indexOf('(')) > 0) + { + encoding = encoding.substring(0, temp); + } + // ... and values may be quoted + if ((temp = encoding.indexOf('"')) > 0) + { + encoding = + encoding.substring(temp + 1, + encoding.indexOf('"', temp + 2)); + } + encoding = encoding.trim(); + } + else + { + handler.warn("ignoring illegal MIME attribute: " + + encoding); + encoding = null; + } + } + } + } + + // if we got an external encoding label, use it ... + if (encoding != null) + { + this.encoding = ENCODING_EXTERNAL; + setupDecoding(encoding); + ignoreEncoding = true; + + // ... else autodetect from first bytes. + } + else + { + detectEncoding(); + ignoreEncoding = false; + } + + // Read any XML or text declaration. + // If we autodetected, it may tell us the "real" encoding. + try + { + tryEncodingDecl(ignoreEncoding); + } + catch (UnsupportedEncodingException x) + { + encoding = x.getMessage(); + + // if we don't handle the declared encoding, + // try letting a JVM InputStreamReader do it + try + { + if (sourceType != INPUT_STREAM) + { + throw x; + } + + is.reset(); + readBufferPos = 0; + readBufferLength = 0; + readBufferOverflow = -1; + line = 1; + currentByteCount = column = 0; + + sourceType = INPUT_READER; + this.reader = new InputStreamReader(is, encoding); + is = null; + + tryEncodingDecl(true); + + } + catch (IOException e) + { + error("unsupported text encoding", + encoding, + null); + } + } + } + + /** + * Check for an encoding declaration. This is the second part of the + * XML encoding autodetection algorithm, relying on detectEncoding to + * get to the point that this part can read any encoding declaration + * in the document (using only US-ASCII characters). + * + *

Because this part starts to fill parser buffers with this data, + * it's tricky to setup a reader so that Java's built-in decoders can be + * used for the character encodings that aren't built in to this parser + * (such as EUC-JP, KOI8-R, Big5, etc). + * + * @return any encoding in the declaration, uppercased; or null + * @see detectEncoding + */ + private String tryEncodingDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + // Read the XML/text declaration. + if (tryRead(" 0) + { + return parseTextDecl(ignoreEncoding); + } + else + { + return parseXMLDecl(ignoreEncoding); + } + } + else + { + // or similar + unread('l'); + unread('m'); + unread('x'); + unread('?'); + unread('<'); + } + } + return null; + } + + /** + * Attempt to detect the encoding of an entity. + *

The trick here (as suggested in the XML standard) is that + * any entity not in UTF-8, or in UCS-2 with a byte-order mark, + * must begin with an XML declaration or an encoding + * declaration; we simply have to look for "<?xml" in various + * encodings. + *

This method has no way to distinguish among 8-bit encodings. + * Instead, it sets up for UTF-8, then (possibly) revises its assumption + * later in setupDecoding (). Any ASCII-derived 8-bit encoding + * should work, but most will be rejected later by setupDecoding (). + * @see #tryEncoding (byte[], byte, byte, byte, byte) + * @see #tryEncoding (byte[], byte, byte) + * @see #setupDecoding + */ + private void detectEncoding() + throws SAXException, IOException + { + byte[] signature = new byte[4]; + + // Read the first four bytes for + // autodetection. + is.mark(4); + is.read(signature); + is.reset(); + + // + // FIRST: four byte encodings (who uses these?) + // + if (tryEncoding(signature, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x3c)) + { + // UCS-4 must begin with "Utility routine for detectEncoding (). + *

Always looks for some part of "Looks for a UCS-2 byte-order mark. + *

Utility routine for detectEncoding (). + * @param sig The first four bytes read. + * @param b1 The first byte of the signature + * @param b2 The second byte of the signature + * @see #detectEncoding + */ + private static boolean tryEncoding(byte[] sig, byte b1, byte b2) + { + return ((sig[0] == b1) && (sig[1] == b2)); + } + + /** + * This method pushes a string back onto input. + *

It is useful either as the expansion of an internal entity, + * or for backtracking during the parse. + *

Call pushCharArray () to do the actual work. + * @param s The string to push back onto input. + * @see #pushCharArray + */ + private void pushString(String ename, String s) + throws SAXException + { + char[] ch = s.toCharArray(); + pushCharArray(ename, ch, 0, ch.length); + } + + /** + * Push a new internal input source. + *

This method is useful for expanding an internal entity, + * or for unreading a string of characters. It creates a new + * readBuffer containing the characters in the array, instead + * of characters converted from an input byte stream. + * @param ch The char array to push. + * @see #pushString + * @see #pushURL + * @see #readBuffer + * @see #sourceType + * @see #pushInput + */ + private void pushCharArray(String ename, char[] ch, int start, int length) + throws SAXException + { + // Push the existing status + pushInput(ename); + if (ename != null && doReport) + { + dataBufferFlush(); + handler.startInternalEntity(ename); + } + sourceType = INPUT_INTERNAL; + readBuffer = ch; + readBufferPos = start; + readBufferLength = length; + readBufferOverflow = -1; + } + + /** + * Save the current input source onto the stack. + *

This method saves all of the global variables associated with + * the current input source, so that they can be restored when a new + * input source has finished. It also tests for entity recursion. + *

The method saves the following global variables onto a stack + * using a fixed-length array: + *

    + *
  1. sourceType + *
  2. externalEntity + *
  3. readBuffer + *
  4. readBufferPos + *
  5. readBufferLength + *
  6. line + *
  7. encoding + *
+ * @param ename The name of the entity (if any) causing the new input. + * @see #popInput + * @see #sourceType + * @see #externalEntity + * @see #readBuffer + * @see #readBufferPos + * @see #readBufferLength + * @see #line + * @see #encoding + */ + private void pushInput(String ename) + throws SAXException + { + // Check for entity recursion. + if (ename != null) + { + Iterator entities = entityStack.iterator(); + while (entities.hasNext()) + { + String e = (String) entities.next(); + if (e != null && e == ename) + { + error("recursive reference to entity", ename, null); + } + } + } + entityStack.addLast(ename); + + // Don't bother if there is no current input. + if (sourceType == INPUT_NONE) + { + return; + } + + // Set up a snapshot of the current + // input source. + Input input = new Input(); + + input.sourceType = sourceType; + input.externalEntity = externalEntity; + input.readBuffer = readBuffer; + input.readBufferPos = readBufferPos; + input.readBufferLength = readBufferLength; + input.line = line; + input.encoding = encoding; + input.readBufferOverflow = readBufferOverflow; + input.is = is; + input.currentByteCount = currentByteCount; + input.column = column; + input.reader = reader; + + // Push it onto the stack. + inputStack.addLast(input); + } + + /** + * Restore a previous input source. + *

This method restores all of the global variables associated with + * the current input source. + * @exception java.io.EOFException + * If there are no more entries on the input stack. + * @see #pushInput + * @see #sourceType + * @see #externalEntity + * @see #readBuffer + * @see #readBufferPos + * @see #readBufferLength + * @see #line + * @see #encoding + */ + private void popInput() + throws SAXException, IOException + { + String ename = (String) entityStack.removeLast(); + + if (ename != null && doReport) + { + dataBufferFlush(); + } + switch (sourceType) + { + case INPUT_STREAM: + handler.endExternalEntity(ename); + is.close(); + break; + case INPUT_READER: + handler.endExternalEntity(ename); + reader.close(); + break; + case INPUT_INTERNAL: + if (ename != null && doReport) + { + handler.endInternalEntity(ename); + } + break; + } + + // Throw an EOFException if there + // is nothing else to pop. + if (inputStack.isEmpty()) + { + throw new EOFException("no more input"); + } + + Input input = (Input) inputStack.removeLast(); + + sourceType = input.sourceType; + externalEntity = input.externalEntity; + readBuffer = input.readBuffer; + readBufferPos = input.readBufferPos; + readBufferLength = input.readBufferLength; + line = input.line; + encoding = input.encoding; + readBufferOverflow = input.readBufferOverflow; + is = input.is; + currentByteCount = input.currentByteCount; + column = input.column; + reader = input.reader; + } + + /** + * Return true if we can read the expected character. + *

Note that the character will be removed from the input stream + * on success, but will be put back on failure. Do not attempt to + * read the character again if the method succeeds. + * @param delim The character that should appear next. For a + * insensitive match, you must supply this in upper-case. + * @return true if the character was successfully read, or false if + * it was not. + * @see #tryRead (String) + */ + private boolean tryRead(char delim) + throws SAXException, IOException + { + char c; + + // Read the character + c = readCh(); + + // Test for a match, and push the character + // back if the match fails. + if (c == delim) + { + return true; + } + else + { + unread(c); + return false; + } + } + + /** + * Return true if we can read the expected string. + *

This is simply a convenience method. + *

Note that the string will be removed from the input stream + * on success, but will be put back on failure. Do not attempt to + * read the string again if the method succeeds. + *

This method will push back a character rather than an + * array whenever possible (probably the majority of cases). + * @param delim The string that should appear next. + * @return true if the string was successfully read, or false if + * it was not. + * @see #tryRead (char) + */ + private boolean tryRead(String delim) + throws SAXException, IOException + { + return tryRead(delim.toCharArray()); + } + + private boolean tryRead(char[] ch) + throws SAXException, IOException + { + char c; + + // Compare the input, character- + // by character. + + for (int i = 0; i < ch.length; i++) + { + c = readCh(); + if (c != ch[i]) + { + unread(c); + if (i != 0) + { + unread(ch, i); + } + return false; + } + } + return true; + } + + /** + * Return true if we can read some whitespace. + *

This is simply a convenience method. + *

This method will push back a character rather than an + * array whenever possible (probably the majority of cases). + * @return true if whitespace was found. + */ + private boolean tryWhitespace() + throws SAXException, IOException + { + char c; + c = readCh(); + if (isWhitespace(c)) + { + skipWhitespace(); + return true; + } + else + { + unread(c); + return false; + } + } + + /** + * Read all data until we find the specified string. + * This is useful for scanning CDATA sections and PIs. + *

This is inefficient right now, since it calls tryRead () + * for every character. + * @param delim The string delimiter + * @see #tryRead (String, boolean) + * @see #readCh + */ + private void parseUntil(String delim) + throws SAXException, IOException + { + parseUntil(delim.toCharArray()); + } + + private void parseUntil(char[] delim) + throws SAXException, IOException + { + char c; + int startLine = line; + + try + { + while (!tryRead(delim)) + { + c = readCh(); + dataBufferAppend(c); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter " + + "(started on line " + startLine + + ')', null, new String(delim)); + } + } + + ////////////////////////////////////////////////////////////////////// + // Low-level I/O. + ////////////////////////////////////////////////////////////////////// + + /** + * Prefetch US-ASCII XML/text decl from input stream into read buffer. + * Doesn't buffer more than absolutely needed, so that when an encoding + * decl says we need to create an InputStreamReader, we can discard our + * buffer and reset(). Caller knows the first chars of the decl exist + * in the input stream. + */ + private void prefetchASCIIEncodingDecl() + throws SAXException, IOException + { + int ch; + readBufferPos = readBufferLength = 0; + + is.mark(readBuffer.length); + while (true) + { + ch = is.read(); + readBuffer[readBufferLength++] = (char) ch; + switch (ch) + { + case (int) '>': + return; + case -1: + error("file ends before end of XML or encoding declaration.", + null, "?>"); + } + if (readBuffer.length == readBufferLength) + { + error("unfinished XML or encoding declaration"); + } + } + } + + /** + * Read a chunk of data from an external input source. + *

This is simply a front-end that fills the rawReadBuffer + * with bytes, then calls the appropriate encoding handler. + * @see #encoding + * @see #rawReadBuffer + * @see #readBuffer + * @see #filterCR + * @see #copyUtf8ReadBuffer + * @see #copyIso8859_1ReadBuffer + * @see #copyUcs_2ReadBuffer + * @see #copyUcs_4ReadBuffer + */ + private void readDataChunk() + throws SAXException, IOException + { + int count; + + // See if we have any overflow (filterCR sets for CR at end) + if (readBufferOverflow > -1) + { + readBuffer[0] = (char) readBufferOverflow; + readBufferOverflow = -1; + readBufferPos = 1; + sawCR = true; + } + else + { + readBufferPos = 0; + sawCR = false; + } + + // input from a character stream. + if (sourceType == INPUT_READER) + { + count = reader.read(readBuffer, + readBufferPos, READ_BUFFER_MAX - readBufferPos); + if (count < 0) + { + readBufferLength = readBufferPos; + } + else + { + readBufferLength = readBufferPos + count; + } + if (readBufferLength > 0) + { + filterCR(count >= 0); + } + sawCR = false; + return; + } + + // Read as many bytes as possible into the raw buffer. + count = is.read(rawReadBuffer, 0, READ_BUFFER_MAX); + + // Dispatch to an encoding-specific reader method to populate + // the readBuffer. In most parser speed profiles, these routines + // show up at the top of the CPU usage chart. + if (count > 0) + { + switch (encoding) + { + // one byte builtins + case ENCODING_ASCII: + copyIso8859_1ReadBuffer(count, (char) 0x0080); + break; + case ENCODING_UTF_8: + copyUtf8ReadBuffer(count); + break; + case ENCODING_ISO_8859_1: + copyIso8859_1ReadBuffer(count, (char) 0); + break; + + // two byte builtins + case ENCODING_UCS_2_12: + copyUcs2ReadBuffer(count, 8, 0); + break; + case ENCODING_UCS_2_21: + copyUcs2ReadBuffer(count, 0, 8); + break; + + // four byte builtins + case ENCODING_UCS_4_1234: + copyUcs4ReadBuffer(count, 24, 16, 8, 0); + break; + case ENCODING_UCS_4_4321: + copyUcs4ReadBuffer(count, 0, 8, 16, 24); + break; + case ENCODING_UCS_4_2143: + copyUcs4ReadBuffer(count, 16, 24, 0, 8); + break; + case ENCODING_UCS_4_3412: + copyUcs4ReadBuffer(count, 8, 0, 24, 16); + break; + } + } + else + { + readBufferLength = readBufferPos; + } + + readBufferPos = 0; + + // Filter out all carriage returns if we've seen any + // (including any saved from a previous read) + if (sawCR) + { + filterCR(count >= 0); + sawCR = false; + + // must actively report EOF, lest some CRs get lost. + if (readBufferLength == 0 && count >= 0) + { + readDataChunk(); + } + } + + if (count > 0) + { + currentByteCount += count; + } + } + + /** + * Filter carriage returns in the read buffer. + * CRLF becomes LF; CR becomes LF. + * @param moreData true iff more data might come from the same source + * @see #readDataChunk + * @see #readBuffer + * @see #readBufferOverflow + */ + private void filterCR(boolean moreData) + { + int i, j; + + readBufferOverflow = -1; + +loop: + for (i = j = readBufferPos; j < readBufferLength; i++, j++) + { + switch (readBuffer[j]) + { + case '\r': + if (j == readBufferLength - 1) + { + if (moreData) + { + readBufferOverflow = '\r'; + readBufferLength--; + } + else // CR at end of buffer + { + readBuffer[i++] = '\n'; + } + break loop; + } + else if (readBuffer[j + 1] == '\n') + { + j++; + } + readBuffer[i] = '\n'; + break; + + case '\n': + default: + readBuffer[i] = readBuffer[j]; + break; + } + } + readBufferLength = i; + } + + /** + * Convert a buffer of UTF-8-encoded bytes into UTF-16 characters. + *

When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + *

Note that as of Unicode 3.1, good practice became a requirement, + * so that each Unicode character has exactly one UTF-8 representation. + * @param count The number of bytes to convert. + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + * @see #getNextUtf8Byte + */ + private void copyUtf8ReadBuffer(int count) + throws SAXException, IOException + { + int i = 0; + int j = readBufferPos; + int b1; + char c = 0; + + /* + // check once, so the runtime won't (if it's smart enough) + if (count < 0 || count > rawReadBuffer.length) + throw new ArrayIndexOutOfBoundsException (Integer.toString (count)); + */ + + while (i < count) + { + b1 = rawReadBuffer[i++]; + + // Determine whether we are dealing + // with a one-, two-, three-, or four- + // byte sequence. + if (b1 < 0) + { + if ((b1 & 0xe0) == 0xc0) + { + // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + c = (char) (((b1 & 0x1f) << 6) + | getNextUtf8Byte(i++, count)); + if (c < 0x0080) + { + encodingError("Illegal two byte UTF-8 sequence", + c, 0); + } + + //Sec 2.11 + // [1] the two-character sequence #xD #xA + // [2] the two-character sequence #xD #x85 + if ((c == 0x0085 || c == 0x000a) && sawCR) + { + continue; + } + + // Sec 2.11 + // [3] the single character #x85 + + if (c == 0x0085 && xmlVersion == XML_11) + { + readBuffer[j++] = '\r'; + } + } + else if ((b1 & 0xf0) == 0xe0) + { + // 3-byte sequence: + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + // most CJKV characters + c = (char) (((b1 & 0x0f) << 12) | + (getNextUtf8Byte(i++, count) << 6) | + getNextUtf8Byte(i++, count)); + //sec 2.11 + //[4] the single character #x2028 + if (c == 0x2028 && xmlVersion == XML_11) + { + readBuffer[j++] = '\r'; + sawCR = true; + continue; + } + if (c < 0x0800 || (c >= 0xd800 && c <= 0xdfff)) + { + encodingError("Illegal three byte UTF-8 sequence", + c, 0); + } + } + else if ((b1 & 0xf8) == 0xf0) + { + // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // "Surrogate Pairs" ... from the "Astral Planes" + // Unicode 3.1 assigned the first characters there + int iso646 = b1 & 07; + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + + if (iso646 <= 0xffff) + { + encodingError("Illegal four byte UTF-8 sequence", + iso646, 0); + } + else + { + if (iso646 > 0x0010ffff) + { + encodingError("UTF-8 value out of range for Unicode", + iso646, 0); + } + iso646 -= 0x010000; + readBuffer[j++] = (char) (0xd800 | (iso646 >> 10)); + readBuffer[j++] = (char) (0xdc00 | (iso646 & 0x03ff)); + continue; + } + } + else + { + // The five and six byte encodings aren't supported; + // they exceed the Unicode (and XML) range. + encodingError("unsupported five or six byte UTF-8 sequence", + 0xff & b1, i); + // NOTREACHED + c = 0; + } + } + else + { + // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx + // (US-ASCII character, "common" case, one branch to here) + c = (char) b1; + } + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + // How many characters have we read? + readBufferLength = j; + } + + /** + * Return the next byte value in a UTF-8 sequence. + * If it is not possible to get a byte from the current + * entity, throw an exception. + * @param pos The current position in the rawReadBuffer. + * @param count The number of bytes in the rawReadBuffer + * @return The significant six bits of a non-initial byte in + * a UTF-8 sequence. + * @exception EOFException If the sequence is incomplete. + */ + private int getNextUtf8Byte(int pos, int count) + throws SAXException, IOException + { + int val; + + // Take a character from the buffer + // or from the actual input stream. + if (pos < count) + { + val = rawReadBuffer[pos]; + } + else + { + val = is.read(); + if (val == -1) + { + encodingError("unfinished multi-byte UTF-8 sequence at EOF", + -1, pos); + } + } + + // Check for the correct bits at the start. + if ((val & 0xc0) != 0x80) + { + encodingError("bad continuation of multi-byte UTF-8 sequence", + val, pos + 1); + } + + // Return the significant bits. + return (val & 0x3f); + } + + /** + * Convert a buffer of US-ASCII or ISO-8859-1-encoded bytes into + * UTF-16 characters. + * + *

When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + * + * @param count The number of bytes to convert. + * @param mask For ASCII conversion, 0x7f; else, 0xff. + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyIso8859_1ReadBuffer(int count, char mask) + throws IOException + { + int i, j; + for (i = 0, j = readBufferPos; i < count; i++, j++) + { + char c = (char) (rawReadBuffer[i] & 0xff); + if ((c & mask) != 0) + { + throw new CharConversionException("non-ASCII character U+" + + Integer.toHexString(c)); + } + if (c == 0x0085 && xmlVersion == XML_11) + { + c = '\r'; + } + readBuffer[j] = c; + if (c == '\r') + { + sawCR = true; + } + } + readBufferLength = j; + } + + /** + * Convert a buffer of UCS-2-encoded bytes into UTF-16 characters + * (as used in Java string manipulation). + * + *

When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + * @param count The number of bytes to convert. + * @param shift1 The number of bits to shift byte 1. + * @param shift2 The number of bits to shift byte 2 + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyUcs2ReadBuffer(int count, int shift1, int shift2) + throws SAXException + { + int j = readBufferPos; + + if (count > 0 && (count % 2) != 0) + { + encodingError("odd number of bytes in UCS-2 encoding", -1, count); + } + // The loops are faster with less internal brancing; hence two + if (shift1 == 0) + { // "UTF-16-LE" + for (int i = 0; i < count; i += 2) + { + char c = (char) (rawReadBuffer[i + 1] << 8); + c |= 0xff & rawReadBuffer[i]; + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + } + else + { // "UTF-16-BE" + for (int i = 0; i < count; i += 2) + { + char c = (char) (rawReadBuffer[i] << 8); + c |= 0xff & rawReadBuffer[i + 1]; + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + } + readBufferLength = j; + } + + /** + * Convert a buffer of UCS-4-encoded bytes into UTF-16 characters. + * + *

When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + *

Java has Unicode chars, and this routine uses surrogate pairs + * for ISO-10646 values between 0x00010000 and 0x000fffff. An + * exception is thrown if the ISO-10646 character has no Unicode + * representation. + * + * @param count The number of bytes to convert. + * @param shift1 The number of bits to shift byte 1. + * @param shift2 The number of bits to shift byte 2 + * @param shift3 The number of bits to shift byte 2 + * @param shift4 The number of bits to shift byte 2 + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyUcs4ReadBuffer(int count, int shift1, int shift2, + int shift3, int shift4) + throws SAXException + { + int j = readBufferPos; + + if (count > 0 && (count % 4) != 0) + { + encodingError("number of bytes in UCS-4 encoding " + + "not divisible by 4", + -1, count); + } + for (int i = 0; i < count; i += 4) + { + int value = (((rawReadBuffer [i] & 0xff) << shift1) | + ((rawReadBuffer [i + 1] & 0xff) << shift2) | + ((rawReadBuffer [i + 2] & 0xff) << shift3) | + ((rawReadBuffer [i + 3] & 0xff) << shift4)); + if (value < 0x0000ffff) + { + readBuffer [j++] = (char) value; + if (value == (int) '\r') + { + sawCR = true; + } + } + else if (value < 0x0010ffff) + { + value -= 0x010000; + readBuffer[j++] = (char) (0xd8 | ((value >> 10) & 0x03ff)); + readBuffer[j++] = (char) (0xdc | (value & 0x03ff)); + } + else + { + encodingError("UCS-4 value out of range for Unicode", + value, i); + } + } + readBufferLength = j; + } + + /** + * Report a character encoding error. + */ + private void encodingError(String message, int value, int offset) + throws SAXException + { + if (value != -1) + { + message = message + " (character code: 0x" + + Integer.toHexString(value) + ')'; + error(message); + } + } + + ////////////////////////////////////////////////////////////////////// + // Local Variables. + ////////////////////////////////////////////////////////////////////// + + /** + * Re-initialize the variables for each parse. + */ + private void initializeVariables() + { + // First line + line = 1; + column = 0; + + // Set up the buffers for data and names + dataBufferPos = 0; + dataBuffer = new char[DATA_BUFFER_INITIAL]; + nameBufferPos = 0; + nameBuffer = new char[NAME_BUFFER_INITIAL]; + + // Set up the DTD hash tables + elementInfo = new HashMap(); + entityInfo = new HashMap(); + notationInfo = new HashMap(); + skippedPE = false; + + // Set up the variables for the current + // element context. + currentElement = null; + currentElementContent = CONTENT_UNDECLARED; + + // Set up the input variables + sourceType = INPUT_NONE; + inputStack = new LinkedList(); + entityStack = new LinkedList(); + externalEntity = null; + tagAttributePos = 0; + tagAttributes = new String[100]; + rawReadBuffer = new byte[READ_BUFFER_MAX]; + readBufferOverflow = -1; + + scratch = new InputSource(); + + inLiteral = false; + expandPE = false; + peIsError = false; + + doReport = false; + + inCDATA = false; + + symbolTable = new Object[SYMBOL_TABLE_LENGTH][]; + } + + static class ExternalIdentifiers + { + + String publicId; + String systemId; + String baseUri; + + ExternalIdentifiers() + { + } + + ExternalIdentifiers(String publicId, String systemId, String baseUri) + { + this.publicId = publicId; + this.systemId = systemId; + this.baseUri = baseUri; + } + + } + + static class EntityInfo + { + + int type; + ExternalIdentifiers ids; + String value; + String notationName; + + } + + static class AttributeDecl + { + + String type; + String value; + int valueType; + String enumeration; + String defaultValue; + + } + + static class ElementDecl + { + + int contentType; + String contentModel; + HashMap attributes; + + } + + static class Input + { + + int sourceType; + URLConnection externalEntity; + char[] readBuffer; + int readBufferPos; + int readBufferLength; + int line; + int encoding; + int readBufferOverflow; + InputStream is; + int currentByteCount; + int column; + Reader reader; + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlReader.java b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java new file mode 100644 index 000000000..e0a047612 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java @@ -0,0 +1,373 @@ +/* XmlReader.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.aelfred2; + +import java.io.IOException; +import java.util.Locale; + +import org.xml.sax.*; +import org.xml.sax.ext.*; + +import gnu.xml.pipeline.EventFilter; +import gnu.xml.pipeline.ValidationConsumer; + + +/** + * This SAX2 parser optionally layers a validator over the Ælfred2 + * SAX2 parser. While this will not evaluate every XML validity constraint, + * it does support all the validity constraints that are of any real utility + * outside the strict SGML-compatible world. See the documentation for the + * SAXDriver class for information about the SAX2 features and properties + * that are supported, and documentation for the ValidationConsumer for + * information about what validity constraints may not be supported. + * (Ælfred2 tests some of those, even in non-validating mode, to + * achieve better conformance.) + * + *

Note that due to its internal construction, you can't change most + * handlers until parse() returns. This diverges slightly from SAX, which + * expects later binding to be supported. Early binding involves less + * runtime overhead, which is an issue for event pipelines as used inside + * this parser. Rather than relying on the parser to handle late binding + * to your own handlers, do it yourself. + * + * @see SAXDriver + * @see gnu.xml.pipeline.ValidationConsumer + * + * @author David Brownell + */ +public final class XmlReader + implements XMLReader +{ + + static class FatalErrorHandler + extends DefaultHandler2 + { + + public void error(SAXParseException e) + throws SAXException + { + throw e; + } + + } + + private SAXDriver aelfred2 = new SAXDriver(); + private EventFilter filter = new EventFilter(); + private boolean isValidating; + private boolean active; + + /** + * Constructs a SAX Parser. + */ + public XmlReader() + { + } + + /** + * Constructs a SAX Parser, optionally treating validity errors + * as if they were fatal errors. + */ + public XmlReader(boolean invalidIsFatal) + { + if (invalidIsFatal) + { + setErrorHandler(new FatalErrorHandler()); + } + } + + /** + * SAX2: Returns the object used to report the logical + * content of an XML document. + */ + public ContentHandler getContentHandler() + { + return filter.getContentHandler(); + } + + /** + * SAX2: Assigns the object used to report the logical + * content of an XML document. + * @exception IllegalStateException if called mid-parse + */ + public void setContentHandler(ContentHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + filter.setContentHandler(handler); + } + + /** + * SAX2: Returns the object used to process declarations related + * to notations and unparsed entities. + */ + public DTDHandler getDTDHandler() + { + return filter.getDTDHandler(); + } + + /** + * SAX1 Assigns DTD handler + * @exception IllegalStateException if called mid-parse + */ + public void setDTDHandler(DTDHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + filter.setDTDHandler(handler); + } + + /** + * SAX2: Returns the object used when resolving external + * entities during parsing (both general and parameter entities). + */ + public EntityResolver getEntityResolver() + { + return aelfred2.getEntityResolver(); + } + + /** + * SAX1 Assigns parser's entity resolver + */ + public void setEntityResolver(EntityResolver handler) + { + aelfred2.setEntityResolver(handler); + } + + /** + * SAX2: Returns the object used to receive callbacks for XML + * errors of all levels (fatal, nonfatal, warning); this is never null; + */ + public ErrorHandler getErrorHandler() + { + return aelfred2.getErrorHandler(); + } + + /** + * SAX1 Assigns error handler + * @exception IllegalStateException if called mid-parse + */ + public void setErrorHandler(ErrorHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + aelfred2.setErrorHandler(handler); + } + + /** + * SAX2: Assigns the specified property. + * @exception IllegalStateException if called mid-parse + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + if (getProperty(propertyId) != value) + { + filter.setProperty(propertyId, value); + } + } + + /** + * SAX2: Returns the specified property. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException + { + if ((SAXDriver.PROPERTY + "declaration-handler").equals(propertyId) + || (SAXDriver.PROPERTY + "lexical-handler").equals(propertyId)) + { + return filter.getProperty(propertyId); + } + throw new SAXNotRecognizedException(propertyId); + } + + private void forceValidating() + throws SAXNotRecognizedException, SAXNotSupportedException + { + aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes", + true); + aelfred2.setFeature(SAXDriver.FEATURE + "external-general-entities", + true); + aelfred2.setFeature(SAXDriver.FEATURE + "external-parameter-entities", + true); + } + + /** + * SAX2: Sets the state of features supported in this parser. + * Note that this parser requires reporting of namespace prefixes when + * validating. + */ + public void setFeature(String featureId, boolean state) + throws SAXNotRecognizedException, SAXNotSupportedException + { + boolean value = getFeature(featureId); + + if (state == value) + { + return; + } + + if ((SAXDriver.FEATURE + "validation").equals(featureId)) + { + if (active) + { + throw new SAXNotSupportedException("already parsing"); + } + if (state) + { + forceValidating(); + } + isValidating = state; + } + else + { + aelfred2.setFeature(featureId, state); + } + } + + /** + * SAX2: Tells whether this parser supports the specified feature. + * At this time, this directly parallels the underlying SAXDriver, + * except that validation is optionally supported. + * + * @see SAXDriver + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if ((SAXDriver.FEATURE + "validation").equals(featureId)) + { + return isValidating; + } + + return aelfred2.getFeature(featureId); + } + + /** + * SAX1: Sets the locale used for diagnostics; currently, + * only locales using the English language are supported. + * @param locale The locale for which diagnostics will be generated + */ + public void setLocale(Locale locale) + throws SAXException + { + aelfred2.setLocale(locale); + } + + /** + * SAX1: Preferred API to parse an XML document, using a + * system identifier (URI). + */ + public void parse(String systemId) + throws SAXException, IOException + { + parse(new InputSource(systemId)); + } + + /** + * SAX1: Underlying API to parse an XML document, used + * directly when no URI is available. When this is invoked, + * and the parser is set to validate, some features will be + * automatically reset to appropriate values: for reporting + * namespace prefixes, and incorporating external entities. + * + * @param source The XML input source. + * + * @exception IllegalStateException if called mid-parse + * @exception SAXException The handlers may throw any SAXException, + * and the parser normally throws SAXParseException objects. + * @exception IOException IOExceptions are normally through through + * the parser if there are problems reading the source document. + */ + public void parse(InputSource source) + throws SAXException, IOException + { + EventFilter next; + boolean nsdecls; + + synchronized (aelfred2) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + active = true; + } + + // set up the output pipeline + if (isValidating) + { + forceValidating(); + next = new ValidationConsumer(filter); + } + else + { + next = filter; + } + + // connect pipeline and error handler + // don't let _this_ call to bind() affect xmlns* attributes + nsdecls = aelfred2.getFeature(SAXDriver.FEATURE + "namespace-prefixes"); + EventFilter.bind(aelfred2, next); + if (!nsdecls) + { + aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes", + false); + } + + // parse, clean up + try + { + aelfred2.parse(source); + } + finally + { + active = false; + } + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/package.html b/libjava/classpath/gnu/xml/aelfred2/package.html new file mode 100644 index 000000000..e20425844 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/package.html @@ -0,0 +1,506 @@ + + + + package overview + + + +

This package contains Ælfred2, which includes an +enhanced SAX2-compatible version of the Ælfred +non-validating XML parser, a modular (and hence optional) +DTD validating parser, and modular (and hence optional) +JAXP glue to those. +Use these like any other SAX2 parsers.

+ + + +

About Ælfred

+ +

Ælfred is a XML parser written in the java programming language. + +

Design Principles

+ +

In most Java applets and applications, XML should not be the central +feature; instead, XML is the means to another end, such as loading +configuration information, reading meta-data, or parsing transactions.

+ +

When an XML parser is only a single component of a much larger +program, it cannot be large, slow, or resource-intensive. With Java +applets, in particular, code size is a significant issue. The standard +modem is still not operating at 56 Kbaud, or sometimes even with data +compression. Assuming an uncompressed 28.8 Kbaud modem, only about +3 KBytes can be downloaded in one second; compression often doubles +that speed, but a V.90 modem may not provide another doubling. When +used with embedded processors, similar size concerns apply.

+ +

Ælfred is designed for easy and efficient use over the Internet, +based on the following principles:

    + +
  1. Ælfred must be as small as possible, so that it doesn't add too + much to an applet's download time.
  2. + +
  3. Ælfred must use as few class files as possible, to minimize the + number of HTTP connections necessary. (The use of JAR files has made this + be less of a concern.)
  4. + +
  5. Ælfred must be compatible with most or all Java implementations + and platforms. (Write once, run anywhere.)
  6. + +
  7. Ælfred must use as little memory as possible, so that it does + not take away resources from the rest of your program. (It doesn't force + you to use DOM or a similar costly data structure API.)
  8. + +
  9. Ælfred must run as fast as possible, so that it does not slow down + the rest of your program.
  10. + +
  11. Ælfred must produce correct output for well-formed and valid + documents, but need not reject every document that is not valid or + not well-formed. (In Ælfred2, correctness was a bigger concern + than in the original version; and a validation option is available.)
  12. + +
  13. Ælfred must provide full internationalization from the first + release. (Ælfred2 now automatically handles all encodings + supported by the underlying JVM; previous versions handled only + UTF-8, UTF_16, ASCII, and ISO-8859-1.)
  14. + +
+ +

As you can see from this list, Ælfred is designed for production +use, but neither validation nor perfect conformance was a requirement. +Good validating parsers exist, including one in this package, +and you should use them as appropriate. (See conformance reviews +available at http://www.xml.com) +

+ +

One of the main goals of Ælfred2 was to significantly improve +conformance, while not significantly affecting the other goals stated above. +Since the only use of this parser is with SAX, some classes could be +removed, and so the overall size of Ælfred was actually reduced. +Subsequent performance work produced a notable speedup (over twenty +percent on larger files). That is, the tradeoffs between speed, size, and +conformance were re-targeted towards conformance and support of newer APIs +(SAX2), with a a positive performance impact.

+ +

The role anticipated for this version of Ælfred is as a +lightweight Free Software SAX parser that can be used in essentially every +Java program where the handful of conformance violations (noted below) +are acceptable. +That certainly includes applets, and +nowadays one must also mention embedded systems as being even more +size-critical. +At this writing, all parsers that are more conformant are +significantly larger, even when counting the optional +validation support in this version of Ælfred.

+ + +

About the Name Ælfred

+ +

Ælfred the Great (AElfred in ASCII) was King of Wessex, and +some say of King of England, at the time of his death in 899 AD. +Ælfred introduced a wide-spread literacy program in the hope that +his people would learn to read English, at least, if Latin was too +difficult for them. This Ælfred hopes to bring another sort of +literacy to Java, using XML, at least, if full SGML is too difficult.

+ +

The initial Æ ligature ("AE)" is also a reminder that XML is +not limited to ASCII.

+ + +

Character Encodings

+ +

The Ælfred parser currently builds in support for a handful +of input encodings. Of course these include UTF-8 and UTF-16, which +all XML parsers are required to support:

+ +

If you use any encoding other than UTF-8 or UTF-16 you should +make sure to label your data appropriately:

+ +
+<?xml version="1.0" encoding="ISO-8859-15"?> +
+ +

Encodings accessed through java.io.InputStreamReader +are now fully supported for both external labels (such as MIME types) +and internal types (as shown above). +There is one limitation in the support for internal labels: +the encodings must be derived from the US-ASCII encoding, +the EBCDIC family of encodings is not recognized. +Note that Java defines its +own encoding names, which don't always correspond to the standard +Internet encoding names defined by the IETF/IANA, and that Java +may even require use of nonstandard encoding names. +Please report +such problems; some of them can be worked around in this parser, +and many can be worked around by using external labels. +

+ +

Note that if you are using the Euro symbol with an fixed length +eight bit encoding, you should probably be using the encoding label +iso-8859-15 or, with a Microsoft OS, cp-1252. +Of course, UTF-8 and UTF-16 handle the Euro symbol directly. +

+ + +

Known Conformance Violations

+ +

Known conformance issues should be of negligible importance for +most applications, and include:

+ +

When tested against the July 12, 1999 version of the OASIS +XML Conformance test suite, an earlier version passed 1057 of 1067 tests. +That contrasts with the original version, which passed 867. The +current parser is top-ranked in terms of conformance, as is its +validating sibling (which has some additional conformance violations +imposed on it by SAX2 API deficiencies as well as some of the more +curious SGML layering artifacts found in the XML specification).

+ +

The XML 1.0 specification itself was not without problems, +and after some delays the W3C has come out with a revised +"second edition" specification. While that doesn't resolve all +the problems identified the XML specification, many of the most +egregious problems have been resolved. (You still need to drink +magic Kool-Aid before some DTD-related issues make sense.) +To the extent possible, this parser conforms to that second +edition specification, and does well against corrected versions +of the OASIS/NIST XML conformance test cases. See http://xmlconf.sourceforge.net +for more information about SAX2/XML conformance testing.

+ + +

Copyright and distribution terms

+ +

+The software in this package is distributed under the GNU General Public +License (with a special exception described below). +

+ +

+A copy of GNU General Public License (GPL) is included in this distribution, +in the file COPYING. If you do not have the source code, it is available at: + + http://www.gnu.org/software/classpath/ +

+ +
+  Linking this library statically or dynamically with other modules is
+  making a combined work based on this library.  Thus, the terms and
+  conditions of the GNU General Public License cover the whole
+  combination.
+
+  As a special exception, the copyright holders of this library give you
+  permission to link this library with independent modules to produce an
+  executable, regardless of the license terms of these independent
+  modules, and to copy and distribute the resulting executable under
+  terms of your choice, provided that you also meet, for each linked
+  independent module, the terms and conditions of the license of that
+  module.  An independent module is a module which is not derived from
+  or based on this library.  If you modify this library, you may extend
+  this exception to your version of the library, but you are not
+  obligated to do so.  If you do not wish to do so, delete this
+  exception statement from your version.
+
+  Parts derived from code which carried the following notice:
+
+  Copyright (c) 1997, 1998 by Microstar Software Ltd.
+
+  AElfred is free for both commercial and non-commercial use and
+  redistribution, provided that Microstar's copyright and disclaimer are
+  retained intact.  You are free to modify AElfred for your own use and
+  to redistribute AElfred with your modifications, provided that the
+  modifications are clearly documented.
+
+  This program 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.  Please use it AT
+  YOUR OWN RISK.
+
+ +

Some of this documentation was modified from the original +Ælfred README.txt file. All of it has been updated.

+ +

+ + +

Changes Since the last Microstar Release

+ +

As noted above, Microstar has not updated this parser since +the summer of 1998, when it released version 1.2a on its web site. +This release is intended to benefit the developer community by +refocusing the API on SAX2, and improving conformance to the extent +that most developers should not need to use another XML parser.

+ +

The code has been cleaned up (referring to the XML 1.0 spec in +all the production numbers in +comments, rather than some preliminary draft, for one example) and +has been sped up a bit as well. +JAXP support has been added, although developers are still +strongly encouraged to use the SAX2 APIs directly.

+ + +

SAX2 Support

+ +

The original version of Ælfred did not support the +SAX2 APIs.

+ +

This version supports the SAX2 APIs, exposing the standard +boolean feature descriptors. It supports the "DeclHandler" property +to provide access to all DTD declarations not already exposed +through the SAX1 API. The "LexicalHandler" property is supported, +exposing entity boundaries (including the unnamed external subset) and +things like comments and CDATA boundaries. SAX1 compatibility is +currently provided.

+ + +

Validation

+ +

In the 'pipeline' package in this same software distribution is an +XML Validation component +using any full SAX2 event stream (including all document type declarations) +to validate. There is now a XmlReader class +which combines that class and this enhanced Ælfred parser, creating +an optionally validating SAX2 parser.

+ +

As noted in the documentation for that validating component, certain +validity constraints can't reliably be tested by a layered validator. +These include all constraints relying on +layering violations (exposing XML at the level of tokens or below, +required since XML isn't a context-free grammar), some that +SAX2 doesn't support, and a few others. The resulting validating +parser is conformant enough for most applications that aren't doing +strange SGML tricks with DTDs. +Moreover, that validating filter can be used without +a parser ... any application component that emits SAX event streams +can DTD-validate its output on demand.

+ +

You want Smaller?

+ +

You'll have noticed that the original version of Ælfred +had small size as a top goal. Ælfred2 normally includes a +DTD validation layer, but you can package without that. +Similarly, JAXP factory support is available but optional. +Then the main added cost due to this revision are for +supporting the SAX2 API itself; DTD validation is as +cleanly layered as allowed by SAX2.

+ +

Bugs Fixed

+ +

Bugs fixed in Ælfred2 include:

+ +
    +
  1. Originally Ælfred didn't close file descriptors, which + led to file descriptor leakage on programs which ran for any + length of time.
  2. + +
  3. NOTATION declarations without system identifiers are + now handled correctly.
  4. + +
  5. DTD events are now reported for all invocations of a + given parser, not just the first one.
  6. + +
  7. More correct character handling:
      + +
    • Rejects out-of-range characters, both in text and in + character references.
    • + +
    • Correctly handles character references that expand to + surrogate pairs.
    • + +
    • Correctly handles UTF-8 encodings of surrogate pairs.
    • + +
    • Correctly handles Unicode 3.1 rules about illegal UTF-8 + encodings: there is only one legal encoding per character.
    • + +
    • PUBLIC identifiers are now rejected if they have illegal + characters.
    • + +
    • The parser is more correct about what characters are allowed + in names and name tokens. Uses Unicode rules (built in to Java) + rather than the voluminous XML rules, although some extensions + have been made to match XML rules more closely.
    • + +
    • Line ends are now normalized to newlines in all known + cases.
    • + +
  8. + +
  9. Certain validity errors were previously treated as well + formedness violations.
      + +
    • Repeated declarations of an element type are no + longer fatal errors.
    • + +
    • Undeclared parameter entity references are no longer + fatal errors.
    • + +
  10. + +
  11. Attribute handling is improved:
      + +
    • Whitespace must exist between attributes.
    • + +
    • Only one value for a given attribute is permitted.
    • + +
    • ATTLIST declarations don't need to declare attributes.
    • + +
    • Attribute values are normalized when required.
    • + +
    • Tabs in attribute values are normalized to spaces.
    • + +
    • Attribute values containing a literal "<" are rejected.
    • + +
  12. + +
  13. More correct entity handling:
      + +
    • Whitespace must precede NDATA when declaring unparsed + entities.
    • + +
    • Parameter entity declarations may not have NDATA annotations.
    • + +
    • The XML specification has a bug in that it doesn't specify + that certain contexts exist within which parameter entity + expansion must not be performed. Lacking an offical erratum, + this parser now disables such expansion inside comments, + processing instructions, ignored sections, public identifiers, + and parts of entity declarations.
    • + +
    • Entity expansions that include quote characters no longer + confuse parsing of strings using such expansions.
    • + +
    • Whitespace in the values of internal entities is not mapped + to space characters.
    • + +
    • General Entity references in attribute defaults within the + DTD now cause fatal errors when the entity is not defined at the + time it is referenced.
    • + +
    • Malformed general entity references in entity declarations are + now detected.
    • + +
  14. + +
  15. Neither conditional sections + nor parameter entity references within markup declarations + are permitted in the internal subset.
  16. + +
  17. Processing instructions whose target names are "XML" + (ignoring case) are now rejected.
  18. + +
  19. Comments may not include "--".
  20. + +
  21. Most "]]>" sequences in text are rejected.
  22. + +
  23. Correct syntax for standalone declarations is enforced.
  24. + +
  25. Setting a locale for diagnostics only produces an exception + if the language of that locale isn't English.
  26. + +
  27. Some more encoding names are recognized. These include the + Unicode 3.0 variants of UTF-16 (UTF-16BE, UTF-16LE) as well as + US-ASCII and a few commonly seen synonyms.
  28. + +
  29. Text (from character content, PIs, or comments) large enough + not to fit into internal buffers is now handled correctly even in + some cases which were originally handled incorrectly.
  30. + +
  31. Content is now reported for element types for which attributes + have been declared, but no content model is known. (Such documents + are invalid, but may still be well formed.)
  32. + +
+ +

Other bugs may also have been fixed.

+ +

For better overall validation support, some of the validity +constraints that can't be verified using the SAX2 event stream +are now reported directly by Ælfred2.

+ + + diff --git a/libjava/classpath/gnu/xml/dom/Consumer.java b/libjava/classpath/gnu/xml/dom/Consumer.java new file mode 100644 index 000000000..836c8d257 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/Consumer.java @@ -0,0 +1,352 @@ +/* Consumer.java -- + Copyright (C) 2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.ext.Attributes2; + +import gnu.xml.pipeline.DomConsumer; +import gnu.xml.pipeline.EventConsumer; + + +/** + * Event consumer which constructs DOM documents using the implementation + * in this package, using SAX2 events. This packages various backdoors + * into this DOM implementation, as needed to address DOM requirements + * that can't be met by strictly conforming implementations of DOM. + * + *

These requirements all relate to {@link DocumentType} nodes and + * features of that node type. These features are normally not used, + * because that interface only exposes a subset of the information found + * in DTDs. More, that subset does not include the most important typing + * information. For example, it excludes element content models and + * attribute typing. It does expose some entity management issues, + * although entity management doesn't relate to document typing. + * + *

Note that SAX2 does not expose the literal text of the DTD's + * internal subset, so it will not be present in DOM trees constructed + * using this API. (Though with a good SAX2 implementation, it could + * be partially recreated...) + * + * @author David Brownell + */ +public class Consumer extends DomConsumer +{ + /** + * Constructs an unconfigured event consumer, + * as a terminus in a SAX event pipeline. + */ + // used by PipelineFactory [terminus] + public Consumer () + throws SAXException + { + super (DomDocument.class); + setHandler (new Backdoor (this)); + } + + /** + * Constructs an unconfigured event consumer, + * as a stage in a SAX event pipeline. + */ + // used by PipelineFactory [filter] + public Consumer (EventConsumer next) + throws SAXException + { + super (DomDocument.class, next); + setHandler (new Backdoor (this)); + } + + /** + * Implements the backdoors needed by DOM. + * All methods in this class use implementation-specific APIs that are + * implied by the DOM specification (needed to implement testable + * behavior) but which are excluded from the DOM specification. + */ + public static class Backdoor extends DomConsumer.Handler + { + /** + * Constructor. + * @param consumer must have been initialized to use the + * {@link DomDocument} class (or a subclass) for + * constructing DOM trees + */ + protected Backdoor (DomConsumer consumer) + throws SAXException + { super (consumer); } + + // helper routine + private DomDoctype getDoctype () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + DocumentType dt = doc.getDoctype (); + + if (dt == null) + throw new SAXException ("doctype missing!"); + return (DomDoctype) dt; + } + + // SAX2 "lexical" event + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + + super.startDTD (name, publicId, systemId); + // DOM L2 doctype creation model is bizarre + DomDoctype dt = new DomDoctype (doc, name, publicId, systemId); + doc.appendChild (dt); + } + + // SAX2 "lexical" event + public void endDTD () + throws SAXException + { + super.endDTD (); + // DOM L2 has no way to make things readonly + getDoctype ().makeReadonly (); + } + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String systemId + ) throws SAXException + { + // DOM L2 can't create/save notation nodes + getDoctype ().declareNotation (name, publicId, systemId); + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + getDoctype ().declareEntity (name, publicId, systemId, + notationName); + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: this doesn't save the value as a child of this + // node, though it could realistically do so. + getDoctype ().declareEntity (name, null, null, null); + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String systemId + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: DOM allows for these to have children, if + // they don't have unbound namespace references. + getDoctype ().declareEntity (name, publicId, systemId, null); + } + + // SAX2 element + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + Node top; + + super.startElement (uri, localName, qName, atts); + + // might there be more work? + top = getTop (); + if (!top.hasAttributes () || !(atts instanceof Attributes2)) + return; + + // remember any attributes that got defaulted + DomNamedNodeMap map = (DomNamedNodeMap) top.getAttributes (); + Attributes2 attrs = (Attributes2) atts; + int length = atts.getLength (); + + //map.compact (); + for (int i = 0; i < length; i++) { + if (attrs.isSpecified (i)) + continue; + + // value was defaulted. + String temp = attrs.getQName (i); + DomAttr attr; + + if ("".equals (temp)) + attr = (DomAttr) map.getNamedItemNS (attrs.getURI (i), + atts.getLocalName (i)); + else + attr = (DomAttr) map.getNamedItem (temp); + + // DOM L2 can't write this flag, only read it + attr.setSpecified (false); + } + } + + public void endElement ( + String uri, + String localName, + String qName + ) throws SAXException + { + DomNode top = (DomNode) getTop (); + top.compact (); + super.endElement (uri, localName, qName); + } + + protected Text createText ( + boolean isCDATA, + char buf [], + int off, + int len + ) { + DomDocument doc = (DomDocument) getDocument (); + + if (isCDATA) + return doc.createCDATASection (buf, off, len); + else + return doc.createTextNode (buf, off, len); + } + + public void elementDecl(String name, String model) + throws SAXException + { + getDoctype().elementDecl(name, model); + } + + public void attributeDecl ( + String ename, + String aname, + String type, + String mode, + String value + ) throws SAXException + { + getDoctype().attributeDecl(ename, aname, type, mode, value); + /* + if (value == null && !"ID".equals (type)) + return; + + DomDoctype.ElementInfo info; + + info = getDoctype ().getElementInfo (ename); + if (value != null) + info.setAttrDefault (aname, value); + if ("ID".equals (type)) + info.setIdAttr (aname); + */ + + } + + // force duplicate name checking off while we're + // using parser output (don't duplicate the work) + public void startDocument () throws SAXException + { + super.startDocument (); + + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(false); + doc.setBuilding(true); + } + + public void endDocument () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(true); + doc.setBuilding(false); + doc.compact (); + DomDoctype doctype = (DomDoctype) doc.getDoctype(); + if (doctype != null) + { + doctype.makeReadonly(); + } + super.endDocument (); + } + + // these three methods collaborate to populate entity + // refs, marking contents readonly on end-of-entity + + public boolean canPopulateEntityRefs () + { return true; } + + public void startEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + super.startEntity (name); + + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) + top.readonly = false; + } + + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) { + top.compact (); + top.makeReadonly (); + } + super.endEntity (name); + } + } +} diff --git a/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java new file mode 100644 index 000000000..d6e25529d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java @@ -0,0 +1,83 @@ +/* DTDAttributeTypeInfo.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Attribute type information supplied by a DTD attribute declaration. + * + * @author Chris Burdess + */ +class DTDAttributeTypeInfo + implements TypeInfo +{ + + final String elementName; + final String name; + final String type; + final String mode; + final String value; + + DTDAttributeTypeInfo(String elementName, String name, String type, + String mode, String value) + { + this.elementName = elementName; + this.name = name; + this.type = type; + this.mode = mode; + this.value = value; + } + + public final String getTypeName() + { + return type; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java new file mode 100644 index 000000000..9063d4c79 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java @@ -0,0 +1,111 @@ +/* DTDElementTypeInfo.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.HashMap; +import java.util.Iterator; +import org.w3c.dom.TypeInfo; + +/** + * Element type information provided by a DTD element declaration. + * + * @author Chris Burdess + */ +class DTDElementTypeInfo + implements TypeInfo +{ + + final String name; + String model; + HashMap attributes; + String idAttrName; + + DTDElementTypeInfo(String name, String model) + { + this.name = name; + this.model = model; + } + + public final String getTypeName() + { + return null; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + + DTDAttributeTypeInfo getAttributeTypeInfo(String name) + { + if (attributes == null) + { + return null; + } + return (DTDAttributeTypeInfo) attributes.get(name); + } + + void setAttributeTypeInfo(String name, DTDAttributeTypeInfo info) + { + if (attributes == null) + { + attributes = new HashMap(); + } + attributes.put(name, info); + if ("ID".equals(info.type)) + { + idAttrName = name; + } + } + + Iterator attributes() + { + if (attributes == null) + { + return null; + } + return attributes.values().iterator(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomAttr.java b/libjava/classpath/gnu/xml/dom/DomAttr.java new file mode 100644 index 000000000..421baf76a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomAttr.java @@ -0,0 +1,411 @@ +/* DomAttr.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.events.MutationEvent; + + +/** + *

"Attr" implementation. In DOM, attributes cost quite a lot of + * memory because their values are complex structures rather than just + * simple strings. To reduce your costs, avoid having more than one + * child of an attribute; stick to a single Text node child, and ignore + * even that by using the attribute's "nodeValue" property.

+ * + *

As a bit of general advice, only look at attribute modification + * events through the DOMAttrModified event (sent to the associated + * element). Implementations are not guaranteed to report other events + * in the same order, so you're very likely to write nonportable code if + * you monitor events at the "children of Attr" level.

+ * + *

At this writing, not all attribute modifications will cause the + * DOMAttrModified event to be triggered ... only the ones using the string + * methods (setNodeValue, setValue, and Element.setAttribute) to modify + * those values. That is, if you manipulate those children directly, + * elements won't get notified that attribute values have changed. + * The natural fix for that will report other modifications, but won't + * be able to expose "previous" attribute value; it'll need to be cached + * or something (at which point why bother using child nodes).

+ * + *

You are strongly advised not to use "children" of any attribute + * nodes you work with.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomAttr + extends DomNsNode + implements Attr +{ + + private boolean specified; + private String value; // string value cache + + /** + * Constructs an Attr node associated with the specified document. + * The "specified" flag is initialized to true, since this DOM has + * no current "back door" mechanisms to manage default values so + * that every value must effectively be "specified". + * + *

This constructor should only be invoked by a Document as part of + * its createAttribute functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of attribute + * @param name Name of this attribute, which may include a prefix + */ + protected DomAttr(DomDocument owner, String namespaceURI, String name) + { + super(ATTRIBUTE_NODE, owner, namespaceURI, name); + specified = true; + length = 1; + + // XXX register self to get insertion/removal events + // and character data change events and when they happen, + // report self-mutation + } + + /** + * Constructs an Attr node associated with the specified document. + * The "specified" flag is initialized to true, since this DOM has + * no current "back door" mechanisms to manage default values so + * that every value must effectively be "specified". + * + *

This constructor should only be invoked by a Document as part of + * its createAttribute functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + *

+ * With this constructor, the prefix and local part are given explicitly + * rather than being computed. This allows them to be explicitly set to + * {@code null} as required by {@link Document#createAttribute(String)}. + *

+ * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of attribute + * @param name Name of this attribute, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + protected DomAttr(DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(ATTRIBUTE_NODE, owner, namespaceURI, name, prefix, localName); + specified = true; + length = 1; + } + + /** + * DOM L1 + * Returns the attribute name (same as getNodeName) + */ + public final String getName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns true if a parser reported this was in the source text. + */ + public final boolean getSpecified() + { + return specified; + } + + /** + * Records whether this attribute was in the source text. + */ + public final void setSpecified(boolean value) + { + specified = value; + } + + /** + * DOM L1 + * Returns the attribute value, with character and entity + * references substituted. + * NOTE: entity refs as children aren't currently handled. + */ + public String getNodeValue() + { + // If we have a simple node-value, use that + if (first == null) + { + return (value == null) ? "" : value; + } + // Otherwise collect child node-values + CPStringBuilder buf = new CPStringBuilder(); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + switch (ctx.nodeType) + { + case Node.TEXT_NODE: + buf.append(ctx.getNodeValue()); + break; + case Node.ENTITY_REFERENCE_NODE: + // TODO + break; + } + } + return buf.toString(); + } + + /** + * DOM L1 + * Assigns the value of the attribute; it will have one child, + * which is a text node with the specified value (same as + * setNodeValue). + */ + public final void setValue(String value) + { + setNodeValue(value); + } + + /** + * DOM L1 + * Returns the value of the attribute as a non-null string; same + * as getNodeValue. + * NOTE: entity refs as children aren't currently handled. + */ + public final String getValue() + { + return getNodeValue(); + } + + /** + * DOM L1 + * Assigns the attribute value; using this API, no entity or + * character references will exist. + * Causes a DOMAttrModified mutation event to be sent. + */ + public void setNodeValue(String value) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (value == null) + { + value = ""; + } + String oldValue = getNodeValue(); + while (last != null) + { + removeChild(last); + } + // don't create a new node just for this... + /* + Node text = owner.createTextNode(value); + appendChild(text); + */ + this.value = value; + length = 1; + specified = true; + + mutating(oldValue, value, MutationEvent.MODIFICATION); + } + + public final Node getFirstChild() + { + // Create a child text node if necessary + if (first == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return first; + } + + public final Node getLastChild() + { + // Create a child text node if necessary + if (last == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return last; + } + + public Node item(int index) + { + // Create a child text node if necessary + if (first == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return super.item(index); + } + + /** + * DOM L2 + * Returns the element with which this attribute is associated. + */ + public final Element getOwnerElement() + { + return (Element) parent; + } + + public final Node getNextSibling() + { + return null; + } + + public final Node getPreviousSibling() + { + return null; + } + + public Node getParentNode() + { + return null; + } + + /** + * Records the element with which this attribute is associated. + */ + public final void setOwnerElement(Element e) + { + if (parent != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); + } + if (!(e instanceof DomElement)) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); + } + parent = (DomElement) e; + depth = parent.depth + 1; + } + + /** + * The base URI of an Attr is always null. + */ + public final String getBaseURI() + { + return null; + } + + /** + * Shallow clone of the attribute, breaking all ties with any + * elements. + */ + public Object clone() + { + DomAttr retval = (DomAttr) super.clone(); + retval.specified = true; + return retval; + } + + private void mutating(String oldValue, String newValue, short why) + { + if (!reportMutations || parent == null || equal(newValue, oldValue)) + { + return; + } + + // EVENT: DOMAttrModified, target = parent, + // prev/new values provided, also attr name + MutationEvent event; + + event = (MutationEvent) createEvent ("MutationEvents"); + event.initMutationEvent ("DOMAttrModified", + true /* bubbles */, false /* nocancel */, + null, oldValue, newValue, getNodeName (), why); + parent.dispatchEvent (event); + } + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + if (parent != null) + { + // DTD implementation + DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); + if (doctype != null) + { + return doctype.getAttributeTypeInfo(parent.getNodeName(), + getNodeName()); + } + // TODO XML Schema implementation + } + return null; + } + + public boolean isId() + { + if (parent != null) + { + DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); + if (doctype != null) + { + DTDAttributeTypeInfo info = + doctype.getAttributeTypeInfo(parent.getNodeName(), + getNodeName()); + if (info != null && "ID".equals(info.type)) + { + return true; + } + } + DomElement element = (DomElement) parent; + if (element.userIdAttrs != null && + element.userIdAttrs.contains(this)) + { + return true; + } + // TODO XML Schema implementation + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomCDATASection.java b/libjava/classpath/gnu/xml/dom/DomCDATASection.java new file mode 100644 index 000000000..770f7d5dd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomCDATASection.java @@ -0,0 +1,90 @@ +/* DomCDATASection.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.CDATASection; + +/** + *

"CDATASection" implementation. + * This is a non-core DOM class, supporting the "XML" feature. + * CDATA sections are just ways to represent text using different + * delimeters.

+ * + *

You are strongly advised not to use CDATASection nodes. + * The advantage of having slightly prettier ways to print text that may + * have lots of embedded XML delimiters, such as "&" and "<", + * can be dwarfed by the cost of dealing with multiple kinds of text + * nodes in all your algorithms.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomCDATASection + extends DomText + implements CDATASection +{ + + /** + * Constructs a CDATA section node associated with the specified + * document and holding the specified data. + * + *

This constructor should only be invoked by a Document as part of + * its createCDATASection functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + */ + protected DomCDATASection(DomDocument owner, String value) + { + super(CDATA_SECTION_NODE, owner, value); + } + + protected DomCDATASection(DomDocument owner, char buf [], int off, int len) + { + super(CDATA_SECTION_NODE, owner, buf, off, len); + } + + /** + * DOM L1 + * Returns the string "#cdata-section". + */ + final public String getNodeName() + { + return "#cdata-section"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomCharacterData.java b/libjava/classpath/gnu/xml/dom/DomCharacterData.java new file mode 100644 index 000000000..396c5f7a7 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomCharacterData.java @@ -0,0 +1,344 @@ +/* DomCharacterData.java -- + Copyright (C) 1999,2000,2001,2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.events.MutationEvent; + + +/** + *

Abstract "CharacterData" implementation. This + * facilitates reusing code in classes implementing subtypes of that DOM + * interface (Text, Comment, CDATASection).

+ * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomCharacterData + extends DomNode + implements CharacterData +{ + + /** + * Empty node list representing the children of character data nodes. + */ + static class EmptyNodeList + implements NodeList + { + + public int getLength() + { + return 0; + } + + public Node item(int index) + { + return null; + } + + } + + /** + * Singleton empty node list for character data nodes. + */ + static final NodeList CHILD_NODES = new EmptyNodeList(); + + private String text; + + // package private + DomCharacterData(short nodeType, DomDocument doc, String value) + { + super(nodeType, doc); + text = (value == null) ? "" : value; + } + + // package private + DomCharacterData(short nodeType, DomDocument doc, + char[] buf, int offset, int length) + { + super(nodeType, doc); + text = (buf == null) ? "" : new String(buf, offset, length); + } + + /** + * DOM L1 + * Appends the specified data to the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void appendData(String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + String value = text + arg; + mutating(value); + text = value; + } + + /** + * DOM L1 + * Modifies the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void deleteData(int offset, int count) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + if (count == 0) + { + return; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Returns the value of this node. + */ + public String getNodeValue() + { + return text; + } + + /** + * DOM L1 + * Returns the value of this node; same as getNodeValue. + */ + public final String getData() + { + return text; + } + + /** + * DOM L1 + * Returns the length of the data. + */ + public int getLength() + { + return text.length(); + } + + /** + * DOM L1 + * Modifies the value of this node. + */ + public void insertData(int offset, String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + char[] tmp = arg.toCharArray (); + char[] buf = new char[raw.length + tmp.length]; + + try + { + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Modifies the value of this node. Causes DOMCharacterDataModified + * mutation events to be reported (at least one). + */ + public void replaceData(int offset, int count, String arg) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + + // deleteData + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + + // insertData + char[] tmp = arg.toCharArray (); + char[] buf2 = new char[buf.length + tmp.length]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Assigns the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void setNodeValue(String value) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (value == null) + { + value = ""; + } + mutating(value); + text = value; + } + + /** + * DOM L1 + * Assigns the value of this node; same as setNodeValue. + */ + final public void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Returns the specified substring. + */ + public String substringData(int offset, int count) + { + try + { + return text.substring(offset, count); + } + catch (StringIndexOutOfBoundsException e) + { + if (offset >= 0 && count >= 0 && offset < text.length()) + { + return text.substring(offset); + } + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * Returns an empty node list. + * Character data nodes do not have children. + */ + public NodeList getChildNodes() + { + return CHILD_NODES; + } + + /** + * The base URI for character data is null. + * @since DOM Level 3 Core + */ + public final String getBaseURI() + { + return null; + } + + private void mutating(String newValue) + { + if (!reportMutations) + { + return; + } + + // EVENT: DOMCharacterDataModified, target = this, + // prev/new values provided + MutationEvent event; + + event = (MutationEvent) createEvent("MutationEvents"); + event.initMutationEvent("DOMCharacterDataModified", + true /* bubbles */, false /* nocancel */, + null, text, newValue, null, (short) 0); + dispatchEvent(event); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomComment.java b/libjava/classpath/gnu/xml/dom/DomComment.java new file mode 100644 index 000000000..5be6bd518 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomComment.java @@ -0,0 +1,80 @@ +/* DomComment.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.Comment; + +/** + *

"Comment" implementation. + * Comments hold data intended for direct consumption by people; + * programs should only use ProcessingInstruction nodes. Note that + * since SAX makes comment reporting optional, XML systems that + * rely on comments (such as by using this class) will often lose + * those comments at some point in the processing pipeline.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomComment + extends DomCharacterData + implements Comment +{ + + /** + * Constructs a comment node associated with the specified + * document and holding the specified data. + * + *

This constructor should only be invoked by a Document as part of + * its createComment functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + */ + protected DomComment(DomDocument owner, String value) + { + super(COMMENT_NODE, owner, value); + } + + /** + * DOM L1 + * Returns the string "#comment". + */ + final public String getNodeName() + { + return "#comment"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDOMException.java b/libjava/classpath/gnu/xml/dom/DomDOMException.java new file mode 100644 index 000000000..4a3ba7a8c --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDOMException.java @@ -0,0 +1,174 @@ +/* DomDOMException.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + *

DOMException implementation. The version that + * is provided by the W3C is abstract, so it can't be instantiated. + * + *

This also provides a bit more information about the error + * that is being reported, in terms of the relevant DOM structures + * and data. + * + * @author David Brownell + */ +public class DomDOMException + extends DOMException +{ + + /** @serial Data that caused an error to be reported */ + private String data; + + /** @serial Node associated with the error. */ + private Node node; + + /** @serial Data associated with the error. */ + private int value; + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code. + */ + public DomDOMException(short code) + { + super(code, diagnostic(code)); + } + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code and additional + * information as provided. + */ + public DomDOMException(short code, String data, Node node, int value) + { + super(code, diagnostic(code)); + this.data = data; + this.node = node; + this.value = value; + } + + /** Returns the node to which the diagnotic applies, or null. */ + final public Node getNode() + { + return node; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public String getData() + { + return data; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public int getValue() + { + return value; + } + + /** + * Returns a diagnostic message that may be slightly more useful + * than the generic one, where possible. + */ + public String getMessage() + { + String retval = super.getMessage(); + + if (data != null) + { + retval += "\nMore Information: " + data; + } + if (value != 0) + { + retval += "\nNumber: " + value; + } + if (node != null) + { + retval += "\nNode Name: " + node.getNodeName(); + } + return retval; + } + + // these strings should be localizable. + + private static String diagnostic(short code) + { + switch (code) + { + // DOM L1: + case INDEX_SIZE_ERR: + return "An index or size is out of range."; + case DOMSTRING_SIZE_ERR: + return "A string is too big."; + case HIERARCHY_REQUEST_ERR: + return "The node doesn't belong here."; + case WRONG_DOCUMENT_ERR: + return "The node belongs in another document."; + case INVALID_CHARACTER_ERR: + return "That character is not permitted."; + case NO_DATA_ALLOWED_ERR: + return "This node does not permit data."; + case NO_MODIFICATION_ALLOWED_ERR: + return "No changes are allowed."; + case NOT_FOUND_ERR: + return "The node was not found in that context."; + case NOT_SUPPORTED_ERR: + return "That object is not supported."; + case INUSE_ATTRIBUTE_ERR: + return "The attribute belongs to a different element."; + + // DOM L2: + case INVALID_STATE_ERR: + return "The object is not usable."; + case SYNTAX_ERR: + return "An illegal string was provided."; + case INVALID_MODIFICATION_ERR: + return "An object's type may not be changed."; + case NAMESPACE_ERR: + return "The operation violates XML Namespaces."; + case INVALID_ACCESS_ERR: + return "Parameter or operation isn't supported by this node."; + case TYPE_MISMATCH_ERR: + return "The type of the argument is incompatible with the expected type."; + } + return "Reserved exception number: " + code; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDoctype.java b/libjava/classpath/gnu/xml/dom/DomDoctype.java new file mode 100644 index 000000000..ecf7a9588 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDoctype.java @@ -0,0 +1,455 @@ +/* DomDoctype.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.HashMap; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; + +/** + *

"DocumentType" implementation (with no extensions for supporting + * any document typing information). This is a non-core DOM class, + * supporting the "XML" feature.

+ * + *

Few XML applications will actually care about this partial + * DTD support, since it doesn't expose any (!) of the data typing + * facilities which can motivate applications to use DTDs. It does not + * expose element content models, or information about attribute typing + * rules. Plus the information it exposes isn't very useful; as one example, + * DOM exposes information about unparsed ENTITY objects, which is only used + * with certain element attributes, but does not expose the information about + * those attributes which is needed to apply that data!

+ * + *

Also, note that there are no nonportable ways to associate even the + * notation and entity information exposed by DOM with a DocumentType. While + * there is a DOM L2 method to construct a DocumentType, it only gives access + * to the textual content of the <!DOCTYPE ...> declaration.

+ * + *

In short, you are strongly advised not to rely on this incomplete + * DTD functionality in your application code.

+ * + * @see DomEntity + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDoctype + extends DomExtern + implements DocumentType +{ + + private DomNamedNodeMap notations; + private DomNamedNodeMap entities; + private final DOMImplementation implementation; + private String subset; + + private HashMap elements = new HashMap(); + private boolean ids; + + /** + * Constructs a DocumentType node associated with the specified + * implementation, with the specified name. + * + *

This constructor should only be invoked by a DOMImplementation as + * part of its createDocumentType functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + *

Note that at this time there is no standard SAX API granting + * access to the internal subset text, so that relying on that value + * is not currently portable. + * + * @param impl The implementation with which this object is associated + * @param name Name of this root element + * @param publicId If non-null, provides the external subset's + * PUBLIC identifier + * @param systemId If non-null, provides the external subset's + * SYSTEM identifier + * @param internalSubset Provides the literal value (unparsed, no + * entities expanded) of the DTD's internal subset. + */ + protected DomDoctype(DOMImplementation impl, + String name, + String publicId, + String systemId, + String internalSubset) + { + super(DOCUMENT_TYPE_NODE, null, name, publicId, systemId); + implementation = impl; + subset = internalSubset; + } + + /** + * JAXP builder constructor. + * @param doc the document + * @param name the name of the document element + * @param publicId the public ID of the document type declaration + * @param systemId the system ID of the document type declaration + */ + public DomDoctype(DomDocument doc, + String name, + String publicId, + String systemId) + { + super(DOCUMENT_TYPE_NODE, doc, name, publicId, systemId); + implementation = doc.getImplementation(); + } + + /** + * DOM L1 + * Returns the root element's name (just like getNodeName). + */ + final public String getName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns information about any general entities declared + * in the DTD. + * + *

Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getEntities() + { + if (entities == null) + { + entities = new DomNamedNodeMap(this, Node.ENTITY_NODE); + } + return entities; + } + + /** + * Records the declaration of a general entity in this DocumentType. + * + * @param name Name of the entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier + * @param notation If non-null, provides the entity's notation + * (indicating an unparsed entity) + * @return The Entity that was declared, or null if the entity wasn't + * recorded (because it's a parameter entity or because an entity with + * this name was already declared). + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Entity declareEntity(String name, + String publicId, + String systemId, + String notation) + { + DomEntity entity; + + if (name.charAt(0) == '%' || "[dtd]".equals(name)) + { + return null; + } + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getEntities(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + if (entities.getNamedItem(name) != null) + { + return null; + } + + entity = new DomEntity(owner, name, publicId, systemId, notation); + entities.setNamedItem(entity); + return entity; + } + + /** + * DOM L1 + * Returns information about any notations declared in the DTD. + * + *

Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getNotations() + { + if (notations == null) + { + notations = new DomNamedNodeMap(this, Node.NOTATION_NODE); + } + return notations; + } + + /** + * Records the declaration of a notation in this DocumentType. + * + * @param name Name of the notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, provides the notation's SYSTEM identifier + * @return The notation that was declared. + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Notation declareNotation(String name, + String publicId, + String systemId) + { + DomNotation notation; + + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getNotations(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + + notation = new DomNotation(owner, name, publicId, systemId); + notations.setNamedItem(notation); + return notation; + } + + /** + * DOM L2 + * Returns the internal subset of the document, as a string of unparsed + * XML declarations (and comments, PIs, whitespace); or returns null if + * there is no such subset. There is no vendor-independent expectation + * that this attribute be set, or that declarations found in it be + * reflected in the entities or notations attributes + * of this Document "Type" object. + * + *

Some application-specific XML profiles require that documents + * only use specific PUBLIC identifiers, without an internal subset + * to modify the interperetation of the declarations associated with + * that PUBLIC identifier through some standard. + */ + public String getInternalSubset() + { + return subset; + } + + /** + * The base URI of a DocumentType is always null. + * See the Infoset Mapping, appendix C. + */ + public final String getBaseURI() + { + return null; + } + + /** + * Sets the internal "readonly" flag so the node and its associated + * data (only lists of entities and notations, no type information + * at the moment) can't be changed. + */ + public void makeReadonly() + { + super.makeReadonly(); + if (entities != null) + { + entities.makeReadonly(); + } + if (notations != null) + { + notations.makeReadonly(); + } + } + + void setOwner(DomDocument doc) + { + if (entities != null) + { + for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + if (notations != null) + { + for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + super.setOwner(doc); + } + + /** + * DOM L2 + * Consults the DOM implementation to determine if the requested + * feature is supported. + */ + final public boolean supports(String feature, String version) + { + return implementation.hasFeature(feature, version); + } + + /** + * Returns the implementation associated with this document type. + */ + final public DOMImplementation getImplementation() + { + return implementation; + } + + public void elementDecl(String name, String model) + { + DTDElementTypeInfo info = getElementTypeInfo(name); + if (info == null) + { + info = new DTDElementTypeInfo(name, model); + elements.put(name, info); + } + else + { + info.model = model; + } + } + + DTDElementTypeInfo getElementTypeInfo(String name) + { + return (DTDElementTypeInfo) elements.get(name); + } + + public void attributeDecl(String eName, String aName, String type, + String mode, String value) + { + DTDAttributeTypeInfo info = new DTDAttributeTypeInfo(eName, aName, type, + mode, value); + DTDElementTypeInfo elementInfo = getElementTypeInfo(eName); + if (elementInfo == null) + { + elementInfo = new DTDElementTypeInfo(eName, null); + elements.put(eName, elementInfo); + } + elementInfo.setAttributeTypeInfo(aName, info); + if ("ID".equals(type)) + { + ids = true; + } + } + + DTDAttributeTypeInfo getAttributeTypeInfo(String elementName, String name) + { + DTDElementTypeInfo elementInfo = + (DTDElementTypeInfo) elements.get(elementName); + return (elementInfo == null) ? null : + elementInfo.getAttributeTypeInfo(name); + } + + boolean hasIds() + { + return ids; + } + + public boolean isSameNode(Node arg) + { + if (equals(arg)) + { + return true; + } + if (!(arg instanceof DocumentType)) + { + return false; + } + DocumentType doctype = (DocumentType) arg; + if (!equal(getPublicId(), doctype.getPublicId())) + { + return false; + } + if (!equal(getSystemId(), doctype.getSystemId())) + { + return false; + } + if (!equal(getInternalSubset(), doctype.getInternalSubset())) + { + return false; + } + // TODO entities + // TODO notations + return true; + } + + /** + * Shallow clone of the doctype, except that associated + * entities and notations are (deep) cloned. + */ + public Object clone() + { + DomDoctype node = (DomDoctype) super.clone(); + + if (entities != null) + { + node.entities = new DomNamedNodeMap(node, Node.ENTITY_NODE); + for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next) + { + node.entities.setNamedItem(ctx.cloneNode(true)); + } + } + if (notations != null) + { + node.notations = new DomNamedNodeMap(node, Node.NOTATION_NODE); + for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next) + { + node.notations.setNamedItem(ctx.cloneNode(true)); + } + } + return node; + } + + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocument.java b/libjava/classpath/gnu/xml/dom/DomDocument.java new file mode 100644 index 000000000..b1e99f46d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocument.java @@ -0,0 +1,1555 @@ +/* DomDocument.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.Iterator; +import javax.xml.XMLConstants; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + *

"Document" and "DocumentTraversal" implementation. + * + *

Note that when this checks names for legality, it uses an + * approximation of the XML rules, not the real ones. Specifically, + * it uses Unicode rules, with sufficient tweaks to pass a majority + * of basic XML conformance tests. (The huge XML character tables are + * hairy to implement.) + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocument + extends DomNode + implements Document, DocumentTraversal, XPathEvaluator +{ + + private final DOMImplementation implementation; + private boolean checkingCharacters = true; + boolean checkingWellformedness = true; + private boolean defaultAttributes = true; + + boolean building; // if true, skip mutation events in the tree + + DomDocumentConfiguration config; + + String inputEncoding; + String encoding; + String version = "1.0"; + boolean standalone; + String systemId; + + /** + * Constructs a Document node, associating it with an instance + * of the DomImpl class. + * + *

Note that this constructor disables character checking. + * It is normally used when connecting a DOM to an XML parser, + * and duplicating such checks is undesirable. When used for + * purposes other than connecting to a parser, you should + * re-enable that checking. + * + * @see #setCheckingCharacters + */ + public DomDocument() + { + this(new DomImpl()); + } + + /** + * Constructs a Document node, associating it with the specified + * implementation. This should only be used in conjunction with + * a specialized implementation; it will normally be called by + * that implementation. + * + * @see DomImpl + * @see #setCheckingCharacters + */ + protected DomDocument(DOMImplementation impl) + { + super(DOCUMENT_NODE, null); + implementation = impl; + } + + /** + * Sets the building flag. + * Mutation events in the document are not reported. + */ + public void setBuilding(boolean flag) + { + building = flag; + } + + /** + * Sets whether to check for document well-formedness. + * If true, an exception will be raised if a second doctype or root + * element node is added to the document. + */ + public void setCheckWellformedness(boolean flag) + { + checkingWellformedness = flag; + } + + /** + * Sets whether to check for document characters. + */ + public void setCheckingCharacters(boolean flag) + { + checkingCharacters = flag; + } + + /** + * Sets whether to default attributes for new elements. + */ + public void setDefaultAttributes(boolean flag) + { + defaultAttributes = flag; + } + + /** + * DOM L1 + * Returns the constant "#document". + */ + final public String getNodeName() + { + return "#document"; + } + + /** + * DOM L1 + * Returns the document's root element, or null. + */ + final public Element getDocumentElement() + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.nodeType == ELEMENT_NODE) + { + return (Element) ctx; + } + } + return null; + } + + /** + * DOM L1 + * Returns the document's DocumentType, or null. + */ + final public DocumentType getDoctype() + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.nodeType == DOCUMENT_TYPE_NODE) + { + return (DocumentType) ctx; + } + } + return null; + } + + /** + * DOM L1 + * Returns the document's DOMImplementation. + */ + final public DOMImplementation getImplementation() + { + return implementation; + } + + /** + * DOM L1 (relocated in DOM L2) + * Returns the element with the specified "ID" attribute, or null. + * + *

Returns null unless {@link Consumer} was used to populate internal + * DTD declaration information, using package-private APIs. If that + * internal DTD information is available, the document may be searched for + * the element with that ID. + */ + public Element getElementById(String id) + { + if (id == null || id.length() == 0) + { + return null; + } + DomDoctype doctype = (DomDoctype) getDoctype(); + if (doctype != null && !doctype.hasIds()) + { + doctype = null; + } + + // yes, this is linear in size of document. + // it'd be easy enough to maintain a hashtable. + Node current = getDocumentElement(); + Node temp; + + if (current == null) + { + return null; + } + while (current != this) + { + // done? + if (current.getNodeType() == ELEMENT_NODE) + { + DomElement element = (DomElement) current; + if (element.userIdAttrs != null) + { + for (Iterator i = element.userIdAttrs.iterator(); + i.hasNext(); ) + { + Node idAttr = (Node) i.next(); + if (id.equals(idAttr.getNodeValue())) + { + return element; + } + } + } + if (doctype != null) + { + DTDElementTypeInfo info = + doctype.getElementTypeInfo(current.getNodeName()); + if (info != null && + id.equals(element.getAttribute(info.idAttrName))) + { + return element; + } + } + // xml:id + String xmlId = element.getAttribute("xml:id"); + if (xmlId == null) + { + xmlId = element.getAttributeNS(XMLConstants.XML_NS_URI, + "id"); + } + if (id.equals(xmlId)) + { + return element; + } + } + + // descend? + if (current.hasChildNodes()) + { + current = current.getFirstChild(); + continue; + } + + // lateral? + temp = current.getNextSibling(); + if (temp != null) + { + current = temp; + continue; + } + + // back up ... + do + { + temp = current.getParentNode(); + if (temp == null) + { + return null; + } + current = temp; + temp = current.getNextSibling(); + } + while (temp == null); + current = temp; + } + return null; + } + + private void checkNewChild(Node newChild) + { + if (newChild.getNodeType() == ELEMENT_NODE + && getDocumentElement() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document element already present: " + + getDocumentElement(), newChild, 0); + } + if (newChild.getNodeType() == DOCUMENT_TYPE_NODE + && getDoctype() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document type already present: " + + getDoctype(), newChild, 0); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node appendChild(Node newChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.appendChild(newChild); + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.insertBefore(newChild, refChild); + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node replaceChild(Node newChild, Node refChild) + { + if (checkingWellformedness && + ((newChild.getNodeType() == ELEMENT_NODE && + refChild.getNodeType() != ELEMENT_NODE) || + (newChild.getNodeType() == DOCUMENT_TYPE_NODE && + refChild.getNodeType() != DOCUMENT_TYPE_NODE))) + { + checkNewChild(newChild); + } + return super.replaceChild(newChild, refChild); + } + + // NOTE: DOM can't really tell when the name of an entity, + // notation, or PI must follow the namespace rules (excluding + // colons) instead of the XML rules (which allow them without + // much restriction). That's an API issue. verifyXmlName + // aims to enforce the XML rules, not the namespace rules. + + /** + * Throws a DOM exception if the specified name is not a legal XML 1.0 + * Name. + * @deprecated This method is deprecated and may be removed in future + * versions of GNU JAXP + */ + public static void verifyXmlName(String name) + { + // XXX why is this public? + checkName(name, false); + } + + static void checkName(String name, boolean xml11) + { + if (name == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + int len = name.length(); + if (len == 0) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + + // dog: rewritten to use the rules for XML 1.0 and 1.1 + + // Name start character + char c = name.charAt(0); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + c != ':' && c != '_' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != ':' && c != '_' && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + + // Subsequent characters + for (int i = 1; i < len; i++) + { + c = name.charAt(i); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + (c < 0x0030 || c > 0x0039) && + c != ':' && c != '_' && c != '-' && c != '.' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff) && + c != 0x00b7 && + (c < 0x0300 || c > 0x036f) && + (c < 0x203f || c > 0x2040)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, name, + null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.DECIMAL_DIGIT_NUMBER: // Nd + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + case Character.COMBINING_SPACING_MARK: // Mc + case Character.ENCLOSING_MARK: // Me + case Character.NON_SPACING_MARK: // Mn + case Character.MODIFIER_LETTER: // Lm + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != '-' && c != '.' && c != ':' && c != '_' && + c != 0x0387 && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6 && c != 0x00b7) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + } + + // FIXME characters with a font or compatibility decomposition (i.e. + // those with a "compatibility formatting tag" in field 5 of the + // database -- marked by field 5 beginning with a "<") are not allowed. + } + + // package private + static void checkNCName(String name, boolean xml11) + { + checkName(name, xml11); + int len = name.length(); + int index = name.indexOf(':'); + if (index != -1) + { + if (index == 0 || index == (len - 1) || name.lastIndexOf(':') != index) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + } + } + + // package private + static void checkChar(String value, boolean xml11) + { + char[] chars = value.toCharArray(); + checkChar(chars, 0, chars.length, xml11); + } + + static void checkChar(char[] buf, int off, int len, boolean xml11) + { + for (int i = 0; i < len; i++) + { + char c = buf[i]; + + // assume surrogate pairing checks out OK, for simplicity + if ((c >= 0x0020 && c <= 0xd7ff) || + (c == 0x000a || c == 0x000d || c == 0x0009) || + (c >= 0xe000 && c <= 0xfffd) || + (c >= 0x10000 && c <= 0x10ffff)) + { + continue; + } + if (xml11) + { + if ((c >= 0x0001 && c <= 0x001f) || + (c >= 0x007f && c <= 0x0084) || + (c >= 0x0086 && c <= 0x009f)) + { + continue; + } + } + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + new String(buf, off, len), null, c); + } + } + + /** + * DOM L1 + * Returns a newly created element with the specified name. + * The node name of the created element will be equal to {@code name}. + * The namespace, prefix and local name will all be {@code null}. + */ + public Element createElement(String name) + { + Element element; + + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + element = createElementNS(null, name); + } + else + { + DomElement domElement = new DomElement(this, null, name, null, null); + element = domElement; + } + if (defaultAttributes) + setDefaultAttributes(element, name); + return element; + } + + /** + * DOM L2 + * Returns a newly created element with the specified name + * and namespace information. + */ + public Element createElementNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith("xml:")) + { + if (namespaceURI != null + && !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", this, 0); + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name '" + name + + "' needs a URI", this, 0); + } + + Element element = new DomElement(this, namespaceURI, name); + if (defaultAttributes) + setDefaultAttributes(element, name); + return element; + } + + private void setDefaultAttributes(Element element, String name) + { + DomDoctype doctype = (DomDoctype) getDoctype(); + if (doctype == null) + { + return; + } + + // default any attributes that need it + DTDElementTypeInfo info = doctype.getElementTypeInfo(name); + if (info != null) + { + for (Iterator i = info.attributes(); i != null && i.hasNext(); ) + { + DTDAttributeTypeInfo attr = (DTDAttributeTypeInfo) i.next(); + String value = attr.value; + if ("#IMPLIED".equals(attr.mode) && value == null) + continue; + DomAttr node = (DomAttr) createAttribute(attr.name); + + if (value == null) + { + value = ""; + } + node.setValue(value); + node.setSpecified(false); + element.setAttributeNode(node); + } + } + } + + /** + * DOM L1 + * Returns a newly created document fragment. + */ + public DocumentFragment createDocumentFragment() + { + return new DomDocumentFragment(this); + } + + /** + * DOM L1 + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomText(this, value); + } + + /** + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomText(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created comment node with the specified value. + */ + public Comment createComment(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomComment(this, value); + } + + /** + * DOM L1 + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomCDATASection(this, value); + } + + /** + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomCDATASection(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created processing instruction. + */ + public ProcessingInstruction createProcessingInstruction(String target, + String data) + { + if (checkingCharacters) + { + boolean xml11 = "1.1".equals(version); + checkName(target, xml11); + if ("xml".equalsIgnoreCase(target)) + { + throw new DomDOMException(DOMException.SYNTAX_ERR, + "illegal PI target name", + this, 0); + } + checkChar(data, xml11); + } + return new DomProcessingInstruction(this, target, data); + } + + /** + * DOM L1 + * Returns a newly created attribute with the specified name. + */ + public Attr createAttribute(String name) + { + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + return createAttributeNS(XMLConstants.XML_NS_URI, name); + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + return createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, name); + } + else + { + DomAttr ret = new DomAttr(this, null, name, null, null); + return ret; + } + } + + /** + * DOM L2 + * Returns a newly created attribute with the specified name + * and namespace information. + */ + public Attr createAttributeNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith ("xml:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (!XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, + this, 0); + } + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + } + else if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, + this, 0); + } + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name needs a URI: " + name, this, 0); + } + return new DomAttr(this, namespaceURI, name); + } + + /** + * DOM L1 + * Returns a newly created reference to the specified entity. + * The caller should populate this with the appropriate children + * and then mark it as readonly. + * + * @see DomNode#makeReadonly + */ + public EntityReference createEntityReference(String name) + { + DomEntityReference ret = new DomEntityReference(this, name); + DocumentType doctype = getDoctype(); + if (doctype != null) + { + DomEntity ent = (DomEntity) doctype.getEntities().getNamedItem(name); + if (ent != null) + { + for (DomNode ctx = ent.first; ctx != null; ctx = ctx.next) + { + ret.appendChild(ctx.cloneNode(true)); + } + } + } + ret.makeReadonly(); + return ret; + } + + /** + * DOM L2 + * Makes a copy of the specified node, with all nodes "owned" by + * this document and with children optionally copied. This type + * of standard utility has become, well, a standard utility. + * + *

Note that EntityReference nodes created through this method (either + * directly, or recursively) never have children, and that there is no + * portable way to associate them with such children. + * + *

Note also that there is no requirement that the specified node + * be associated with a different document. This differs from the + * cloneNode operation in that the node itself is not given + * an opportunity to participate, so that any information managed + * by node subclasses will be lost. + */ + public Node importNode(Node src, boolean deep) + { + Node dst = null; + switch (src.getNodeType()) + { + case TEXT_NODE: + dst = createTextNode(src.getNodeValue()); + break; + case CDATA_SECTION_NODE: + dst = createCDATASection(src.getNodeValue()); + break; + case COMMENT_NODE: + dst = createComment(src.getNodeValue()); + break; + case PROCESSING_INSTRUCTION_NODE: + dst = createProcessingInstruction(src.getNodeName(), + src.getNodeValue()); + break; + case NOTATION_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Notation notation = (Notation) src; + dst = new DomNotation(this, notation.getNodeName(), + notation.getPublicId(), + notation.getSystemId()); + break; + case ENTITY_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Entity entity = (Entity) src; + dst = new DomEntity(this, entity.getNodeName(), + entity.getPublicId(), + entity.getSystemId(), + entity.getNotationName()); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ENTITY_REFERENCE_NODE: + dst = createEntityReference(src.getNodeName()); + break; + case DOCUMENT_FRAGMENT_NODE: + dst = new DomDocumentFragment(this); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ATTRIBUTE_NODE: + String attr_nsuri = src.getNamespaceURI(); + if (attr_nsuri != null) + { + dst = createAttributeNS(attr_nsuri, src.getNodeName()); + } + else + { + dst = createAttribute(src.getNodeName()); + } + // this is _always_ done regardless of "deep" setting + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, false)); + } + break; + case ELEMENT_NODE: + String elem_nsuri = src.getNamespaceURI(); + if (elem_nsuri != null) + { + dst = createElementNS(elem_nsuri, src.getNodeName()); + } + else + { + dst = createElement(src.getNodeName()); + } + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Attr a = (Attr) srcAttrs.item(i); + Attr dflt; + + // maybe update defaulted attributes + dflt = (Attr) dstAttrs.getNamedItem(a.getNodeName()); + if (dflt != null) + { + String newval = a.getNodeValue(); + if (!dflt.getNodeValue().equals(newval) + || a.getSpecified () == true) + { + dflt.setNodeValue (newval); + } + continue; + } + + dstAttrs.setNamedItem((Attr) importNode(a, false)); + } + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, true)); + } + } + break; + // can't import document or doctype nodes + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + // FALLTHROUGH + // can't import unrecognized or nonstandard nodes + default: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, src, 0); + } + + // FIXME cleanup a bit -- for deep copies, copy those + // children in one place, here (code sharing is healthy) + + if (src instanceof DomNode) + { + ((DomNode) src).notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + src, dst); + } + return dst; + } + + /** + * DOM L2 (Traversal) + * Returns a newly created node iterator. Don't forget to detach + * this iterator when you're done using it! + * + * @see DomIterator + */ + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + true); + } + + // DOM Level 3 methods + + /** + * DOM L3 + */ + public String getInputEncoding() + { + return inputEncoding; + } + + public void setInputEncoding(String inputEncoding) + { + this.inputEncoding = inputEncoding; + } + + /** + * DOM L3 + */ + public String getXmlEncoding() + { + return encoding; + } + + public void setXmlEncoding(String encoding) + { + this.encoding = encoding; + } + + public boolean getXmlStandalone() + { + return standalone; + } + + public void setXmlStandalone(boolean xmlStandalone) + { + standalone = xmlStandalone; + } + + public String getXmlVersion() + { + return version; + } + + public void setXmlVersion(String xmlVersion) + { + if (xmlVersion == null) + { + xmlVersion = "1.0"; + } + if ("1.0".equals(xmlVersion) || + "1.1".equals(xmlVersion)) + { + version = xmlVersion; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean getStrictErrorChecking() + { + return checkingCharacters; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + checkingCharacters = strictErrorChecking; + } + + public String lookupPrefix(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? false : root.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + return getDocumentURI(); + /* + Node root = getDocumentElement(); + if (root != null) + { + NamedNodeMap attrs = root.getAttributes(); + Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return systemId; + */ + } + + public String getDocumentURI() + { + return systemId; + } + + public void setDocumentURI(String documentURI) + { + systemId = documentURI; + } + + public Node adoptNode(Node source) + { + int sourceNodeType = source.getNodeType(); + switch (sourceNodeType) + { + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + case ENTITY_NODE: + case NOTATION_NODE: + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (source instanceof DomNode) + { + // GNU native + DomNode src = (DomNode) source; + DomNode dst = src; + if (dst.parent != null) + { + dst = (DomNode) dst.cloneNode(true); + } + dst.setOwner(this); + src.notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, src, dst); + return dst; + } + else + { + // Some other implementation + Node dst = null; + switch (sourceNodeType) + { + case Node.ATTRIBUTE_NODE: + { + Attr src = (Attr) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createAttribute(nodeName) : + createAttributeNS(namespaceUri, nodeName); + adoptChildren(src, dst); + break; + } + case Node.CDATA_SECTION_NODE: + { + CDATASection src = (CDATASection) source; + dst = createCDATASection(src.getData()); + break; + } + case Node.COMMENT_NODE: + { + Comment src = (Comment) source; + dst = createComment(src.getData()); + break; + } + case Node.DOCUMENT_FRAGMENT_NODE: + { + DocumentFragment src = (DocumentFragment) source; + dst = createDocumentFragment(); + adoptChildren(src, dst); + break; + } + case Node.ELEMENT_NODE: + { + Element src = (Element) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createElement(nodeName) : + createElementNS(namespaceUri, nodeName); + adoptAttributes(src, dst); + adoptChildren(src, dst); + break; + } + case Node.ENTITY_REFERENCE_NODE: + { + EntityReference src = (EntityReference) source; + dst = createEntityReference(src.getNodeName()); + adoptChildren(src, dst); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: + { + ProcessingInstruction src = (ProcessingInstruction) source; + dst = createProcessingInstruction(src.getTarget(), + src.getData()); + break; + } + case Node.TEXT_NODE: + { + Text src = (Text) source; + dst = createTextNode(src.getData()); + break; + } + } + return dst; + } + } + + void adoptChildren(Node src, Node dst) + { + Node node = src.getFirstChild(); + while (node != null) + { + Node next = node.getNextSibling(); + dst.appendChild(adoptNode(node)); + node = next; + } + } + + void adoptAttributes(Node src, Node dst) + { + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Node node = srcAttrs.item(i); + String localName = node.getLocalName(); + if (localName == null) + { + dstAttrs.setNamedItem(adoptNode(node)); + } + else + { + dstAttrs.setNamedItemNS(adoptNode(node)); + } + } + } + + public DOMConfiguration getDomConfig() + { + if (config == null) + { + config = new DomDocumentConfiguration(); + } + return config; + } + + public boolean isEqualNode(Node arg) + { + if (!super.isEqualNode(arg)) + return false; + Document d = (Document) arg; + String dversion = d.getXmlVersion(); + if (dversion == null || !dversion.equals(version)) + return false; + boolean dstandalone = d.getXmlStandalone(); + if (dstandalone != standalone) + return false; + String dencoding = d.getXmlEncoding(); + if (dencoding == null || dencoding.equalsIgnoreCase("UTF-8")) + { + if (encoding != null && !encoding.equalsIgnoreCase("UTF-8")) + return false; + } + else + { + if (!dencoding.equals(encoding)) + return false; + } + return true; + } + + public void normalizeDocument() + { + boolean save = building; + building = true; + normalizeNode(this); + building = save; + } + + void normalizeNode(DomNode node) + { + node.normalize(); + if (config != null) + { + switch (node.nodeType) + { + case CDATA_SECTION_NODE: + if (!config.cdataSections) + { + // replace CDATA section with text node + Text text = createTextNode(node.getNodeValue()); + node.parent.insertBefore(text, node); + node.parent.removeChild(node); + // merge adjacent text nodes + String data = text.getWholeText(); + node = (DomNode) text.replaceWholeText(data); + } + else if (config.splitCdataSections) + { + String value = node.getNodeValue(); + int i = value.indexOf("]]>"); + while (i != -1) + { + Node node2 = createCDATASection(value.substring(0, i)); + node.parent.insertBefore(node2, node); + value = value.substring(i + 3); + node.setNodeValue(value); + i = value.indexOf("]]>"); + } + } + break; + case COMMENT_NODE: + if (!config.comments) + { + node.parent.removeChild(node); + } + break; + case TEXT_NODE: + if (!config.elementContentWhitespace && + ((Text) node).isElementContentWhitespace()) + { + node.parent.removeChild(node); + } + break; + case ENTITY_REFERENCE_NODE: + if (!config.entities) + { + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + node.parent.insertBefore(ctx, node); + ctx = ctxNext; + } + node.parent.removeChild(node); + } + break; + case ELEMENT_NODE: + if (!config.namespaceDeclarations) + { + DomNamedNodeMap attrs = + (DomNamedNodeMap) node.getAttributes(); + boolean aro = attrs.readonly; + attrs.readonly = false; // Ensure we can delete if necessary + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String namespace = attr.getNamespaceURI(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespace)) + { + attrs.removeNamedItemNS(namespace, + attr.getLocalName()); + i--; + len--; + } + } + attrs.readonly = aro; + } + break; + } + } + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + normalizeNode(ctx); + ctx = ctxNext; + } + } + + public Node renameNode(Node n, String namespaceURI, String qualifiedName) + throws DOMException + { + if (n instanceof DomNsNode) + { + DomNsNode src = (DomNsNode) n; + if (src == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (src.owner != this) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, src, 0); + } + boolean xml11 = "1.1".equals(version); + checkName(qualifiedName, xml11); + int ci = qualifiedName.indexOf(':'); + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (namespaceURI != null) + { + checkNCName(qualifiedName, xml11); + String prefix = (ci == -1) ? "" : + qualifiedName.substring(0, ci); + if (XMLConstants.XML_NS_PREFIX.equals(prefix) && + !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)) && + !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + if (XMLConstants.XML_NS_URI.equals(namespaceURI) && + !XMLConstants.XML_NS_PREFIX.equals(prefix)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) && + !(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + + } + src.setNodeName(qualifiedName); + src.setNamespaceURI(namespaceURI); + src.notifyUserDataHandlers(UserDataHandler.NODE_RENAMED, src, src); + // TODO MutationNameEvents + // DOMElementNameChanged or DOMAttributeNameChanged + return src; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, n, 0); + } + + // -- XPathEvaluator -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new DomXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new DomXPathNSResolver(nodeResolver); + } + + public Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException + { + XPathExpression xpe = + new DomXPathExpression(this, expression, resolver); + return xpe.evaluate(contextNode, type, result); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java new file mode 100644 index 000000000..99c254481 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java @@ -0,0 +1,227 @@ +/* DomDocumentBuilder.java -- + Copyright (C) 2004,2006,2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; +import org.w3c.dom.Document; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Document builder using the GNU DOM Load & Save implementation. + * + * @author Chris Burdess + */ +class DomDocumentBuilder + extends DocumentBuilder +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + final LSParser parser; + + DomDocumentBuilder(DOMImplementation impl, + DOMImplementationLS ls, + LSParser parser) + { + this.impl = impl; + this.ls = ls; + this.parser = parser; + } + + public boolean isNamespaceAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("namespaces")).booleanValue(); + } + + public boolean isValidating() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("validating")).booleanValue(); + } + + public boolean isXIncludeAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("xinclude-aware")).booleanValue(); + } + + public void setEntityResolver(EntityResolver resolver) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("entity-resolver", resolver); + } + + public void setErrorHandler(ErrorHandler handler) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("error-handler", handler); + } + + public DOMImplementation getDOMImplementation() + { + return impl; + } + + public Document newDocument() + { + return impl.createDocument(null, null, null); + } + + public Document parse(InputStream in) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(InputStream in, String systemId) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + input.setSystemId(systemId); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(String systemId) + throws SAXException, IOException + { + try + { + return parser.parseURI(systemId); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(InputSource is) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + String systemId = is.getSystemId(); + InputStream in = is.getByteStream(); + if (in != null) + { + input.setByteStream(in); + } + else + { + Reader reader = is.getCharacterStream(); + if (reader != null) + { + input.setCharacterStream(reader); + } + else + { + try + { + URL url = new URL(systemId); + input.setByteStream(url.openStream()); + } + catch (MalformedURLException e) + { + // Maybe this is a relative file URL + File cwd = new File(System.getProperty("user.dir")); + URL url = new URL(cwd.toURL(), systemId); + input.setByteStream(url.openStream()); + } + } + } + input.setPublicId(is.getPublicId()); + input.setSystemId(systemId); + input.setEncoding(is.getEncoding()); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java new file mode 100644 index 000000000..1e3eaa582 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java @@ -0,0 +1,181 @@ +/* DomDocumentBuilderFactory.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSParser; + +/** + * Document builder factory that uses a DOM Level 3 Load & Save + * implementation. + * + * @author Chris Burdess + */ +public class DomDocumentBuilderFactory + extends DocumentBuilderFactory +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + private boolean secureProcessing; + + public DomDocumentBuilderFactory() + { + try + { + DOMImplementationRegistry reg = + DOMImplementationRegistry.newInstance(); + impl = reg.getDOMImplementation("LS 3.0"); + if (impl == null) + { + throw new FactoryConfigurationError("no LS implementations found"); + } + ls = (DOMImplementationLS) impl; + } + catch (Exception e) + { + throw new FactoryConfigurationError(e); + } + } + + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + LSParser parser = null; + try + { + parser = ls.createLSParser(DOMImplementationLS.MODE_ASYNCHRONOUS, + "http://www.w3.org/TR/REC-xml"); + } + catch (DOMException e) + { + if (e.code == DOMException.NOT_SUPPORTED_ERR) + { + // Fall back to synchronous parser + try + { + parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, + "http://www.w3.org/TR/REC-xml"); + } + catch (DOMException e2) + { + ParserConfigurationException pce = + new ParserConfigurationException(); + pce.initCause(e2); + throw pce; + } + } + else + { + ParserConfigurationException pce = + new ParserConfigurationException(); + pce.initCause(e); + throw pce; + } + } + DOMConfiguration config = parser.getDomConfig(); + setParameter(config, "namespaces", + isNamespaceAware() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "element-content-whitespace", + isIgnoringElementContentWhitespace() ? Boolean.FALSE : + Boolean.TRUE); + setParameter(config, "comments", + isIgnoringComments() ? Boolean.FALSE : Boolean.TRUE); + setParameter(config, "expand-entity-references", + isExpandEntityReferences() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "coalescing", + isCoalescing() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "validating", + isValidating() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "xinclude-aware", + isXIncludeAware() ? Boolean.TRUE : Boolean.FALSE); + return new DomDocumentBuilder(impl, ls, parser); + } + + void setParameter(DOMConfiguration config, String name, Object value) + throws ParserConfigurationException + { + if (!config.canSetParameter(name, value)) + { + throw new ParserConfigurationException(name); + } + config.setParameter(name, value); + } + + public Object getAttribute(String name) + { + // TODO + return null; + } + + public void setAttribute(String name, Object value) + { + // TODO + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java new file mode 100644 index 000000000..9aab44532 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java @@ -0,0 +1,260 @@ +/* DomDocumentConfiguration.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.Arrays; +import java.util.List; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; + +/** + * Document configuration, used to store normalization and other parameters. + * + * @author Chris Burdess + */ +class DomDocumentConfiguration + implements DOMConfiguration, DOMStringList +{ + + private static final List SUPPORTED_PARAMETERS = + Arrays.asList(new String[] { "cdata-sections", + "comments", + "element-content-whitespace", + "entities", + "error-handler", + "namespace-declarations", + "split-cdata-sections", + "infoset"}); + + boolean cdataSections = true; + boolean comments = true; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaceDeclarations = true; + boolean splitCdataSections = true; + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + cdataSections = "true".equals(value.toString()); + } + else if ("comments".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("element-content-whitespace".equals(name)) + { + elementContentWhitespace = "true".equals(value.toString()); + } + else if ("entities".equals(name)) + { + entities = "true".equals(value.toString()); + } + else if ("error-handler".equals(name)) + { + try + { + errorHandler = (DOMErrorHandler) value; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.TYPE_MISMATCH_ERR, + value.getClass().getName(), null, 0); + } + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = "true".equals(value.toString()); + } + else if ("split-cdata-sections".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("infoset".equals(name)) + { + if ("true".equals(value.toString())) + { + entities = false; + cdataSections = false; + namespaceDeclarations = true; + elementContentWhitespace = true; + comments = true; + } + } + else if (("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) && + "false".equals(value.toString())) + { + // NOOP + } + else if (("namespaces".equals(name) || + "well-formed".equals(name)) && + "true".equals(value.toString())) + { + // NOOP + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + name, null, 0); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + return cdataSections ? Boolean.TRUE : Boolean.FALSE; + } + else if ("comments".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("element-content-whitespace".equals(name)) + { + return elementContentWhitespace ? Boolean.TRUE : Boolean.FALSE; + } + else if ("entities".equals(name)) + { + return entities ? Boolean.TRUE : Boolean.FALSE; + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("namespace-declarations".equals(name)) + { + return namespaceDeclarations ? Boolean.TRUE : Boolean.FALSE; + } + else if ("split-cdata-sections".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return Boolean.FALSE; + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return Boolean.TRUE; + } + else if ("infoset".equals(name)) + { + return (entities == false && + cdataSections == false && + namespaceDeclarations == true && + comments == true) ? Boolean.TRUE : Boolean.FALSE; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, name, null, 0); + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + else if (contains(name)) + { + return true; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return "false".equals(value.toString()); + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return "true".equals(value.toString()); + } + return false; + } + + public DOMStringList getParameterNames() + { + return this; + } + + public String item(int i) + { + try + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + catch (IndexOutOfBoundsException e) + { + return null; + } + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + str = str.toLowerCase(); + return SUPPORTED_PARAMETERS.contains(str); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java new file mode 100644 index 000000000..8c4e0db3b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java @@ -0,0 +1,75 @@ +/* DomDocumentFragment.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DocumentFragment; + +/** + *

"DocumentFragment" implementation.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocumentFragment + extends DomNode + implements DocumentFragment +{ + + /** + * Constructs a DocumentFragment node associated with the + * specified document. + * + *

This constructor should only be invoked by a Document as part of + * its createDocumentFragment functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + */ + protected DomDocumentFragment(DomDocument owner) + { + super(DOCUMENT_FRAGMENT_NODE, owner); + } + + /** + * DOM L1 + * Returns the string "#document-fragment". + */ + final public String getNodeName() + { + return "#document-fragment"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomElement.java b/libjava/classpath/gnu/xml/dom/DomElement.java new file mode 100644 index 000000000..429749978 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomElement.java @@ -0,0 +1,582 @@ +/* DomElement.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.HashSet; +import java.util.Set; +import javax.xml.XMLConstants; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + *

"Element" implementation. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomElement + extends DomNsNode + implements Element +{ + + /** + * User-defined ID attributes. + * Used by DomAttr.isId and DomDocument.getElementById + */ + Set userIdAttrs; + + // Attributes are VERY expensive in DOM, and not just for + // this implementation. Avoid creating them. + private DomNamedNodeMap attributes; + + // xml:space cache + String xmlSpace = ""; + + /** + * Constructs an Element node associated with the specified document. + * + *

This constructor should only be invoked by a Document as part + * of its createElement functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of element + * @param name Name of this element, which may include a prefix + */ + protected DomElement(DomDocument owner, String namespaceURI, String name) + { + super(ELEMENT_NODE, owner, namespaceURI, name); + } + + /** + *

+ * Constructs an Element node associated with the specified document. + * This constructor should only be invoked by a Document as part + * of its createElement functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + *

+ *

+ * With this constructor, the prefix and local part are given explicitly + * rather than being computed. This allows them to be explicitly set to + * {@code null} as required by {@link Document#createElement(String)}. + *

+ * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of element + * @param name Name of this element, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + protected DomElement(DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(ELEMENT_NODE, owner, namespaceURI, name, prefix, localName); + } + + /** + * DOM L1 + * Returns the element's attributes + */ + public NamedNodeMap getAttributes() + { + if (attributes == null) + { + attributes = new DomNamedNodeMap(this, Node.ATTRIBUTE_NODE); + } + return attributes; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return attributes != null && attributes.length != 0; + } + + /** + * Shallow clone of the element, except that associated + * attributes are (deep) cloned. + */ + public Object clone() + { + DomElement node = (DomElement) super.clone(); + + if (attributes != null) + { + node.attributes = new DomNamedNodeMap(node, Node.ATTRIBUTE_NODE); + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + node.attributes.setNamedItem(ctx.cloneNode(true), true, true); + } + } + return node; + } + + void setOwner(DomDocument doc) + { + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + super.setOwner(doc); + } + + /** + * Marks this element, its children, and its associated attributes as + * readonly. + */ + public void makeReadonly() + { + super.makeReadonly(); + if (attributes != null) + { + attributes.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the element name (same as getNodeName). + */ + final public String getTagName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttribute(String name) + { + if ("xml:space" == name) // NB only works on interned string + { + // Use cached value + return xmlSpace; + } + Attr attr = getAttributeNode(name); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttribute(String name) + { + return getAttributeNode(name) != null; + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttributeNS(String namespaceURI, String local) + { + return getAttributeNodeNS(namespaceURI, local) != null; + } + + /** + * DOM L2 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttributeNS(String namespaceURI, String local) + { + Attr attr = getAttributeNodeNS(namespaceURI, local); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L1 + * Returns the appropriate attribute node; the name is the + * nodeName property of the attribute. + */ + public Attr getAttributeNode(String name) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItem(name); + } + + /** + * DOM L2 + * Returns the appropriate attribute node; the name combines + * the namespace name and the local part. + */ + public Attr getAttributeNodeNS(String namespace, String localPart) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItemNS(namespace, localPart); + } + + /** + * DOM L1 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. The name used is the + * nodeName value. + */ + public void setAttribute(String name, String value) + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + attr.setNodeValue(value); + ((DomAttr) attr).setSpecified(true); + return; + } + attr = owner.createAttribute(name); + attr.setNodeValue(value); + setAttributeNode(attr); + } + + /** + * DOM L2 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. + */ + public void setAttributeNS(String uri, String aname, String value) + { + if (("xmlns".equals (aname) || aname.startsWith ("xmlns:")) + && !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals (uri)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "setting xmlns attribute to illegal value", this, 0); + } + + Attr attr = getAttributeNodeNS(uri, aname); + if (attr != null) + { + attr.setNodeValue(value); + return; + } + attr = owner.createAttributeNS(uri, aname); + attr.setNodeValue(value); + setAttributeNodeNS(attr); + } + + /** + * DOM L1 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNode(Attr attr) + { + return (Attr) getAttributes().setNamedItem(attr); + } + + /** + * DOM L2 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNodeNS(Attr attr) + { + return (Attr) getAttributes().setNamedItemNS(attr); + } + + /** + * DOM L1 + * Removes the appropriate attribute node. + * If there is no such node, this is (bizarrely enough) a NOP so you + * won't see exceptions if your code deletes non-existent attributes. + * + *

Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttribute(String name) + { + if (attributes == null) + { + return; + } + + try + { + attributes.removeNamedItem(name); + } + catch (DomDOMException e) + { + if (e.code != DOMException.NOT_FOUND_ERR) + { + throw e; + } + } + } + + /** + * DOM L1 + * Removes the appropriate attribute node; the name is the + * nodeName property of the attribute. + * + *

Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public Attr removeAttributeNode(Attr node) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, null, node, 0); + } + return (Attr) attributes.removeNamedItem(node.getNodeName()); + } + + /** + * DOM L2 + * Removes the appropriate attribute node; the name combines + * the namespace name and the local part. + * + *

Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttributeNS(String namespace, String localPart) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, localPart, null, 0); + } + attributes.removeNamedItemNS (namespace, localPart); + } + + // DOM Level 3 methods + + public String lookupPrefix(String namespaceURI) + { + if (namespaceURI == null) + { + return null; + } + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix(); + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String value = ctx.getNodeValue(); + if (value.equals(namespaceURI)) + { + return ctx.getLocalName(); + } + } + } + } + return super.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix() == null; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String qName = ctx.getNodeName(); + return (XMLConstants.XMLNS_ATTRIBUTE.equals(qName)); + } + } + } + return super.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + String namespace = getNamespaceURI(); + if (namespace != null && equal(prefix, getPrefix())) + { + return namespace; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + if (prefix == null) + { + if (XMLConstants.XMLNS_ATTRIBUTE.equals(ctx.getNodeName())) + { + return ctx.getNodeValue(); + } + } + else + { + if (prefix.equals(ctx.getLocalName())) + { + return ctx.getNodeValue(); + } + } + } + } + } + return super.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + if (attributes != null) + { + Node xmlBase = + attributes.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return super.getBaseURI(); + } + + public TypeInfo getSchemaTypeInfo() + { + // DTD implementation + DomDoctype doctype = (DomDoctype) owner.getDoctype(); + if (doctype != null) + { + return doctype.getElementTypeInfo(getNodeName()); + } + // TODO XML Schema implementation + return null; + } + + public void setIdAttribute(String name, boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItem(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (attr == null || attr.getOwnerElement() != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItemNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + + public boolean isEqualNode(Node arg) + { + if (!super.isEqualNode(arg)) + return false; + getAttributes(); + NamedNodeMap argAttrs = arg.getAttributes(); + int len = argAttrs.getLength(); + if (argAttrs == null || (len != attributes.length)) + return false; + for (int i = 0; i < len; i++) + { + Node argCtx = argAttrs.item(i); + // Don't compare namespace nodes + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(argCtx.getNamespaceURI())) + continue; + // Find corresponding attribute node + DomNode ctx = attributes.first; + for (; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + continue; + if (!ctx.isEqualNode(argCtx)) + continue; + break; + } + if (ctx == null) + return false; // not found + } + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEntity.java b/libjava/classpath/gnu/xml/dom/DomEntity.java new file mode 100644 index 000000000..be44d7359 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntity.java @@ -0,0 +1,146 @@ +/* DomEntity.java -- + Copyright (C) 1999,2000,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.Entity; + +/** + *

"Entity" implementation. This is a non-core DOM class, supporting the + * "XML" feature. There are two types of entities, neither of which works + * particularly well in this API:

+ * + *
Unparsed Entities
+ *
Since ENTITY/ENTITIES attributes, the only legal use of unparsed + * entities in XML, can't be detected with DOM, there isn't much point in + * trying to use unparsed entities in DOM applications. (XML Linking is + * working to provide a better version of this functionality.)
+ * + *
Parsed Entities
+ *
While the DOM specification permits nodes for parsed entities + * to have a readonly set of children, this is not required and there + * is no portable way to provide such children. This implementation + * currently does not permit children to be added to Entities. + * There are related issues with the use of EntityReference nodes.
+ * + *
+ * + *

In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntity + extends DomExtern + implements Entity +{ + + private String notation; + + /** + * Constructs an Entity node associated with the specified document, + * with the specified descriptive data. + * + *

This constructor should only be invoked by a DomDoctype as part + * of its declareEntity functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this entity is associated + * @param name Name of this entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier (URI) + * @param notation If non-null, provides the unparsed entity's notation. + */ + protected DomEntity(DomDocument owner, + String name, + String publicId, + String systemId, + String notation) + { + super(ENTITY_NODE, owner, name, publicId, systemId); + this.notation = notation; + + // NOTE: if notation == null, this is a parsed entity + // which could reasonably be given child nodes ... + makeReadonly(); + } + + /** + * DOM L1 + * Returns the NOTATION identifier associated with this entity, if any. + */ + final public String getNotationName() + { + return notation; + } + + // DOM Level 3 methods + + public String getInputEncoding() + { + // TODO + return null; + } + + public String getXmlEncoding() + { + // TODO + return null; + } + + public String getXmlVersion() + { + // TODO + return null; + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEntityReference.java b/libjava/classpath/gnu/xml/dom/DomEntityReference.java new file mode 100644 index 000000000..1fa2ea628 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntityReference.java @@ -0,0 +1,130 @@ +/* DomEntityReference.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; + +/** + *

"EntityReference" implementation (reference to parsed entity). + * This is a non-core DOM class, supporting the "XML" feature. + * It does not represent builtin entities (such as "&amp;") + * or character references, which are always directly expanded in + * DOM trees.

+ * + *

Note that while the DOM specification permits these nodes to have + * a readonly set of children, this is not required. Similarly, it does + * not require a DOM to couple EntityReference nodes with any Entity nodes + * that have the same entity name (and equivalent children). It also + * effectively guarantees that references created directly or indirectly + * through the Document.ImportNode method will not have children. + * The level of functionality you may get is extremely variable. + * + *

Also significant is that even at their most functional level, the fact + * that EntityReference children must be readonly has caused significant + * problems when modifying work products held in DOM trees. Other problems + * include issues related to undeclared namespace prefixes (and references + * to the current default namespace) that may be found in the text of such + * parsed entities nodes. These must be contextually bound as part of DOM + * tree construction. When such nodes are moved, the namespace associated + * with a given prefix (or default) may change to be in conflict with the + * namespace bound to the node at creation time. + * + *

In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntityReference + extends DomNode + implements EntityReference +{ + + private String name; + + /** + * Constructs an EntityReference node associated with the specified + * document. The creator should populate this with whatever contents + * are appropriate, and then mark it as readonly. + * + *

This constructor should only be invoked by a Document as part of + * its createEntityReference functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + * + * @see DomNode#makeReadonly + */ + protected DomEntityReference(DomDocument owner, String name) + { + super(ENTITY_REFERENCE_NODE, owner); + this.name = name; + } + + /** + * Returns the name of the referenced entity. + * @since DOM Level 1 Core + */ + public final String getNodeName() + { + return name; + } + + /** + * The base URI of an entity reference is the base URI where the entity + * declaration occurs. + * @since DOM Level 3 Core + */ + public final String getBaseURI() + { + DocumentType doctype = owner.getDoctype(); + if (doctype == null) + { + return null; + } + Entity entity = (Entity) doctype.getEntities().getNamedItem(name); + if (entity == null) + { + return null; + } + return entity.getBaseURI(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEvent.java b/libjava/classpath/gnu/xml/dom/DomEvent.java new file mode 100644 index 000000000..3e9a6550a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEvent.java @@ -0,0 +1,351 @@ +/* DomEvent.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Node; + +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.events.UIEvent; + +import org.w3c.dom.views.AbstractView; // used by UIEvent + +/** + * "Event" implementation. Events are + * created (through DocumentEvent interface methods on the document object), + * and are sent to any target node in the document. + * + *

Applications may define application specific event subclasses, but + * should otherwise use the DocumentTraversal interface to acquire + * event objects. + * + * @author David Brownell + */ +public class DomEvent + implements Event +{ + + String type; // init + EventTarget target; + EventTarget currentNode; + short eventPhase; + boolean bubbles; // init + boolean cancelable; // init + long timeStamp; // ? + + /** Returns the event's type (name) as initialized */ + public final String getType() + { + return type; + } + + /** + * Returns event's target; delivery of an event is initiated + * by a target.dispatchEvent(event) invocation. + */ + public final EventTarget getTarget() + { + return target; + } + + /** + * Returns the target to which events are currently being + * delivered. When capturing or bubbling, this will not + * be what getTarget returns. + */ + public final EventTarget getCurrentTarget() + { + return currentNode; + } + + /** + * Returns CAPTURING_PHASE, AT_TARGET, or BUBBLING; + * only meaningful within EventListener.handleEvent + */ + public final short getEventPhase() + { + return eventPhase; + } + + /** + * Returns true if the news of the event bubbles to tree tops + * (as specified during initialization). + */ + public final boolean getBubbles() + { + return bubbles; + } + + /** + * Returns true if the default handling may be canceled + * (as specified during initialization). + */ + public final boolean getCancelable() + { + return cancelable; + } + + /** + * Returns the event's timestamp. + */ + public final long getTimeStamp() + { + return timeStamp; + } + + boolean stop; + boolean doDefault; + + /** + * Requests the event no longer be captured or bubbled; only + * listeners on the event target will see the event, if they + * haven't yet been notified. + * + *

Avoid using this except for application-specific + * events, for which you the protocol explicitly "blesses" the use + * of this with some event types. Otherwise, you are likely to break + * algorithms which depend on event notification either directly or + * through bubbling or capturing.

+ * + *

Note that this method is not final, specifically to enable + * enforcing of policies about events always propagating.

+ */ + public void stopPropagation() + { + stop = true; + } + + /** + * Requests that whoever dispatched the event not perform their + * default processing when event delivery completes. Initializes + * event timestamp. + */ + public final void preventDefault() + { + doDefault = false; + } + + /** Initializes basic event state. */ + public void initEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg) + { + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + } + + /** Constructs, but does not initialize, an event. */ + public DomEvent(String type) + { + this.type = type; + } + + /** + * Returns a basic printable description of the event's type, + * state, and delivery conditions + */ + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("[Event "); + buf.append(type); + switch (eventPhase) + { + case CAPTURING_PHASE: + buf.append(", CAPTURING"); + break; + case AT_TARGET: + buf.append(", AT TARGET"); + break; + case BUBBLING_PHASE: + buf.append(", BUBBLING"); + break; + default: + buf.append(", (inactive)"); + break; + } + if (bubbles && eventPhase != BUBBLING_PHASE) + { + buf.append(", bubbles"); + } + if (cancelable) + { + buf.append(", can cancel"); + } + // were we to provide subclass info, this's where it'd live + buf.append("]"); + return buf.toString(); + } + + /** + * "MutationEvent" implementation. + */ + public static final class DomMutationEvent + extends DomEvent + implements MutationEvent + { + + // package private + Node relatedNode; // init + + private String prevValue; // init + private String newValue; // init + + private String attrName; // init + private short attrChange; // init + + /** Returns any "related" node provided by this type of event */ + public final Node getRelatedNode() + { + return relatedNode; + } + + /** Returns any "previous value" provided by this type of event */ + public final String getPrevValue() + { + return prevValue; + } + + /** Returns any "new value" provided by this type of event */ + public final String getNewValue() + { + return newValue; + } + + /** For attribute change events, returns the attribute's name */ + public final String getAttrName() + { + return attrName; + } + + /** For attribute change events, returns how the attribuet changed */ + public final short getAttrChange() + { + return attrChange; + } + + /** Initializes a mutation event */ + public final void initMutationEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + Node relatedNodeArg, + String prevValueArg, + String newValueArg, + String attrNameArg, + short attrChangeArg) + { + // super.initEvent is inlined here for speed + // (mutation events are issued on all DOM changes) + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + + relatedNode = relatedNodeArg; + prevValue = prevValueArg; + newValue = newValueArg; + attrName = attrNameArg; + attrChange = attrChangeArg; + } + + // clear everything that should be GC-able + void clear() + { + type = null; + target = null; + relatedNode = null; + currentNode = null; + prevValue = newValue = attrName = null; + } + + /** Constructs an uninitialized mutation event. */ + public DomMutationEvent(String type) + { + super(type); + } + + } + + /** + * "UIEvent" implementation. + */ + public static class DomUIEvent + extends DomEvent + implements UIEvent + { + + private AbstractView view; // init + private int detail; // init + + /** Constructs an uninitialized User Interface (UI) event */ + public DomUIEvent (String type) { super (type); } + + public final AbstractView getView () { return view; } + public final int getDetail () { return detail; } + + /** Initializes a UI event */ + public final void initUIEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + AbstractView viewArg, + int detailArg) + { + super.initEvent(typeArg, canBubbleArg, cancelableArg); + view = viewArg; + detail = detailArg; + } + + } + + /* + + static final class DomMouseEvent extends DomUIEvent + implements MouseEvent + { + // another half dozen state variables/accessors + } + + */ + +} diff --git a/libjava/classpath/gnu/xml/dom/DomExtern.java b/libjava/classpath/gnu/xml/dom/DomExtern.java new file mode 100644 index 000000000..7f2e55afc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomExtern.java @@ -0,0 +1,116 @@ +/* DomExtern.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +/** + *

Abstract implemention of nodes describing external DTD-related + * objects. This facilitates reusing code for Entity, Notation, and + * DocumentType (really, external subset) nodes. Such support is not + * part of the core DOM; it's for the "XML" feature.

+ * + *

Note that you are strongly advised to avoid using the DOM + * features that take advantage of this class, since (as of L2) none + * of them is defined fully enough to permit full use of the + * XML feature they partially expose.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomExtern + extends DomNode +{ + + private final String name; + private final String publicId; + private final String systemId; + + /** + * Constructs a node associated with the specified document, + * with the specified descriptive data. + * + * @param owner The document with which this object is associated + * @param name Name of this object + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId If non-null, provides the entity's SYSTEM identifier + */ + // package private + DomExtern(short nodeType, + DomDocument owner, + String name, + String publicId, + String systemId) + { + super(nodeType, owner); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * DOM L1 + * Returns the SYSTEM identifier associated with this object, if any. + */ + public final String getSystemId() + { + return systemId; + } + + /** + * DOM L1 + * Returns the PUBLIC identifier associated with this object, if any. + */ + public final String getPublicId() + { + return publicId; + } + + /** + * DOM L1 + * Returns the object's name. + */ + public final String getNodeName() + { + return name; + } + + public final String getLocalName() + { + return name; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomImpl.java b/libjava/classpath/gnu/xml/dom/DomImpl.java new file mode 100644 index 000000000..76a63caf6 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomImpl.java @@ -0,0 +1,277 @@ +/* DomImpl.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; +import gnu.xml.dom.html2.DomHTMLImpl; +import gnu.xml.dom.ls.DomLSInput; +import gnu.xml.dom.ls.DomLSOutput; +import gnu.xml.dom.ls.DomLSParser; +import gnu.xml.dom.ls.DomLSSerializer; + +/** + *

"DOMImplementation" implementation.

+ * + *

At this writing, the following features are supported: + * "XML" (L1, L2, L3), + * "Events" (L2), "MutationEvents" (L2), "USER-Events" (a conformant extension), + * "HTMLEvents" (L2), "UIEvents" (L2), "Traversal" (L2), "XPath" (L3), + * "LS" (L3) "LS-Async" (L3). + * It is possible to compile the package so it doesn't support some of these + * features (notably, Traversal). + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomImpl + implements DOMImplementation, DOMImplementationLS +{ + + /** + * Constructs a DOMImplementation object which supports + * "XML" and other DOM Level 2 features. + */ + public DomImpl() + { + } + + /** + * DOM L1 + * Returns true if the specified feature and version are + * supported. Note that the case of the feature name is ignored. + */ + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("events".equals(name) + || "mutationevents".equals(name) + || "uievents".equals(name) + // || "mouseevents".equals(name) + || "htmlevents".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + + // Extension: "USER-" prefix event types can + // be created and passed through the DOM. + + } + else if ("user-events".equals(name)) + { + return (version == null || + "".equals(version) || + "0.1".equals(version)); + + // NOTE: "hasFeature" for events is here interpreted to + // mean the DOM can manufacture those sorts of events, + // since actually choosing to report the events is more + // often part of the environment or application. It's + // only really an issue for mutation events. + + } + else if (DomNode.reportMutations + && "traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("html".equals(name) || "xhtml".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + + // views + // stylesheets + // css, css2 + // range + + return false; + } + + /** + * DOM L2 + * Creates and returns a DocumentType, associated with this + * implementation. This DocumentType can have no associated + * objects(notations, entities) until the DocumentType is + * first associated with a document. + * + *

Note that there is no implication that this DTD will + * be parsed by the DOM, or ever have contents. Moreover, the + * DocumentType created here can only be added to a document by + * the createDocument method(below). That means that the only + * portable way to create a Document object is to start parsing, + * queue comment and processing instruction (PI) nodes, and then only + * create a DOM Document after (a) it's known if a DocumentType + * object is needed, and (b) the name and namespace of the root + * element is known. Queued comment and PI nodes would then be + * inserted appropriately in the document prologue, both before and + * after the DTD node, and additional attributes assigned to the + * root element. + *(One hopes that the final DOM REC fixes this serious botch.) + */ + public DocumentType createDocumentType(String rootName, + String publicId, + String systemId) + // CR2 deleted internal subset, ensuring DocumentType + // is 100% useless instead of just 90% so. + { + DomDocument.checkNCName(rootName, false); + return new DomDoctype(this, rootName, publicId, systemId, null); + } + + /** + * DOM L2 + * Creates and returns a Document, populated only with a root element and + * optionally a document type(if that was provided). + */ + public Document createDocument(String namespaceURI, + String rootName, + DocumentType doctype) + { + Document doc = createDocument(); + Element root = null; + + if (rootName != null) + { + root = doc.createElementNS(namespaceURI, rootName); + if (rootName.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", null, 0); + } + } + // Bleech -- L2 seemingly _requires_ omission of xmlns attributes. + if (doctype != null) + { + doc.appendChild(doctype); // handles WRONG_DOCUMENT error + } + if (root != null) + { + doc.appendChild(root); + } + return doc; + } + + protected Document createDocument() + { + return new DomDocument(this); + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + if ("html".equalsIgnoreCase(feature) || + "xhtml".equalsIgnoreCase(feature)) + { + return new DomHTMLImpl(); + } + return this; + } + return null; + } + + // -- DOMImplementationLS -- + + public LSParser createLSParser(short mode, String schemaType) + throws DOMException + { + return new DomLSParser(mode, schemaType); + } + + public LSSerializer createLSSerializer() + { + return new DomLSSerializer(); + } + + public LSInput createLSInput() + { + return new DomLSInput(); + } + + public LSOutput createLSOutput() + { + return new DomLSOutput(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomIterator.java b/libjava/classpath/gnu/xml/dom/DomIterator.java new file mode 100644 index 000000000..d5f305cd8 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomIterator.java @@ -0,0 +1,380 @@ +/* DomIterator.java -- + Copyright (C) 1999, 2000, 2001, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *

"NodeIterator" implementation, usable with any L2 DOM which + * supports MutationEvents.

+ * + * @author David Brownell + */ +public final class DomIterator + implements NodeIterator, EventListener +{ + + private Node reference; + private boolean right; + private boolean done; + + private final Node root; + private final int whatToShow; + private final NodeFilter filter; + private final boolean expandEntityReferences; + + /** + * Constructs and initializes an iterator. + */ + protected DomIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + { + if (!root.isSupported("MutationEvents", "2.0")) + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + "Iterator needs mutation events", root, 0); + } + + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.expandEntityReferences = entityReferenceExpansion; + + // start condition: going right, seen nothing yet. + reference = null; + right = true; + + EventTarget target = (EventTarget) root; + target.addEventListener("DOMNodeRemoved", this, false); + } + + /** + * DOM L2 + * Flags the iterator as done, unregistering its event listener so + * that the iterator can be garbage collected without relying on weak + * references (a "Java 2" feature) in the event subsystem. + */ + public void detach() + { + EventTarget target = (EventTarget) root; + target.removeEventListener("DOMNodeRemoved", this, false); + done = true; + } + + /** + * DOM L2 + * Returns the flag controlling whether iteration descends + * through entity references. + */ + public boolean getExpandEntityReferences() + { + return expandEntityReferences; + } + + /** + * DOM L2 + * Returns the filter provided during construction. + */ + public NodeFilter getFilter() + { + return filter; + } + + /** + * DOM L2 + * Returns the root of the tree this is iterating through. + */ + public Node getRoot() + { + return root; + } + + /** + * DOM L2 + * Returns the mask of flags provided during construction. + */ + public int getWhatToShow() + { + return whatToShow; + } + + /** + * DOM L2 + * Returns the next node in a forward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed backwards. + */ + public Node nextNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + right = true; + return walk(true); + } + + /** + * DOM L2 + * Returns the next node in a backward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed forwards. + */ + public Node previousNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + Node previous = reference; + right = false; + walk(false); + return previous; + } + + private boolean shouldShow(Node node) + // raises Runtime exceptions indirectly, via acceptNode() + { + if ((whatToShow & (1 << (node.getNodeType() - 1))) == 0) + { + return false; + } + if (filter == null) + { + return true; + } + return filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; + } + + // + // scenario: root = 1, sequence = 1 2 ... 3 4 + // forward walk: 1 2 ... 3 4 null + // then backward: 4 3 ... 2 1 null + // + // At the leftmost end, "previous" == null + // At the rightmost end, "previous" == 4 + // + // The current draft spec really seem to make no sense re the + // role of the reference node, so what it says is ignored here. + // + private Node walk(boolean forward) + { + Node here = reference; + + while ((here = successor(here, forward)) != null + && !shouldShow(here)) + { + continue; + } + if (here != null || !forward) + { + reference = here; + } + return here; + } + + private boolean isLeaf(Node here) + { + boolean leaf = !here.hasChildNodes(); + if (!leaf && !expandEntityReferences) + { + leaf = (here.getNodeType() == Node.ENTITY_REFERENCE_NODE); + } + return leaf; + } + + // + // Returns the immediate successor in a forward (or backward) + // document order walk, sans filtering ... except that it knows + // how to stop, returning null when done. This is a depth first + // preorder traversal when run in the forward direction. + // + private Node successor(Node here, boolean forward) + { + Node next; + + // the "leftmost" end is funky + if (here == null) + { + return forward ? root : null; + } + + // + // Forward, this is preorder: children before siblings. + // Backward, it's postorder: we saw the children already. + // + if (forward && !isLeaf(here)) + { + return here.getFirstChild(); + } + + // There's no way up or sideways from the root, so if we + // couldn't move down to a child, there's nowhere to go. + // + if (here == root) + return null; + + // + // Siblings ... if forward, we visit them, if backwards + // we visit their children first. + // + if (forward) + { + if ((next = here.getNextSibling()) != null) + { + return next; + } + } + else if ((next = here.getPreviousSibling()) != null) + { + if (isLeaf(next)) + { + return next; + } + next = next.getLastChild(); + while (!isLeaf(next)) + { + next = next.getLastChild(); + } + return next; + } + + // + // We can't go down or lateral -- it's up, then. The logic is + // the converse of what's above: backwards is easy (the parent + // is next), forwards isn't. + // + next = here.getParentNode(); + if (!forward) + { + return next; + } + + Node temp = null; + while (next != null + && next != root + && (temp = next.getNextSibling()) == null) + { + next = next.getParentNode(); + } + + // If we have exceeded the root node then stop traversing. + if (next == root.getParentNode()) + { + return null; + } + return temp; + } + + /** + * Not for public use. This lets the iterator know when its + * reference node will be removed from the tree, so that a new + * one may be selected. + * + *

This version works by watching removal events as they + * bubble up. So, don't prevent them from bubbling. + */ + public void handleEvent(Event e) + { + MutationEvent event; + Node ancestor, removed; + + if (reference == null + || !"DOMNodeRemoved".equals(e.getType()) + || e.getEventPhase() != Event.BUBBLING_PHASE) + { + return; + } + + event = (MutationEvent) e; + removed = (Node) event.getTarget(); + + // See if the removal will cause trouble for this iterator + // by being the reference node or an ancestor of it. + for (ancestor = reference; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + break; + } + } + if (ancestor != removed) + { + return; + } + + // OK, it'll cause trouble. We want to make the "next" + // node in our current traversal direction seem right. + // So we pick the nearest node that's not getting removed, + // but go in the _opposite_ direction from our current + // traversal ... so the "next" doesn't skip anything. + Node candidate; + +search: + while ((candidate = walk(!right)) != null) + { + for (ancestor = candidate; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + continue search; + } + } + return; + } + + // The current DOM WD talks about a special case here; + // I've not yet seen it. + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java new file mode 100644 index 000000000..3dd957560 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java @@ -0,0 +1,90 @@ +/* DomNSResolverContext.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * Namespace content wrapper for an XPathNSResolver. + * + * @author Chris Burdess + */ +class DomNSResolverContext + implements NamespaceContext, Iterator +{ + + final XPathNSResolver resolver; + + DomNSResolverContext(XPathNSResolver resolver) + { + this.resolver = resolver; + } + + public String getNamespaceURI(String prefix) + { + return resolver.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return null; + } + + public Iterator getPrefixes(String namespaceURI) + { + return this; + } + + public boolean hasNext() + { + return false; + } + + public Object next() + { + return null; + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java new file mode 100644 index 000000000..7a767355a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java @@ -0,0 +1,421 @@ +/* DomNamedNodeMap.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + *

"NamedNodeMap" implementation.

+ * Used mostly to hold element attributes, but sometimes also + * to list notations or entities. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNamedNodeMap + implements NamedNodeMap +{ + + final DomNode owner; + final short type; + + DomNode first; + int length; + boolean readonly; + + // package private + DomNamedNodeMap(DomNode owner, short type) + { + this.owner = owner; + this.type = type; + } + + /** + * Exposes the internal "readonly" flag. In DOM, all NamedNodeMap + * objects found in a DocumentType object are read-only (after + * they are fully constructed), and those holding attributes of + * a readonly element will also be readonly. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so the node and its + * children can't be changed. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the named item from the map, or null; names are just + * the nodeName property. + */ + public Node getNamedItem(String name) + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.getNodeName().equals(name)) + { + return ctx; + } + } + return null; + } + + /** + * DOM L2 + * Returns the named item from the map, or null; names are the + * localName and namespaceURI properties, ignoring any prefix. + */ + public Node getNamedItemNS(String namespaceURI, String localName) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String name = ctx.getLocalName(); + if ((localName == null && name == null) || + (localName != null && localName.equals(name))) + { + String uri = ctx.getNamespaceURI(); + if ("".equals(uri)) + { + uri = null; + } + if ((namespaceURI == null && uri == null) || + (namespaceURI != null && namespaceURI.equals(uri))) + { + return ctx; + } + } + } + return null; + } + + /** + * DOM L1 + * Stores the named item into the map, optionally overwriting + * any existing node with that name. The name used is just + * the nodeName attribute. + */ + public Node setNamedItem(Node arg) + { + return setNamedItem(arg, false, false); + } + + /** + * DOM L2 + * Stores the named item into the map, optionally overwriting + * any existing node with that fully qualified name. The name + * used incorporates the localName and namespaceURI properties, + * and ignores any prefix. + */ + public Node setNamedItemNS(Node arg) + { + return setNamedItem(arg, true, false); + } + + Node setNamedItem(Node arg, boolean ns, boolean cloning) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + DomNode node = (DomNode) arg; + if (!cloning && node.owner != owner.owner) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); + } + if (node.nodeType != type) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); + } + if (node.nodeType == Node.ATTRIBUTE_NODE) + { + DomNode element = node.parent; + if (element != null && element != owner) + { + throw new DomDOMException(DOMException.INUSE_ATTRIBUTE_ERR); + } + node.parent = owner; + node.depth = owner.depth + 1; + } + + String nodeName = node.getNodeName(); + String localName = ns ? node.getLocalName() : null; + String namespaceURI = ns ? node.getNamespaceURI() : null; + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + + // maybe attribute ADDITION events (?) + DomNode last = null; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + if (ns) + { + String tln = ctx.getLocalName(); + if (tln == null) + { + tln = ctx.getNodeName(); + } + if (tln.equals(localName)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && namespaceURI == null) || + (tu != null && tu.equals(namespaceURI))) + { + test = true; + } + } + } + else + { + test = ctx.getNodeName().equals(nodeName); + } + if (test) + { + // replace + node.previous = ctx.previous; + node.next = ctx.next; + if (ctx.previous != null) + { + ctx.previous.next = node; + } + if (ctx.next != null) + { + ctx.next.previous = node; + } + if (first == ctx) + { + first = node; + } + reparent(node, nodeName, ctx.index); + ctx.parent = null; + ctx.next = null; + ctx.previous = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + last = ctx; + } + // append + if (last != null) + { + last.next = node; + node.previous = last; + } + else + { + first = node; + } + length++; + reparent(node, nodeName, 0); + return null; + } + + void reparent(DomNode node, String nodeName, int i) + { + node.parent = owner; + node.setDepth(owner.depth + 1); + // index renumbering + for (DomNode ctx = node; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + // cache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = node.getNodeValue(); + } + } + + /** + * DOM L1 + * Removes the named item from the map, or reports an exception; + * names are just the nodeName property. + */ + public Node removeNamedItem(String name) + { + return removeNamedItem(null, name, false); + } + + /** + * DOM L2 + * Removes the named item from the map, or reports an exception; + * names are the localName and namespaceURI properties. + */ + public Node removeNamedItemNS(String namespaceURI, String localName) + { + return removeNamedItem(namespaceURI, localName, true); + } + + Node removeNamedItem(String uri, String name, boolean ns) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + // report attribute REMOVAL event? + + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + String nodeName = ctx.getNodeName(); + if (ns) + { + String tln = ctx.getLocalName(); + if (name != null && name.equals(tln)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && uri == null) || + (tu != null && tu.equals(uri))) + { + test = true; + } + } + } + else + { + test = nodeName.equals(name); + } + if (test) + { + // uncache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = ""; + } + // is this a default attribute? + if (ctx.nodeType == Node.ATTRIBUTE_NODE) + { + String def = getDefaultValue(ctx.getNodeName()); + if (def != null) + { + ctx.setNodeValue(def); + ((DomAttr) ctx).setSpecified(false); + return null; + } + } + // remove + if (ctx == first) + { + first = ctx.next; + } + if (ctx.previous != null) + { + ctx.previous.next = ctx.next; + } + if (ctx.next != null) + { + ctx.next.previous = ctx.previous; + } + length--; + ctx.previous = null; + ctx.next = null; + ctx.parent = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + String getDefaultValue(String name) + { + DomDoctype doctype = (DomDoctype) owner.owner.getDoctype(); + if (doctype == null) + { + return null; + } + DTDAttributeTypeInfo info = + doctype.getAttributeTypeInfo(owner.getNodeName(), name); + if (info == null) + { + return null; + } + return info.value; + } + + /** + * DOM L1 + * Returns the indexed item from the map, or null. + */ + public Node item(int index) + { + DomNode ctx = first; + int count = 0; + while (ctx != null && count < index) + { + ctx = ctx.next; + count++; + } + return ctx; + } + + /** + * DOM L1 + * Returns the length of the map. + */ + public int getLength() + { + return length; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNode.java b/libjava/classpath/gnu/xml/dom/DomNode.java new file mode 100644 index 000000000..879baaa8d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNode.java @@ -0,0 +1,2222 @@ +/* DomNode.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.DocumentEvent; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventException; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *

"Node", "EventTarget", and "DocumentEvent" implementation. + * This provides most of the core DOM functionality; only more + * specialized features are provided by subclasses. Those subclasses may + * have some particular constraints they must implement, by overriding + * methods defined here. Such constraints are noted here in the method + * documentation.

+ * + *

Note that you can create events with type names prefixed with "USER-", + * and pass them through this DOM. This lets you use the DOM event scheme + * for application specific purposes, although you must use a predefined event + * structure (such as MutationEvent) to pass data along with those events. + * Test for existence of this feature with the "USER-Events" DOM feature + * name.

+ * + *

Other kinds of events you can send include the "html" events, + * like "load", "unload", "abort", "error", and "blur"; and the mutation + * events. If this DOM has been compiled with mutation event support + * enabled, it will send mutation events when you change parts of the + * tree; otherwise you may create and send such events yourself, but + * they won't be generated by the DOM itself.

+ * + *

Note that there is a namespace-aware name comparison method, + * nameAndTypeEquals, which compares the names (and types) of + * two nodes in conformance with the "Namespaces in XML" specification. + * While mostly intended for use with elements and attributes, this should + * also be helpful for ProcessingInstruction nodes and some others which + * do not have namespace URIs. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNode + implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable +{ + + // package private + //final static String xmlNamespace = "http://www.w3.org/XML/1998/namespace"; + //final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + // tunable + // NKIDS_* affects arrays of children (which grow) + // (currently) fixed size: + // ANCESTORS_* is for event capture/bubbling, # ancestors + // NOTIFICATIONS_* is for per-node event delivery, # events + private static final int NKIDS_DELTA = 8; + private static final int ANCESTORS_INIT = 20; + private static final int NOTIFICATIONS_INIT = 10; + + // tunable: enable mutation events or not? Enabling it costs about + // 10-15% in DOM construction time, last time it was measured. + + // package private !!! + static final boolean reportMutations = true; + + // locking protocol changeable only within this class + private static final Object lockNode = new Object(); + + // NON-FINAL class data + + // Optimize event dispatch by not allocating memory each time + private static boolean dispatchDataLock; + private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT]; + private static ListenerRecord[] notificationSet + = new ListenerRecord[NOTIFICATIONS_INIT]; + + // Ditto for the (most common) event object itself! + private static boolean eventDataLock; + private static DomEvent.DomMutationEvent mutationEvent + = new DomEvent.DomMutationEvent(null); + + // + // PER-INSTANCE DATA + // + + DomDocument owner; + DomNode parent; // parent node; + DomNode previous; // previous sibling node + DomNode next; // next sibling node + DomNode first; // first child node + DomNode last; // last child node + int index; // index of this node in its parent's children + int depth; // depth of the node in the document + int length; // number of children + final short nodeType; + + // Bleech ... "package private" so a builder can populate entity refs. + // writable during construction. DOM spec is nasty. + boolean readonly; + + // event registrations + private HashSet listeners; + private int nListeners; + + // DOM Level 3 userData dictionary. + private HashMap userData; + private HashMap userDataHandlers; + + // + // Some of the methods here are declared 'final' because + // knowledge about their implementation is built into this + // class -- for both integrity and performance. + // + + /** + * Reduces space utilization for this node. + */ + public void compact() + { + } + + /** + * Constructs a node and associates it with its owner. Only + * Document and DocumentType nodes may be created with no owner, + * and DocumentType nodes get an owner as soon as they are + * associated with a document. + */ + protected DomNode(short nodeType, DomDocument owner) + { + this.nodeType = nodeType; + + if (owner == null) + { + // DOM calls never go down this path + if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE) + { + throw new IllegalArgumentException ("no owner!"); + } + } + this.owner = owner; + this.listeners = new HashSet(); + } + + + /** + * DOM L1 + * Returns null; Element subclasses must override this method. + */ + public NamedNodeMap getAttributes() + { + return null; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return false; + } + + /** + * DOM L1 + * Returns a list, possibly empty, of the children of this node. + * In this implementation, to conserve memory, nodes are the same + * as their list of children. This can have ramifications for + * subclasses, which may need to provide their own getLength method + * for reasons unrelated to the NodeList method of the same name. + */ + public NodeList getChildNodes() + { + return this; + } + + /** + * DOM L1 + * Returns the first child of this node, or null if there are none. + */ + public Node getFirstChild() + { + return first; + } + + /** + * DOM L1 + * Returns the last child of this node, or null if there are none. + */ + public Node getLastChild() + { + return last; + } + + /** + * DOM L1 + * Returns true if this node has children. + */ + public boolean hasChildNodes() + { + return length != 0; + } + + + /** + * Exposes the internal "readonly" flag. In DOM, children of + * entities and entity references are readonly, as are the + * objects associated with DocumentType objets. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so this subtree can't be changed. + * Subclasses need to override this method for any associated content + * that's not a child node, such as an element's attributes or the + * (few) declarations associated with a DocumentType. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode child = first; child != null; child = child.next) + { + child.makeReadonly(); + } + } + + /** + * Used to adopt a node to a new document. + */ + void setOwner(DomDocument doc) + { + this.owner = doc; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + + // just checks the node for inclusion -- may be called many + // times (docfrag) before anything is allowed to change + private void checkMisc(DomNode child) + { + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + for (DomNode ctx = this; ctx != null; ctx = ctx.parent) + { + if (child == ctx) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't make ancestor into a child", + this, 0); + } + } + + DomDocument owner = (nodeType == DOCUMENT_NODE) ? (DomDocument) this : + this.owner; + DomDocument childOwner = child.owner; + short childNodeType = child.nodeType; + + if (childOwner != owner) + { + // new in DOM L2, this case -- patch it up later, in reparent() + if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null)) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, child, 0); + } + } + + // enforce various structural constraints + switch (nodeType) + { + case DOCUMENT_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case COMMENT_NODE: + case DOCUMENT_TYPE_NODE: + return; + } + break; + + case ATTRIBUTE_NODE: + switch (childNodeType) + { + case TEXT_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + + case DOCUMENT_FRAGMENT_NODE: + case ENTITY_REFERENCE_NODE: + case ELEMENT_NODE: + case ENTITY_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case TEXT_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case CDATA_SECTION_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + case DOCUMENT_TYPE_NODE: + if (!owner.building) + break; + switch (childNodeType) + { + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return; + } + break; + } + if (owner.checkingWellformedness) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't append " + + nodeTypeToString(childNodeType) + + " to node of type " + + nodeTypeToString(nodeType), + this, 0); + } + } + + // Here's hoping a good optimizer will detect the case when the + // next several methods are never called, and won't allocate + // object code space of any kind. (Case: not reporting any + // mutation events. We can also remove some static variables + // listed above.) + + private void insertionEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeInserted", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeInsertedIntoDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + if (doFree) + { + event.target = null; + event.relatedNode = null; + event.currentNode = null; + eventDataLock = false; + } // else we created work for the GC + } + + private void removalEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeRemoved", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeRemovedFromDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + event.target = null; + event.relatedNode = null; + event.currentNode = null; + if (doFree) + { + eventDataLock = false; + } + // else we created more work for the GC + } + + // + // Avoid creating lots of memory management work, by using a simple + // allocation strategy for the mutation event objects that get used + // at least once per tree modification. We can't use stack allocation, + // so we do the next simplest thing -- more or less, static allocation. + // Concurrent notifications should be rare, anyway. + // + // Returns the preallocated object, which needs to be carefully freed, + // or null to indicate the caller needs to allocate their own. + // + static private DomEvent.DomMutationEvent getMutationEvent() + { + synchronized (lockNode) + { + if (eventDataLock) + { + return null; + } + eventDataLock = true; + return mutationEvent; + } + } + + // NOTE: this is manually inlined in the insertion + // and removal event methods above; change in sync. + static private void freeMutationEvent() + { + // clear fields to enable GC + mutationEvent.clear(); + eventDataLock = false; + } + + void setDepth(int depth) + { + this.depth = depth; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setDepth(depth + 1); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *

Causes a DOMNodeInserted mutation event to be reported. + * Will first cause a DOMNodeRemoved event to be reported if the + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and + * inserted is implementation-specific. + * + *

If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node appendChild(Node newChild) + { + try + { + DomNode child = (DomNode) newChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + appendChild(ctx); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = length++; + child.setDepth(depth + 1); + child.next = null; + if (last == null) + { + first = child; + child.previous = null; + } + else + { + last.next = child; + child.previous = last; + } + last = child; + + if (reportMutations) + { + insertionEvent(null, child); + } + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *

Causes a DOMNodeInserted mutation event to be reported. Will + * first cause a DOMNodeRemoved event to be reported if the newChild + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and inserted + * is implementation-specific. + * + *

If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (refChild == null) + { + return appendChild(newChild); + } + + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + insertBefore(ctx, ref); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (ref == child) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't insert node before itself", + ref, 0); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + int i = ref.index; + child.setDepth(depth + 1); + child.next = ref; + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + ref.previous = child; + if (first == ref) + { + first = child; + } + // index renumbering + for (DomNode ctx = child; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + + if (reportMutations) + { + insertionEvent(null, child); + } + length++; + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children. + * Document subclasses must override this to test the restrictions + * that there be only one element and document type child. + * + *

Causes DOMNodeRemoved and DOMNodeInserted mutation event to be + * reported. Will cause another DOMNodeRemoved event to be reported if + * the newChild parameter already has a parent. These events may be + * delivered in any order, except that the event reporting removal + * from such an existing parent will always be delivered before the + * event reporting its re-insertion as a child of some other node. + * The order in which children are removed and inserted is implementation + * specific. + * + *

If your application needs to depend on the in which those removal + * and insertion events are delivered, don't use this API. Instead, + * invoke the removeChild and insertBefore methods directly, to guarantee + * a specific delivery order. Similarly, don't use document fragments, + * Otherwise your application code may not work on a DOM which implements + * this method differently. + * + *

If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node replaceChild(Node newChild, Node refChild) + { + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + DomEvent.DomMutationEvent event = getMutationEvent(); + boolean doFree = (event != null); + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + length--; + length += child.length; + + if (child.length == 0) + { + // Removal + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + } + else + { + int i = ref.index; + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + // Insertion + ctx.parent = this; + ctx.index = i++; + ctx.setDepth(ref.depth); + if (ctx == child.first) + { + ctx.previous = ref.previous; + } + if (ctx == child.last) + { + ctx.next = ref.next; + } + } + if (first == ref) + { + first = child.first; + } + if (last == ref) + { + last = child.last; + } + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = ref.index; + child.setDepth(ref.depth); + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + if (ref.next != null) + { + ref.next.previous = child; + } + child.next = ref.next; + if (first == ref) + { + first = child; + } + if (last == ref) + { + last = child; + } + + if (reportMutations) + { + insertionEvent(event, child); + } + if (doFree) + { + freeMutationEvent(); + } + } + ref.parent = null; + ref.index = 0; + ref.setDepth(0); + ref.previous = null; + ref.next = null; + + return ref; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Removes the specified child from this node's list of children, + * or else reports an exception. + * + *

Causes a DOMNodeRemoved mutation event to be reported. + * + *

If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node removeChild(Node refChild) + { + try + { + DomNode ref = (DomNode) refChild; + + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + + for (DomNode child = first; child != null; child = child.next) + { + if (child == ref) + { + if (reportMutations) + { + removalEvent(null, child); + } + + length--; + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + // renumber indices + int i = 0; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + ref.parent = null; + ref.setDepth(0); + ref.index = 0; + ref.previous = null; + ref.next = null; + + return ref; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + "that's no child of mine", refChild, 0); + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, refChild, 0); + } + } + + /** + * DOM L1 (NodeList) + * Returns the item with the specified index in this NodeList, + * else null. + */ + public Node item(int index) + { + DomNode child = first; + int count = 0; + while (child != null && count < index) + { + child = child.next; + count++; + } + return child; + } + + /** + * DOM L1 (NodeList) + * Returns the number of elements in this NodeList. + * (Note that many interfaces have a "Length" property, not just + * NodeList, and if a node subtype must implement one of those, + * it will also need to override getChildNodes.) + */ + public int getLength() + { + return length; + } + + /** + * Minimize extra space consumed by this node to hold children and event + * listeners. + */ + public void trimToSize() + { + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getNextSibling() + { + return next; + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getPreviousSibling() + { + return previous; + } + + /** + * DOM L1 + * Returns the parent node, if one is known. + */ + public Node getParentNode() + { + return parent; + } + + /** + * DOM L2 + * Consults the DOM implementation to determine if the requested + * feature is supported. DocumentType subclasses must override + * this method, and associate themselves directly with the + * DOMImplementation node used. (This method relies on being able + * to access the DOMImplementation from the owner document, but + * DocumentType nodes can be created without an owner.) + */ + public boolean isSupported(String feature, String version) + { + Document doc = owner; + DOMImplementation impl = null; + + if (doc == null && nodeType == DOCUMENT_NODE) + { + doc = (Document) this; + } + + if (doc == null) + { + // possible for DocumentType + throw new IllegalStateException ("unbound ownerDocument"); + } + + impl = doc.getImplementation(); + return impl.hasFeature(feature, version); + } + + /** + * DOM L1 (modified in L2) + * Returns the owner document. This is only null for Document nodes, + * and (new in L2) for DocumentType nodes which have not yet been + * associated with the rest of their document. + */ + final public Document getOwnerDocument() + { + return owner; + } + + /** + * DOM L1 + * Does nothing; this must be overridden (along with the + * getNodeValue method) for nodes with a non-null defined value. + */ + public void setNodeValue(String value) + { + } + + /** + * DOM L1 + * Returns null; this must be overridden for nodes types with + * a defined value, along with the setNodeValue method. + */ + public String getNodeValue() + { + return null; + } + + /** This forces GCJ compatibility. + * Without this method GCJ is unable to compile to byte code. + */ + public final short getNodeType() + { + return nodeType; + } + + /** This forces GCJ compatibility. + * Without this method GCJ seems unable to natively compile GNUJAXP. + */ + public abstract String getNodeName(); + + /** + * DOM L2 + * Does nothing; this must be overridden (along with the + * getPrefix method) for element and attribute nodes. + */ + public void setPrefix(String prefix) + { + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getPrefix() + { + return null; + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getNamespaceURI() + { + return null; + } + + /** + * DOM L2 + * Returns the node name; this must be overridden for element and + * attribute nodes. + */ + public String getLocalName() + { + return null; + } + + /** + * DOM L1 + * Returns a clone of this node which optionally includes cloned + * versions of child nodes. Clones are always mutable, except for + * entity reference nodes. + */ + public Node cloneNode(boolean deep) + { + if (deep) + { + return cloneNodeDeepInternal(true, null); + } + + DomNode node = (DomNode) clone(); + if (nodeType == ENTITY_REFERENCE_NODE) + { + node.makeReadonly(); + } + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); + return node; + } + + /** + * Returns a deep clone of this node. + */ + private DomNode cloneNodeDeepInternal(boolean root, DomDocument doc) + { + DomNode node = (DomNode) clone(); + boolean building = false; // Never used unless root is true + if (root) + { + doc = (nodeType == DOCUMENT_NODE) ? (DomDocument) node : node.owner; + building = doc.building; + doc.building = true; // Permit certain structural rules + } + node.owner = doc; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + DomNode newChild = ctx.cloneNodeDeepInternal(false, doc); + node.appendChild(newChild); + } + if (nodeType == ENTITY_REFERENCE_NODE) + { + node.makeReadonly(); + } + if (root) + { + doc.building = building; + } + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); + return node; + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + /** + * Clones this node; roughly equivalent to cloneNode(false). + * Element subclasses must provide a new implementation which + * invokes this method to handle the basics, and then arranges + * to clone any element attributes directly. Attribute subclasses + * must make similar arrangements, ensuring that existing ties to + * elements are broken by cloning. + */ + public Object clone() + { + try + { + DomNode node = (DomNode) super.clone(); + + node.parent = null; + node.depth = 0; + node.index = 0; + node.length = 0; + node.first = null; + node.last = null; + node.previous = null; + node.next = null; + + node.readonly = false; + node.listeners = new HashSet(); + node.nListeners = 0; + return node; + + } + catch (CloneNotSupportedException x) + { + throw new Error("clone didn't work"); + } + } + + // the elements-by-tagname stuff is needed for both + // elements and documents ... this is in lieu of a + // common base class between Node and NodeNS. + + /** + * DOM L1 + * Creates a NodeList giving array-style access to elements with + * the specified name. Access is fastest if indices change by + * small values, and the DOM is not modified. + */ + public NodeList getElementsByTagName(String tag) + { + return new ShadowList(null, tag); + } + + /** + * DOM L2 + * Creates a NodeList giving array-style access to elements with + * the specified namespace and local name. Access is fastest if + * indices change by small values, and the DOM is not modified. + */ + public NodeList getElementsByTagNameNS(String namespace, String local) + { + return new ShadowList(namespace, local); + } + + + // + // This shadow class is GC-able even when the live list it shadows + // can't be, because of event registration hookups. Its finalizer + // makes that live list become GC-able. + // + final class ShadowList + implements NodeList + { + + private LiveNodeList liveList; + + ShadowList(String ns, String local) + { + liveList = new LiveNodeList(ns, local); + } + + public void finalize() + { + liveList.detach(); + liveList = null; + } + + public Node item(int index) + { + return liveList.item(index); + } + + public int getLength() + { + return liveList.getLength(); + } + } + + final class LiveNodeList + implements NodeList, EventListener, NodeFilter + { + + private final boolean matchAnyURI; + private final boolean matchAnyName; + private final String elementURI; + private final String elementName; + + private DomIterator current; + private int lastIndex; + + LiveNodeList(String uri, String name) + { + elementURI = uri; + elementName = name; + matchAnyURI = "*".equals(uri); + matchAnyName = "*".equals(name); + + DomNode.this.addEventListener("DOMNodeInserted", this, true); + DomNode.this.addEventListener("DOMNodeRemoved", this, true); + } + + void detach() + { + if (current != null) + current.detach(); + current = null; + + DomNode.this.removeEventListener("DOMNodeInserted", this, true); + DomNode.this.removeEventListener("DOMNodeRemoved", this, true); + } + + public short acceptNode(Node element) + { + if (element == DomNode.this) + { + return FILTER_SKIP; + } + + // use namespace-aware matching ... + if (elementURI != null) + { + if (!(matchAnyURI + || elementURI.equals(element.getNamespaceURI()))) + { + return FILTER_SKIP; + } + if (!(matchAnyName + || elementName.equals(element.getLocalName()))) + { + return FILTER_SKIP; + } + + // ... or qName-based kind. + } + else + { + if (!(matchAnyName + || elementName.equals(element.getNodeName()))) + { + return FILTER_SKIP; + } + } + return FILTER_ACCEPT; + } + + private DomIterator createIterator() + { + return new DomIterator(DomNode.this, + NodeFilter.SHOW_ELEMENT, + this, /* filter */ + true /* expand entity refs */ + ); + } + + public void handleEvent(Event e) + { + MutationEvent mutation = (MutationEvent) e; + Node related = mutation.getRelatedNode(); + + // XXX if it's got children ... check all kids too, they + // will invalidate our saved index + + if (related.getNodeType() != Node.ELEMENT_NODE || + related.getNodeName() != elementName || + related.getNamespaceURI() != elementURI) + { + return; + } + + if (current != null) + current.detach(); + current = null; + } + + public Node item(int index) + { + if (current == null) + { + current = createIterator(); + lastIndex = -1; + } + + // last node or before? go backwards + if (index <= lastIndex) { + while (index != lastIndex) { + current.previousNode (); + lastIndex--; + } + Node ret = current.previousNode (); + current.detach(); + current = null; + return ret; + } + + // somewhere after last node + while (++lastIndex != index) + current.nextNode (); + + Node ret = current.nextNode (); + current.detach(); + current = null; + return ret; + } + + public int getLength() + { + int retval = 0; + NodeIterator iter = createIterator(); + + while (iter.nextNode() != null) + { + retval++; + } + iter.detach(); + return retval; + } + + } + + // + // EventTarget support + // + static final class ListenerRecord + { + + String type; + EventListener listener; + boolean useCapture; + + // XXX use JDK 1.2 java.lang.ref.WeakReference to listener, + // and we can both get rid of "shadow" classes and remove + // the need for applications to apply similar trix ... but + // JDK 1.2 support isn't generally available yet + + ListenerRecord(String type, EventListener listener, boolean useCapture) + { + this.type = type.intern(); + this.listener = listener; + this.useCapture = useCapture; + } + + public boolean equals(Object o) + { + ListenerRecord rec = (ListenerRecord)o; + return listener == rec.listener + && useCapture == rec.useCapture + && type == rec.type; + } + + public int hashCode() + { + return listener.hashCode() ^ type.hashCode(); + } + } + + /** + * DOM L2 (Events) + * Returns an instance of the specified type of event object. + * Understands about DOM Mutation, HTML, and UI events. + * + *

If the name of the event type begins with "USER-", then an object + * implementing the "Event" class will be returned; this provides a + * limited facility for application-defined events to use the DOM event + * infrastructure. Alternatively, use one of the standard DOM event + * classes and initialize it using use such a "USER-" event type name; + * or defin, instantiate, and initialize an application-specific subclass + * of DomEvent and pass that to dispatchEvent(). + * + * @param eventType Identifies the particular DOM feature module + * defining the type of event, such as "MutationEvents". + * The event "name" is a different kind of "type". + */ + public Event createEvent(String eventType) + { + eventType = eventType.toLowerCase(); + + if ("mutationevents".equals(eventType)) + { + return new DomEvent.DomMutationEvent(null); + } + + if ("htmlevents".equals(eventType) + || "events".equals(eventType) + || "user-events".equals(eventType)) + { + return new DomEvent(null); + } + + if ("uievents".equals(eventType)) + { + return new DomEvent.DomUIEvent(null); + } + + // mouse events + + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + eventType, null, 0); + } + + /** + * DOM L2 (Events) + * Registers an event listener's interest in a class of events. + */ + public final void addEventListener(String type, + EventListener listener, + boolean useCapture) + { + // prune duplicates + ListenerRecord record; + + record = new ListenerRecord(type, listener, useCapture); + listeners.add(record); + nListeners = listeners.size(); + } + + // XXX this exception should be discarded from DOM + + // this class can be instantiated, unlike the one in the spec + static final class DomEventException + extends EventException + { + + DomEventException() + { + super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type"); + } + + } + + /** + * DOM L2 (Events) + * Delivers an event to all relevant listeners, returning true if the + * caller should perform their default action. Note that the event + * must have been provided by the createEvent() method on this + * class, else it can't be dispatched. + * + * @see #createEvent + * + * @exception NullPointerException When a null event is passed. + * @exception ClassCastException When the event wasn't provided by + * the createEvent method, or otherwise isn't a DomEvent. + * @exception EventException If the event type wasn't specified + */ + public final boolean dispatchEvent(Event event) + throws EventException + { + DomEvent e = (DomEvent) event; + DomNode[] ancestors = null; + int ancestorMax = 0; + boolean haveDispatchDataLock = false; + + if (e.type == null) + { + throw new DomEventException(); + } + + e.doDefault = true; + e.target = this; + + // + // Typical case: one nonrecursive dispatchEvent call at a time + // for this class. If that's our case, we can avoid allocating + // garbage, which is overall a big win. Even with advanced GCs + // that deal well with short-lived garbage, and wayfast allocators, + // it still helps. + // + // Remember -- EVERY mutation goes though here at least once. + // + // When populating a DOM tree, trying to send mutation events is + // the primary cost; this dominates the critical path. + // + try + { + DomNode current; + int index; + boolean haveAncestorRegistrations = false; + ListenerRecord[] notificationSet; + int ancestorLen; + + synchronized (lockNode) + { + if (!dispatchDataLock) + { + haveDispatchDataLock = dispatchDataLock = true; + notificationSet = DomNode.notificationSet; + ancestors = DomNode.ancestors; + } + else + { + notificationSet = new ListenerRecord[NOTIFICATIONS_INIT]; + ancestors = new DomNode[ANCESTORS_INIT]; + } + ancestorLen = ancestors.length; + } + + // Climb to the top of this subtree and handle capture, letting + // each node (from the top down) capture until one stops it or + // until we get to this one. + current = (parent == null) ? this : parent; + if (current.depth >= ANCESTORS_INIT) + { + DomNode[] newants = new DomNode[current.depth + 1]; + System.arraycopy(ancestors, 0, newants, 0, ancestors.length); + ancestors = newants; + ancestorLen = ancestors.length; + } + for (index = 0; index < ancestorLen; index++) + { + if (current == null || current.depth == 0) + break; + + if (current.nListeners != 0) + { + haveAncestorRegistrations = true; + } + ancestors [index] = current; + current = current.parent; + } + if (current.depth > 0) + { + throw new RuntimeException("dispatchEvent capture stack size"); + } + + ancestorMax = index; + e.stop = false; + + if (haveAncestorRegistrations) + { + e.eventPhase = Event.CAPTURING_PHASE; + while (!e.stop && index-- > 0) + { + current = ancestors [index]; + if (current.nListeners != 0) + { + notifyNode(e, current, true, notificationSet); + } + } + } + + // Always deliver events to the target node (this) + // unless stopPropagation was called. If we saw + // no registrations yet (typical!), we never will. + if (!e.stop && nListeners != 0) + { + e.eventPhase = Event.AT_TARGET; + notifyNode (e, this, false, notificationSet); + } + else if (!haveAncestorRegistrations) + { + e.stop = true; + } + + // If the event bubbles and propagation wasn't halted, + // walk back up the ancestor list. Stop bubbling when + // any bubbled event handler stops it. + + if (!e.stop && e.bubbles) + { + e.eventPhase = Event.BUBBLING_PHASE; + for (index = 0; + !e.stop + && index < ancestorMax + && (current = ancestors[index]) != null; + index++) + { + if (current.nListeners != 0) + { + notifyNode(e, current, false, notificationSet); + } + } + } + e.eventPhase = 0; + + // Caller chooses whether to perform the default + // action based on return from this method. + return e.doDefault; + + } + finally + { + if (haveDispatchDataLock) + { + // synchronize to force write ordering + synchronized (lockNode) + { + // null out refs to ensure they'll be GC'd + for (int i = 0; i < ancestorMax; i++) + { + ancestors [i] = null; + } + // notificationSet handled by notifyNode + + dispatchDataLock = false; + } + } + } + } + + private void notifyNode(DomEvent e, + DomNode current, + boolean capture, + ListenerRecord[] notificationSet) + { + int count = 0; + Iterator iter; + + iter = current.listeners.iterator(); + + // do any of this set of listeners get notified? + while (iter.hasNext()) + { + ListenerRecord rec = (ListenerRecord)iter.next(); + + if (rec.useCapture != capture) + { + continue; + } + if (!e.type.equals (rec.type)) + { + continue; + } + if (count >= notificationSet.length) + { + // very simple growth algorithm + int len = Math.max(notificationSet.length, 1); + ListenerRecord[] tmp = new ListenerRecord[len * 2]; + System.arraycopy(notificationSet, 0, tmp, 0, + notificationSet.length); + notificationSet = tmp; + } + notificationSet[count++] = rec; + } + iter = null; + + // Notify just those listeners + e.currentNode = current; + for (int i = 0; i < count; i++) + { + try + { + iter = current.listeners.iterator(); + // Late in the DOM CR process (3rd or 4th CR?) the + // removeEventListener spec became asymmetric with respect + // to addEventListener ... effect is now immediate. + while (iter.hasNext()) + { + ListenerRecord rec = (ListenerRecord)iter.next(); + + if (rec.equals(notificationSet[i])) + { + notificationSet[i].listener.handleEvent(e); + break; + } + } + iter = null; + } + catch (Exception x) + { + // ignore all exceptions + } + notificationSet[i] = null; // free for GC + } + } + + /** + * DOM L2 (Events) + * Unregisters an event listener. + */ + public final void removeEventListener(String type, + EventListener listener, + boolean useCapture) + { + listeners.remove(new ListenerRecord(type, listener, useCapture)); + nListeners = listeners.size(); + // no exceptions reported + } + + /** + * DOM L1 (relocated in DOM L2) + * In this node and all contained nodes (including attributes if + * relevant) merge adjacent text nodes. This is done while ignoring + * text which happens to use CDATA delimiters). + */ + public final void normalize() + { + // Suspend readonly status + boolean saved = readonly; + readonly = false; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean saved2 = ctx.readonly; + ctx.readonly = false; + switch (ctx.nodeType) + { + case TEXT_NODE: + case CDATA_SECTION_NODE: + while (ctx.next != null && + (ctx.next.nodeType == TEXT_NODE || + ctx.next.nodeType == CDATA_SECTION_NODE)) + { + Text text = (Text) ctx; + text.appendData(ctx.next.getNodeValue()); + removeChild(ctx.next); + } + break; + case ELEMENT_NODE: + NamedNodeMap attrs = ctx.getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + DomNode attr = (DomNode) attrs.item(i); + boolean saved3 = attr.readonly; + attr.readonly = false; + attr.normalize(); + attr.readonly = saved3; + } + // Fall through + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_REFERENCE_NODE: + ctx.normalize(); + break; + } + ctx.readonly = saved2; + } + readonly = saved; + } + + /** + * Returns true iff node types match, and either (a) both nodes have no + * namespace and their getNodeName() values are the same, or (b) both + * nodes have the same getNamespaceURI() and same getLocalName() values. + * + *

Note that notion of a "Per-Element-Type" attribute name scope, as + * found in a non-normative appendix of the XML Namespaces specification, + * is not supported here. Your application must implement that notion, + * typically by not bothering to check nameAndTypeEquals for attributes + * without namespace URIs unless you already know their elements are + * nameAndTypeEquals. + */ + public boolean nameAndTypeEquals(Node other) + { + if (other == this) + { + return true; + } + // node types must match + if (nodeType != other.getNodeType()) + { + return false; + } + + // if both have namespaces, do a "full" comparision + // this is a "global" partition + String ns1 = this.getNamespaceURI(); + String ns2 = other.getNamespaceURI(); + + if (ns1 != null && ns2 != null) + { + return ns1.equals(ns2) && + equal(getLocalName(), other.getLocalName()); + } + + // if neither has a namespace, this is a "no-namespace" name. + if (ns1 == null && ns2 == null) + { + if (!getNodeName().equals(other.getNodeName())) + { + return false; + } + // can test the non-normative "per-element-type" scope here. + // if this is an attribute node and both nodes have been bound + // to elements (!!), then return the nameAndTypeEquals() + // comparison of those elements. + return true; + } + + // otherwise they're unequal: one scoped, one not. + return false; + } + + // DOM Level 3 methods + + public String getBaseURI() + { + return (parent != null) ? parent.getBaseURI() : null; + } + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + /** + * DOM nodes have a natural ordering: document order. + */ + public final int compareTo(Object other) + { + if (other instanceof DomNode) + { + DomNode n1 = this; + DomNode n2 = (DomNode) other; + if (n1.owner != n2.owner) + { + return 0; + } + int d1 = n1.depth, d2 = n2.depth; + int delta = d1 - d2; + while (d1 > d2) + { + n1 = n1.parent; + d1--; + } + while (d2 > d1) + { + n2 = n2.parent; + d2--; + } + int c = compareTo2(n1, n2); + return (c != 0) ? c : delta; + } + return 0; + } + + /** + * Compare two nodes at the same depth. + */ + final int compareTo2(DomNode n1, DomNode n2) + { + if (n1 == n2 || n1.depth == 0 || n2.depth == 0) + { + return 0; + } + int c = compareTo2(n1.parent, n2.parent); + return (c != 0) ? c : n1.index - n2.index; + } + + public final String getTextContent() + throws DOMException + { + return getTextContent(true); + } + + final String getTextContent(boolean topLevel) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + CPStringBuilder buffer = new CPStringBuilder(); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String textContent = ctx.getTextContent(false); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + if (((Text) this).isElementContentWhitespace()) + { + return ""; + } + return getNodeValue(); + case ATTRIBUTE_NODE: + return getNodeValue(); + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return topLevel ? getNodeValue() : ""; + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + for (DomNode ctx = first; ctx != null; ) + { + DomNode n = ctx.next; + removeChild(ctx); + ctx = n; + } + if (textContent != null) + { + Text text = owner.createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return this == other; + } + + public String lookupPrefix(String namespaceURI) + { + return (parent == null || parent == owner) ? null : + parent.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + return (parent == null || parent == owner) ? false : + parent.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + return (parent == null || parent == owner) ? null : + parent.lookupNamespaceURI(prefix); + } + + public boolean isEqualNode(Node arg) + { + if (this == arg) + return true; + if (arg == null) + return false; + if (nodeType != arg.getNodeType()) + return false; + switch (nodeType) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + if (!equal(getLocalName(), arg.getLocalName()) || + !equal(getNamespaceURI(), arg.getNamespaceURI())) + return false; + break; + case PROCESSING_INSTRUCTION_NODE: + if (!equal(getNodeName(), arg.getNodeName()) || + !equal(getNodeValue(), arg.getNodeValue())) + return false; + break; + case COMMENT_NODE: + case TEXT_NODE: + case CDATA_SECTION_NODE: + if (!equal(getNodeValue(), arg.getNodeValue())) + return false; + break; + } + // Children + Node argCtx = arg.getFirstChild(); + getFirstChild(); // because of DomAttr lazy children + DomNode ctx = first; + for (; ctx != null && argCtx != null; ctx = ctx.next) + { + if (nodeType == DOCUMENT_NODE) + { + // Ignore whitespace outside document element + while (ctx != null && ctx.nodeType == TEXT_NODE) + ctx = ctx.next; + while (argCtx != null && ctx.getNodeType() == TEXT_NODE) + argCtx = argCtx.getNextSibling(); + if (ctx == null && argCtx != null) + return false; + else if (argCtx == null && ctx != null) + return false; + } + if (!ctx.isEqualNode(argCtx)) + return false; + argCtx = argCtx.getNextSibling(); + } + if (ctx != null || argCtx != null) + return false; + + // TODO DocumentType + return true; + } + + boolean equal(String arg1, String arg2) + { + return ((arg1 == null && arg2 == null) || + (arg1 != null && arg1.equals(arg2))); + } + + public Object getFeature(String feature, String version) + { + DOMImplementation impl = (nodeType == DOCUMENT_NODE) ? + ((Document) this).getImplementation() : owner.getImplementation(); + if (impl.hasFeature(feature, version)) + { + return this; + } + return null; + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + public String toString() + { + String nodeName = getNodeName(); + String nodeValue = getNodeValue(); + CPStringBuilder buf = new CPStringBuilder(getClass().getName()); + buf.append('['); + if (nodeName != null) + { + buf.append(nodeName); + } + if (nodeValue != null) + { + if (nodeName != null) + { + buf.append('='); + } + buf.append('\''); + buf.append(encode(nodeValue)); + buf.append('\''); + } + buf.append(']'); + return buf.toString(); + } + + String encode(String value) + { + CPStringBuilder buf = null; + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '\n') + { + if (buf == null) + { + buf = new CPStringBuilder(value.substring(0, i)); + } + buf.append("\\n"); + } + else if (c == '\r') + { + if (buf == null) + { + buf = new CPStringBuilder(value.substring(0, i)); + } + buf.append("\\r"); + } + else if (buf != null) + { + buf.append(c); + } + } + return (buf != null) ? buf.toString() : value; + } + + String nodeTypeToString(short nodeType) + { + switch (nodeType) + { + case ELEMENT_NODE: + return "ELEMENT_NODE"; + case ATTRIBUTE_NODE: + return "ATTRIBUTE_NODE"; + case TEXT_NODE: + return "TEXT_NODE"; + case CDATA_SECTION_NODE: + return "CDATA_SECTION_NODE"; + case DOCUMENT_NODE: + return "DOCUMENT_NODE"; + case DOCUMENT_TYPE_NODE: + return "DOCUMENT_TYPE_NODE"; + case COMMENT_NODE: + return "COMMENT_NODE"; + case PROCESSING_INSTRUCTION_NODE: + return "PROCESSING_INSTRUCTION_NODE"; + case DOCUMENT_FRAGMENT_NODE: + return "DOCUMENT_FRAGMENT_NODE"; + case ENTITY_NODE: + return "ENTITY_NODE"; + case ENTITY_REFERENCE_NODE: + return "ENTITY_REFERENCE_NODE"; + case NOTATION_NODE: + return "NOTATION_NODE"; + default: + return "UNKNOWN"; + } + } + + public void list(java.io.PrintStream out, int indent) + { + for (int i = 0; i < indent; i++) + out.print(" "); + out.println(toString()); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + ctx.list(out, indent + 1); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNodeIterator.java b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java new file mode 100644 index 000000000..9f9ec7e39 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java @@ -0,0 +1,328 @@ +/* DomNodeIterator.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; + +/** + * Node iterator and tree walker. + * + * @author Chris Burdess + */ +public class DomNodeIterator + implements NodeIterator, TreeWalker +{ + + Node root; + final int whatToShow; + final NodeFilter filter; + final boolean entityReferenceExpansion; + final boolean walk; + Node current; + + public DomNodeIterator(Node root, int whatToShow, NodeFilter filter, + boolean entityReferenceExpansion, boolean walk) + { + if (root == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.entityReferenceExpansion = entityReferenceExpansion; + this.walk = walk; + current = root; + } + + public Node getRoot() + { + return root; + } + + public int getWhatToShow() + { + return whatToShow; + } + + public NodeFilter getFilter() + { + return filter; + } + + public boolean getExpandEntityReferences() + { + return entityReferenceExpansion; + } + + public Node nextNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = root.getFirstChild(); + } + else if (walk) + { + ret = current.getFirstChild(); + if (ret == null) + { + ret = current.getNextSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getLastChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getNextSibling(); + } + } + } + else + { + ret = current.getNextSibling(); + } + current = (ret == null) ? current : ret; + } + while (!accept(ret)); + + return ret; + } + + public Node previousNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = current.getLastChild(); + } + else if (walk) + { + ret = current.getLastChild(); + if (ret == null) + { + ret = current.getPreviousSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getFirstChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getPreviousSibling(); + } + } + } + else + { + ret = current.getPreviousSibling(); + } + } + while (!accept(ret)); + current = (ret == null) ? current : ret; + return ret; + } + + public Node getCurrentNode() + { + return current; + } + + public void setCurrentNode(Node current) + throws DOMException + { + if (current == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.current = current; + } + + public Node parentNode() + { + Node ret = current.getParentNode(); + if (!accept (ret)) + { + ret = null; + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node firstChild () + { + Node ret = current.getFirstChild(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node lastChild() + { + Node ret = current.getLastChild(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node previousSibling() + { + Node ret = current.getPreviousSibling(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node nextSibling() + { + Node ret = current.getNextSibling(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public void detach() + { + root = null; + } + + boolean accept(Node node) + { + if (node == null) + { + return true; + } + boolean ret; + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0; + break; + case Node.CDATA_SECTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0; + break; + case Node.COMMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_COMMENT) != 0; + break; + case Node.DOCUMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT) != 0; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0; + break; + case Node.DOCUMENT_TYPE_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0; + break; + case Node.ELEMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_ELEMENT) != 0; + break; + case Node.ENTITY_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY) != 0; + break; + case Node.ENTITY_REFERENCE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0; + ret = ret && entityReferenceExpansion; + break; + case Node.NOTATION_NODE: + ret = (whatToShow & NodeFilter.SHOW_NOTATION) != 0; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0; + break; + case Node.TEXT_NODE: + ret = (whatToShow & NodeFilter.SHOW_TEXT) != 0; + break; + default: + ret = true; + } + if (ret && filter != null) + { + ret = (filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); + } + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNotation.java b/libjava/classpath/gnu/xml/dom/DomNotation.java new file mode 100644 index 000000000..abb0e9da9 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNotation.java @@ -0,0 +1,102 @@ +/* DomNotation.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.Notation; + +/** + *

"Notation" implementation. This is a non-core DOM class, supporting + * the "XML" feature.

+ * + *

Although unparsed entities using this notation can be detected using + * DOM, neither NOTATIONS nor ENTITY/ENTITIES attributes can be so detected. + * More, there is no portable way to construct a Notation node, so there's + * no way that vendor-neutral DOM construction APIs could even report a + * NOTATION used to identify the intended meaning of a ProcessingInstruction. + *

+ * + *

In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * @see DomPI + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNotation + extends DomExtern + implements Notation +{ + + /** + * Constructs a Notation node associated with the specified document, + * with the specified descriptive data. Note that at least one of + * the PUBLIC and SYSTEM identifiers must be provided; unlike other + * external objects in XML, notations may have only a PUBLIC identifier. + * + *

This constructor should only be invoked by a DomDoctype object + * as part of its declareNotation functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this notation is associated + * @param name Name of this notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, rovides the notation's SYSTEM identifier + */ + protected DomNotation(DomDocument owner, + String name, + String publicId, + String systemId) + { + super(NOTATION_NODE, owner, name, publicId, systemId); + makeReadonly(); + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNsNode.java b/libjava/classpath/gnu/xml/dom/DomNsNode.java new file mode 100644 index 000000000..55e351185 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNsNode.java @@ -0,0 +1,226 @@ +/* DomNsNode.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import javax.xml.XMLConstants; +import org.w3c.dom.DOMException; + +/** + *

Abstract implemention of namespace support. This facilitates + * sharing code for attribute and element nodes. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNsNode + extends DomNode +{ + + private String name; + private String namespace; + private String prefix; + private String localName; + + /** + * Constructs a node associated with the specified document, and + * with the specified namespace information. + * + * @param owner The document with which this entity is associated + * @param namespaceURI Combined with the local part of the name, + * this identifies a type of element or attribute; may be null. + * If this is the empty string, it is reassigned as null so that + * applications only need to test that case. + * @param name Name of this node, which may include a prefix + */ + // package private + DomNsNode(short nodeType, DomDocument owner, String namespaceURI, String name) + { + super(nodeType, owner); + setNodeName(name); + setNamespaceURI(namespaceURI); + } + + /** + * Constructs a node associated with the specified document, and + * with the specified namespace information. The prefix and local part + * are given explicitly rather than being computed. This allows them + * to be explicitly set to {@code null} as required by + * {@link Document#createElement(String)}. + * + * @param owner The document with which this entity is associated + * @param namespaceURI Combined with the local part of the name, + * this identifies a type of element or attribute; may be null. + * If this is the empty string, it is reassigned as null so that + * applications only need to test that case. + * @param name Name of this node, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + // package private + DomNsNode(short nodeType, DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(nodeType, owner); + this.name = name.intern(); + this.prefix = prefix == null ? null : prefix.intern(); + this.localName = localName == null ? null : localName.intern(); + setNamespaceURI(namespaceURI); + } + + /** + * DOM L1 + * Returns the node's name, including any namespace prefix. + */ + public final String getNodeName() + { + return name; + } + + final void setNodeName(String name) + { + this.name = name.intern(); + int index = name.indexOf(':'); + if (index == -1) + { + prefix = null; + localName = this.name; + } + else + { + prefix = name.substring(0, index).intern(); + localName = name.substring(index + 1).intern(); + } + } + + /** + * DOM L2 + * Returns the node's namespace URI + * or null if the node name is not namespace scoped. + */ + public final String getNamespaceURI() + { + return namespace; + } + + final void setNamespaceURI(String namespaceURI) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + namespace = (namespaceURI == null) ? null : namespaceURI.intern(); + } + + /** + * DOM L2 + * Returns any prefix part of the node's name (before any colon). + */ + public final String getPrefix() + { + return prefix; + } + + /** + * DOM L2 + * Assigns the prefix part of the node's name (before any colon). + */ + public final void setPrefix(String prefix) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + if (prefix == null) + { + name = localName; + return; + } + else if (namespace == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "can't set prefix, node has no namespace URI", + this, 0); + } + + DomDocument.checkName(prefix, "1.1".equals(owner.getXmlVersion())); + if (prefix.indexOf (':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "illegal prefix " + prefix, this, 0); + } + + if (XMLConstants.XML_NS_PREFIX.equals(prefix) + && !XMLConstants.XML_NS_URI.equals(namespace)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + if (namespace != null || getNodeType() != ATTRIBUTE_NODE) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns attribute prefix is reserved", + this, 0); + } + } + else if (getNodeType () == ATTRIBUTE_NODE + && (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:"))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "namespace declarations can't change names", + this, 0); + } + + this.prefix = prefix.intern(); + } + + /** + * DOM L2 + * Returns the local part of the node's name (after any colon). + */ + public final String getLocalName() + { + return localName; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java new file mode 100644 index 000000000..6d443a293 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java @@ -0,0 +1,146 @@ +/* DomProcessingInstruction.java -- + Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + *

"ProcessingInstruction" (PI) implementation. + * This is a non-core DOM class, supporting the "XML" feature.

+ * + *

Unlike other DOM APIs in the "XML" feature, this one fully + * exposes the functionality it describes. So there is no reason + * inherent in DOM to avoid using this API, unless you want to rely + * on NOTATION declarations to associate meaning with your PIs; + * there is no vendor-neutal way to record those notations in DOM.

+ * + *

Also of note is that PI support is part of SAX, so that XML + * systems using PIs can choose among multiple APIs.

+ * + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomProcessingInstruction + extends DomNode + implements ProcessingInstruction +{ + + private String target; + private String data; + + /** + * Constructs a ProcessingInstruction node associated with the + * specified document, with the specified data. + * + *

This constructor should only be invoked by a Document object as + * part of its createProcessingInstruction functionality, or through + * a subclass which is similarly used in a "Sub-DOM" style layer. + */ + protected DomProcessingInstruction(DomDocument owner, + String target, String data) + { + super(PROCESSING_INSTRUCTION_NODE, owner); + this.target = target; + this.data = data; + } + + /** + * DOM L1 + * Returns the target of the processing instruction. + */ + public final String getTarget() + { + return target; + } + + /** + * DOM L1 + * Returns the target of the processing instruction + * (same as getTarget). + */ + public final String getNodeName() + { + return target; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction. + */ + public final String getData() + { + return data; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction + * (same as getData). + */ + public final String getNodeValue() + { + return data; + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction; + * same as setNodeValue. + */ + public final void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction. + */ + public final void setNodeValue(String data) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + this.data = data; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomText.java b/libjava/classpath/gnu/xml/dom/DomText.java new file mode 100644 index 000000000..b74c5b4c2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomText.java @@ -0,0 +1,222 @@ +/* DomText.java -- + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Text; + +/** + *

"Text" implementation.

+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomText + extends DomCharacterData + implements Text +{ + + // NOTE: deleted unused per-instance "isIgnorable" + // support to reclaim its space. + + /** + * Constructs a text node associated with the specified + * document and holding the specified data. + * + *

This constructor should only be invoked by a Document object + * as part of its createTextNode functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + */ + protected DomText(DomDocument owner, String value) + { + super(TEXT_NODE, owner, value); + } + + protected DomText(DomDocument owner, char[] buf, int off, int len) + { + super(TEXT_NODE, owner, buf, off, len); + } + + // Used by DomCDATA + DomText(short nodeType, DomDocument owner, String value) + { + super(nodeType, owner, value); + } + + DomText(short nodeType, DomDocument owner, char[] buf, int off, int len) + { + super(nodeType, owner, buf, off, len); + } + + /** + * DOM L1 + * Returns the string "#text". + */ + // can't be 'final' with CDATA subclassing + public String getNodeName() + { + return "#text"; + } + + /** + * DOM L1 + * Splits this text node in two parts at the offset, returning + * the new text node (the sibling with the second part). + */ + public Text splitText(int offset) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + try + { + String text = getNodeValue(); + String before = text.substring(0, offset); + String after = text.substring(offset); + Text next; + + if (getNodeType() == TEXT_NODE) + { + next = owner.createTextNode(after); + } + else // CDATA_SECTION_NODE + { + next = owner.createCDATASection(after); + } + + if (this.next != null) + { + parent.insertBefore(next, this.next); + } + else + { + parent.appendChild(next); + } + setNodeValue(before); + return next; + + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + // DOM Level 3 + + public boolean isElementContentWhitespace() + { + if (parent != null) + { + DomDoctype doctype = (DomDoctype) owner.getDoctype(); + if (doctype != null) + { + DTDElementTypeInfo info = + doctype.getElementTypeInfo(parent.getNodeName()); + if (info != null) + { + if (info.model == null && info.model.indexOf("#PCDATA") != -1) + { + return false; + } + return getNodeValue().trim().length() == 0; + } + } + } + return false; + } + + public String getWholeText() + { + DomNode ref = this; + DomNode ctx; + for (ctx = previous; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.previous) + { + ref = ctx; + } + CPStringBuilder buf = new CPStringBuilder(ref.getNodeValue()); + for (ctx = ref.next; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.next) + { + buf.append(ctx.getNodeValue()); + } + return buf.toString (); + } + + public Text replaceWholeText(String content) + throws DOMException + { + boolean isEmpty = (content == null || content.length () == 0); + if (!isEmpty) + { + setNodeValue(content); + } + + DomNode ref = this; + DomNode ctx; + for (ctx = previous; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.previous) + { + ref = ctx; + } + ctx = ref.next; + if ((isEmpty || ref != this) && parent != null) + { + parent.removeChild(ref); + } + for (; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ref) + { + ref = ctx.next; + if ((isEmpty || ctx != this) && parent != null) + { + parent.removeChild(ctx); + } + } + return (isEmpty) ? null : this; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathExpression.java b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java new file mode 100644 index 000000000..0b6962930 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java @@ -0,0 +1,147 @@ +/* DomXPathExpression.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathNSResolver; +import org.w3c.dom.xpath.XPathResult; +import gnu.xml.xpath.DocumentOrderComparator; + +/** + * An XPath expression. + * + * @author Chris Burdess + */ +class DomXPathExpression +implements org.w3c.dom.xpath.XPathExpression +{ + + final DomDocument doc; + final XPathExpression expression; + final XPathNSResolver resolver; + + DomXPathExpression(DomDocument doc, String expression, + XPathNSResolver resolver) + throws XPathException + { + this.doc = doc; + this.resolver = resolver; + + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + if (resolver != null) + { + xpath.setNamespaceContext(new DomNSResolverContext(resolver)); + } + try + { + this.expression = xpath.compile(expression); + } + catch (XPathExpressionException e) + { + throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, + e.getMessage ()); + } + } + + public Object evaluate(Node contextNode, short type, Object result) + throws XPathException, DOMException + { + try + { + QName typeName = null; + switch (type) + { + case XPathResult.BOOLEAN_TYPE: + typeName = XPathConstants.BOOLEAN; + break; + case XPathResult.NUMBER_TYPE: + typeName = XPathConstants.NUMBER; + break; + case XPathResult.STRING_TYPE: + typeName = XPathConstants.STRING; + break; + case XPathResult.ANY_UNORDERED_NODE_TYPE: + case XPathResult.FIRST_ORDERED_NODE_TYPE: + typeName = XPathConstants.NODE; + break; + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + typeName = XPathConstants.NODESET; + break; + default: + throw new XPathException(XPathException.TYPE_ERR, null); + } + Object val = expression.evaluate(contextNode, typeName); + switch (type) + { + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + // Sort the nodes + List ns = new ArrayList((Collection) val); + Collections.sort(ns, new DocumentOrderComparator()); + val = ns; + } + return new DomXPathResult(val, type); + } + catch (javax.xml.xpath.XPathException e) + { + throw new XPathException(XPathException.TYPE_ERR, e.getMessage()); + } + } + + public String toString () + { + return getClass ().getName () + "[expression=" + expression + "]"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java new file mode 100644 index 000000000..fb0719a4e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java @@ -0,0 +1,64 @@ +/* DomXPathNSResolver.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * Generic XPath namespace resolver using a DOM Node. + * + * @author Chris Burdess + */ +class DomXPathNSResolver +implements XPathNSResolver +{ + + Node node; + + DomXPathNSResolver (Node node) + { + this.node = node; + } + + public String lookupNamespaceURI (String prefix) + { + return node.lookupNamespaceURI (prefix); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathResult.java b/libjava/classpath/gnu/xml/dom/DomXPathResult.java new file mode 100644 index 000000000..da8fcf513 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathResult.java @@ -0,0 +1,233 @@ +/* DomXPathResult.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.util.Collection; +import java.util.Iterator; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathResult; + +/** + * An XPath result object. + * + * @author Chris Burdess + */ +class DomXPathResult +implements XPathResult +{ + + final Object value; + final short type; + Iterator iterator; + + DomXPathResult (Object value, short requestedType) + { + this.value = value; + if (value instanceof Boolean) + { + type = XPathResult.BOOLEAN_TYPE; + } + else if (value instanceof Double) + { + type = XPathResult.NUMBER_TYPE; + } + else if (value instanceof String) + { + type = XPathResult.STRING_TYPE; + } + else if (value instanceof Collection) + { + Collection ns = (Collection) value; + switch (requestedType) + { + case XPathResult.ANY_TYPE: + case XPathResult.ANY_UNORDERED_NODE_TYPE: + type = (ns.size () == 1) ? XPathResult.FIRST_ORDERED_NODE_TYPE : + XPathResult.ORDERED_NODE_ITERATOR_TYPE; + break; + default: + type = requestedType; + } + iterator = ns.iterator (); + } + else + { + throw new IllegalArgumentException (); + } + } + + public boolean getBooleanValue() + { + if (type == XPathResult.BOOLEAN_TYPE) + { + return ((Boolean) value).booleanValue (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public boolean getInvalidIteratorState() + { + return iterator == null; + } + + public double getNumberValue() + { + if (type == XPathResult.NUMBER_TYPE) + { + return ((Double) value).doubleValue (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public short getResultType() + { + return type; + } + + public Node getSingleNodeValue() + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Collection ns = (Collection) value; + if (ns.isEmpty ()) + { + return null; + } + else + { + return (Node) ns.iterator ().next (); + } + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public int getSnapshotLength() + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + return ((Collection) value).size (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public String getStringValue() + { + if (type == XPathResult.STRING_TYPE) + { + return (String) value; + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public Node iterateNext() + { + if (iterator != null) + { + if (iterator.hasNext ()) + { + return (Node) iterator.next (); + } + else + { + iterator = null; + return null; + } + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public Node snapshotItem(int index) + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Collection ns = (Collection) value; + Node[] nodes = new Node[ns.size ()]; + ns.toArray (nodes); + return nodes[index]; + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public String toString () + { + return getClass ().getName () + "[type=" + typeName (type) + ",value=" + + value + ']'; + } + + private String typeName (short type) + { + switch (type) + { + case XPathResult.BOOLEAN_TYPE: + return "BOOLEAN_TYPE"; + case XPathResult.NUMBER_TYPE: + return "NUMBER_TYPE"; + case XPathResult.STRING_TYPE: + return "STRING_TYPE"; + case XPathResult.FIRST_ORDERED_NODE_TYPE: + return "FIRST_ORDERED_NODE_TYPE"; + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + return "ORDERED_NODE_ITERATOR_TYPE"; + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + return "ORDERED_NODE_SNAPSHOT_TYPE"; + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + return "UNORDERED_NODE_ITERATOR_TYPE"; + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + return "UNORDERED_NODE_SNAPSHOT_TYPE"; + default: + return "(unknown)"; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ImplementationList.java b/libjava/classpath/gnu/xml/dom/ImplementationList.java new file mode 100644 index 000000000..c99f55d0d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ImplementationList.java @@ -0,0 +1,70 @@ +/* ImplementationList.java -- + Copyright (C) 2004 Free Software Foundation, Inc.. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.xml.dom; + +import java.util.List; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; + +/** + * Implementation list for GNU JAXP. + * + * @author Chris Burdess + */ +public class ImplementationList + implements DOMImplementationList +{ + + private List list; + + ImplementationList(List list) + { + this.list = list; + } + + public int getLength() + { + return list.size(); + } + + public DOMImplementation item(int index) + { + return (DOMImplementation) list.get(index); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ImplementationSource.java b/libjava/classpath/gnu/xml/dom/ImplementationSource.java new file mode 100644 index 000000000..5f404423a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ImplementationSource.java @@ -0,0 +1,167 @@ +/* ImplementationSource.java -- + Copyright (C) 2004 Free Software Foundation, Inc.. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.xml.dom; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; +import org.w3c.dom.DOMImplementationSource; + +/** + * Implementation source for GNU JAXP. + * + * @author Chris Burdess + */ +public class ImplementationSource + implements DOMImplementationSource +{ + + private static final String DIGITS = "1234567890"; + + /* + * GNU DOM implementations. + */ + private static final DOMImplementation[] implementations; + + static + { + List acc = new ArrayList(); + acc.add(new gnu.xml.dom.DomImpl()); + try + { + Class t = Class.forName("gnu.xml.libxmlj.dom.GnomeDocumentBuilder"); + acc.add(t.newInstance()); + } + catch (Exception e) + { + // libxmlj not available + } + catch (UnsatisfiedLinkError e) + { + // libxmlj not available + } + implementations = new DOMImplementation[acc.size()]; + acc.toArray(implementations); + } + + public DOMImplementation getDOMImplementation(String features) + { + List available = getImplementations(features); + if (available.isEmpty()) + { + return null; + } + return (DOMImplementation) available.get(0); + } + + public DOMImplementationList getDOMImplementationList(String features) + { + List available = getImplementations(features); + return new ImplementationList(available); + } + + /** + * Returns a list of the implementations that support the specified + * features. + */ + private final List getImplementations(String features) + { + List available = new ArrayList(Arrays.asList(implementations)); + for (Iterator i = parseFeatures(features).iterator(); i.hasNext(); ) + { + String feature = (String) i.next(); + String version = null; + int si = feature.indexOf(' '); + if (si != -1) + { + version = feature.substring(si + 1); + feature = feature.substring(0, si); + } + for (Iterator j = available.iterator(); j.hasNext(); ) + { + DOMImplementation impl = (DOMImplementation) j.next(); + if (!impl.hasFeature(feature, version)) + { + j.remove(); + } + } + } + return available; + } + + /** + * Parses the feature list into feature tokens. + */ + final List parseFeatures(String features) + { + List list = new ArrayList(); + int pos = 0, start = 0; + int len = features.length(); + for (; pos < len; pos++) + { + char c = features.charAt(pos); + if (c == ' ') + { + if (pos + 1 < len && + DIGITS.indexOf(features.charAt(pos + 1)) == -1) + { + list.add(getFeature(features, start, pos)); + start = pos + 1; + } + } + } + if (pos > start) + { + list.add(getFeature(features, start, len)); + } + return list; + } + + final String getFeature(String features, int start, int end) + { + if (features.length() > 0 && features.charAt(start) == '+') + { + return features.substring(start + 1, end); + } + return features.substring(start, end); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/JAXPFactory.java b/libjava/classpath/gnu/xml/dom/JAXPFactory.java new file mode 100644 index 000000000..d7d399b5b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/JAXPFactory.java @@ -0,0 +1,308 @@ +/* JAXPFactory.java -- + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom; + +import java.io.IOException; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + + +/** + * DOM bootstrapping API, for use with JAXP. + * + * @see Consumer + * + * @author David Brownell + */ +public final class JAXPFactory + extends DocumentBuilderFactory +{ + + private static final String PROPERTY = "http://xml.org/sax/properties/"; + private static final String FEATURE = "http://xml.org/sax/features/"; + + private SAXParserFactory pf; + private boolean secureProcessing; + + /** + * Default constructor. + */ + public JAXPFactory() + { + } + + /** + * Constructs a JAXP document builder which uses the default + * JAXP SAX2 parser and the DOM implementation in this package. + */ + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + if (pf == null) + { + // Force use of AElfred2 since not all JAXP parsers + // conform very well to the SAX2 API spec ... + pf = new gnu.xml.aelfred2.JAXPFactory(); + // pf = SAXParserFactory.newInstance (); + } + + // JAXP default: false + pf.setValidating(isValidating()); + + // FIXME: this namespace setup may cause errors in some + // conformant SAX2 parsers, which we CAN patch up by + // splicing a "NSFilter" stage up front ... + + // JAXP default: false + pf.setNamespaceAware(isNamespaceAware()); + + try + { + // undo rude "namespace-prefixes=false" default + pf.setFeature(FEATURE + "namespace-prefixes", true); + + return new JAXPBuilder(pf.newSAXParser().getXMLReader(), this); + } + catch (SAXException e) + { + String msg = "can't create JAXP DocumentBuilder: " + e.getMessage(); + throw new ParserConfigurationException(msg); + } + } + + /** There seems to be no useful specification for attribute names */ + public void setAttribute(String name, Object value) + throws IllegalArgumentException + { + if ("http://java.sun.com/xml/jaxp/properties/schemaLanguage".equals(name)) + { + // TODO + } + else + { + throw new IllegalArgumentException(name); + } + } + + /** There seems to be no useful specification for attribute names */ + public Object getAttribute(String name) + throws IllegalArgumentException + { + throw new IllegalArgumentException(name); + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + + static final class JAXPBuilder + extends DocumentBuilder + implements ErrorHandler + { + + private Consumer consumer; + private XMLReader producer; + private DomImpl impl; + + JAXPBuilder(XMLReader parser, JAXPFactory factory) + throws ParserConfigurationException + { + impl = new DomImpl(); + + // set up consumer side + try + { + consumer = new Consumer(); + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getMessage()); + } + + // JAXP defaults: true, noise nodes are good (bleech) + consumer.setHidingReferences(factory.isExpandEntityReferences()); + consumer.setHidingComments(factory.isIgnoringComments()); + consumer.setHidingWhitespace(factory.isIgnoringElementContentWhitespace()); + consumer.setHidingCDATA(factory.isCoalescing()); + + // set up producer side + producer = parser; + producer.setContentHandler(consumer.getContentHandler()); + producer.setDTDHandler(consumer.getDTDHandler()); + + try + { + String id; + + // if validating, report validity errors, and default + // to treating them as fatal + if (factory.isValidating ()) + { + producer.setFeature(FEATURE + "validation", true); + producer.setErrorHandler(this); + } + + // always save prefix info, maybe do namespace processing + producer.setFeature(FEATURE + "namespace-prefixes", true); + producer.setFeature(FEATURE + "namespaces", + factory.isNamespaceAware()); + + // set important handlers + id = PROPERTY + "lexical-handler"; + producer.setProperty(id, consumer.getProperty(id)); + + id = PROPERTY + "declaration-handler"; + producer.setProperty(id, consumer.getProperty(id)); + + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getMessage()); + } + } + + public Document parse(InputSource source) + throws SAXException, IOException + { + producer.parse(source); + Document doc = consumer.getDocument(); + // TODO inputEncoding + doc.setDocumentURI(source.getSystemId()); + return doc; + } + + public boolean isNamespaceAware() + { + try + { + return producer.getFeature(FEATURE + "namespaces"); + } + catch (SAXException e) + { + // "can't happen" + throw new RuntimeException(e.getMessage()); + } + } + + public boolean isValidating() + { + try + { + return producer.getFeature(FEATURE + "validation"); + } + catch (SAXException e) + { + // "can't happen" + throw new RuntimeException(e.getMessage()); + } + } + + public void setEntityResolver(EntityResolver resolver) + { + producer.setEntityResolver(resolver); + } + + public void setErrorHandler(ErrorHandler handler) + { + producer.setErrorHandler(handler); + consumer.setErrorHandler(handler); + } + + public DOMImplementation getDOMImplementation() + { + return impl; + } + + public Document newDocument() + { + return new DomDocument(); + } + + // implementation of error handler that's used when validating + public void fatalError(SAXParseException e) + throws SAXException + { + throw e; + } + + public void error(SAXParseException e) + throws SAXException + { + throw e; + } + + public void warning(SAXParseException e) + throws SAXException + { + /* ignore */ + } + + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java new file mode 100644 index 000000000..4448dd580 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java @@ -0,0 +1,188 @@ +/* DomHTMLAnchorElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAnchorElement; + +/** + * An HTML 'A' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAnchorElement + extends DomHTMLElement + implements HTMLAnchorElement +{ + + protected DomHTMLAnchorElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public String getCoords() + { + return getHTMLAttribute("coords"); + } + + public void setCoords(String coords) + { + setHTMLAttribute("coords", coords); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getHreflang() + { + return getHTMLAttribute("hreflang"); + } + + public void setHreflang(String hreflang) + { + setHTMLAttribute("hreflang", hreflang); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getRel() + { + return getHTMLAttribute("rel"); + } + + public void setRel(String rel) + { + setHTMLAttribute("rel", rel); + } + + public String getRev() + { + return getHTMLAttribute("rev"); + } + + public void setRev(String rev) + { + setHTMLAttribute("rev", rev); + } + + public String getShape() + { + return getHTMLAttribute("shape"); + } + + public void setShape(String shape) + { + setHTMLAttribute("shape", shape); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java new file mode 100644 index 000000000..429fb0038 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java @@ -0,0 +1,187 @@ +/* DomHTMLAppletElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAppletElement; + +/** + * An HTML 'APPLET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAppletElement + extends DomHTMLElement + implements HTMLAppletElement +{ + + protected DomHTMLAppletElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCls() + { + return getHTMLAttribute("class"); + } + + public void setCls(String cls) + { + setHTMLAttribute("class", cls); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getArchive() + { + return getHTMLAttribute("archive"); + } + + public void setArchive(String archive) + { + setHTMLAttribute("archive", archive); + } + + public String getCode() + { + return getHTMLAttribute("code"); + } + + public void setCode(String code) + { + setHTMLAttribute("code", code); + } + + public String getCodeBase() + { + return getHTMLAttribute("codebase"); + } + + public void setCodeBase(String codeBase) + { + setHTMLAttribute("codebase", codeBase); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getObject() + { + return getHTMLAttribute("object"); + } + + public void setObject(String object) + { + setHTMLAttribute("object", object); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java new file mode 100644 index 000000000..728b3fdfc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java @@ -0,0 +1,138 @@ +/* DomHTMLAreaElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAreaElement; + +/** + * An HTML 'AREA' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAreaElement + extends DomHTMLElement + implements HTMLAreaElement +{ + + protected DomHTMLAreaElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getCoords() + { + return getHTMLAttribute("coords"); + } + + public void setCoords(String coords) + { + setHTMLAttribute("coords", coords); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public boolean getNoHref() + { + return getBooleanHTMLAttribute("nohref"); + } + + public void setNoHref(boolean nohref) + { + setBooleanHTMLAttribute("nohref", nohref); + } + + public String getShape() + { + return getHTMLAttribute("shape"); + } + + public void setShape(String shape) + { + setHTMLAttribute("shape", shape); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java new file mode 100644 index 000000000..5ad49c549 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java @@ -0,0 +1,68 @@ +/* DomHTMLBRElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBRElement; + +/** + * An HTML 'BR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBRElement + extends DomHTMLElement + implements HTMLBRElement +{ + + protected DomHTMLBRElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getClear() + { + return getHTMLAttribute("clear"); + } + + public void setClear(String clear) + { + setHTMLAttribute("clear", clear); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java new file mode 100644 index 000000000..99a0993ba --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java @@ -0,0 +1,78 @@ +/* DomHTMLBaseElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBaseElement; + +/** + * An HTML 'BASE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBaseElement + extends DomHTMLElement + implements HTMLBaseElement +{ + + protected DomHTMLBaseElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java new file mode 100644 index 000000000..73ec96dbd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java @@ -0,0 +1,88 @@ +/* DomHTMLBaseFontElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBaseFontElement; + +/** + * An HTML 'BASEFONT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBaseFontElement + extends DomHTMLElement + implements HTMLBaseFontElement +{ + + protected DomHTMLBaseFontElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getColor() + { + return getHTMLAttribute("color"); + } + + public void setColor(String color) + { + setHTMLAttribute("color", color); + } + + public String getFace() + { + return getHTMLAttribute("face"); + } + + public void setFace(String face) + { + setHTMLAttribute("face", face); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java new file mode 100644 index 000000000..d4528625b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java @@ -0,0 +1,118 @@ +/* DomHTMLBodyElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBodyElement; + +/** + * An HTML 'BODY' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBodyElement + extends DomHTMLElement + implements HTMLBodyElement +{ + + protected DomHTMLBodyElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getALink() + { + return getHTMLAttribute("alink"); + } + + public void setALink(String alink) + { + setHTMLAttribute("alink", alink); + } + + public String getBackground() + { + return getHTMLAttribute("background"); + } + + public void setBackground(String background) + { + setHTMLAttribute("background", background); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgcolor) + { + setHTMLAttribute("bgcolor", bgcolor); + } + + public String getLink() + { + return getHTMLAttribute("link"); + } + + public void setLink(String link) + { + setHTMLAttribute("link", link); + } + + public String getText() + { + return getHTMLAttribute("text"); + } + + public void setText(String text) + { + setHTMLAttribute("text", text); + } + + public String getVLink() + { + return getHTMLAttribute("vlink"); + } + + public void setVLink(String vlink) + { + setHTMLAttribute("vlink", vlink); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java new file mode 100644 index 000000000..696169ac2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java @@ -0,0 +1,119 @@ +/* DomHTMLButtonElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLButtonElement; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'BUTTON' element node. + * + * @author Chris Burdess + */ +public class DomHTMLButtonElement + extends DomHTMLElement + implements HTMLButtonElement +{ + + protected DomHTMLButtonElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java new file mode 100644 index 000000000..830028753 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java @@ -0,0 +1,225 @@ +/* DomHTMLCollection.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLOptionsCollection; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + * An HTML element collection. + * + * @author Chris Burdess + */ +class DomHTMLCollection + implements HTMLCollection, HTMLOptionsCollection, NodeList, NodeFilter +{ + + final DomHTMLDocument doc; + final Node root; + List nodeNames; + List attributeNames; + List results; + + DomHTMLCollection(DomHTMLDocument doc, Node root) + { + this.doc = doc; + this.root = root; + } + + // -- Node name and attribute filtering -- + + void addNodeName(String name) + { + if (nodeNames == null) + { + nodeNames = new LinkedList(); + } + nodeNames.add(name); + } + + void addAttributeName(String name) + { + if (attributeNames == null) + { + attributeNames = new LinkedList(); + } + attributeNames.add(name); + } + + public short acceptNode(Node n) + { + if (n.getNodeType() != Node.ELEMENT_NODE) + { + return NodeFilter.FILTER_SKIP; + } + String localName = n.getLocalName(); + if (localName == null) + { + localName = n.getNodeName(); + } + if (nodeNames != null && !acceptName(localName)) + { + return NodeFilter.FILTER_SKIP; + } + if (attributeNames != null && !acceptAttributes(n.getAttributes())) + { + return NodeFilter.FILTER_SKIP; + } + return NodeFilter.FILTER_ACCEPT; + } + + private boolean acceptName(String name) + { + for (Iterator i = nodeNames.iterator(); i.hasNext(); ) + { + String nodeName = (String) i.next(); + if (nodeName.equalsIgnoreCase(name)) + { + return true; + } + } + return false; + } + + private boolean acceptAttributes(NamedNodeMap attrs) + { + for (Iterator i = attributeNames.iterator(); i.hasNext(); ) + { + String attributeName = (String) i.next(); + Node attr = getNamedItem(attrs, attributeName); + if (attr != null) + { + // Check that attribute has a non-null value + String nodeValue = attr.getNodeValue(); + if (nodeValue != null && nodeValue.length() > 0) + { + return true; + } + } + } + return false; + } + + /** + * Case-insensitive version of getNamedItem. + */ + private Node getNamedItem(NamedNodeMap attrs, String name) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (name.equalsIgnoreCase(attrName)) + { + return attr; + } + } + return null; + } + + // -- Perform query -- + + void evaluate() + { + NodeIterator i = doc.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, + this, true); + results = new ArrayList(); + for (Node node = i.nextNode(); node != null; node = i.nextNode()) + { + results.add(node); + } + } + + // -- HTMLCollection/NodeList interface -- + + public int getLength() + { + return results.size(); + } + + public void setLength(int length) + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + + public Node item(int index) + { + return (Node) results.get(index); + } + + public Node namedItem(String name) + { + boolean xhtml = false; // FIXME detect XHTML document + for (Iterator i = results.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + NamedNodeMap attrs = node.getAttributes(); + Node attr = getNamedItem(attrs, "id"); + if (name.equals(attr.getTextContent())) + { + return node; + } + if (!xhtml) + { + attr = getNamedItem(attrs, "name"); + if (name.equals(attr.getTextContent())) + { + return node; + } + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java new file mode 100644 index 000000000..9acce856a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDListElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDListElement; + +/** + * An HTML 'DL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDListElement + extends DomHTMLElement + implements HTMLDListElement +{ + + protected DomHTMLDListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java new file mode 100644 index 000000000..e0f94a1ed --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDirectoryElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDirectoryElement; + +/** + * An HTML 'DIR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDirectoryElement + extends DomHTMLElement + implements HTMLDirectoryElement +{ + + protected DomHTMLDirectoryElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java new file mode 100644 index 000000000..66b3ac743 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDivElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDivElement; + +/** + * An HTML 'DIV' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDivElement + extends DomHTMLElement + implements HTMLDivElement +{ + + protected DomHTMLDivElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java new file mode 100644 index 000000000..1afed7beb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java @@ -0,0 +1,426 @@ +/* DomHTMLDocument.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDOMException; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLDocument; +import org.w3c.dom.html2.HTMLElement; + +/** + * An HTML document. + * This is the factory object used to create HTML elements. + * + * @author Chris Burdess + */ +public class DomHTMLDocument + extends DomDocument + implements HTMLDocument +{ + + private static final Class[] ELEMENT_PT = new Class[] { + DomHTMLDocument.class, + String.class, + String.class + }; + + private static Map ELEMENT_CLASSES; + static + { + Map map = new HashMap(); + map.put("a", DomHTMLAnchorElement.class); + map.put("applet", DomHTMLAppletElement.class); + map.put("area", DomHTMLAreaElement.class); + map.put("base", DomHTMLBaseElement.class); + map.put("basefont", DomHTMLBaseFontElement.class); + map.put("body", DomHTMLBodyElement.class); + map.put("br", DomHTMLBRElement.class); + map.put("button", DomHTMLButtonElement.class); + map.put("dir", DomHTMLDirectoryElement.class); + map.put("div", DomHTMLDivElement.class); + map.put("dlist", DomHTMLDListElement.class); + map.put("embed", DomHTMLEmbedElement.class); + map.put("fieldset", DomHTMLFieldSetElement.class); + map.put("font", DomHTMLFontElement.class); + map.put("form", DomHTMLFormElement.class); + map.put("frame", DomHTMLFrameElement.class); + map.put("frameset", DomHTMLFrameSetElement.class); + map.put("head", DomHTMLHeadElement.class); + map.put("h1", DomHTMLHeadingElement.class); + map.put("h2", DomHTMLHeadingElement.class); + map.put("h3", DomHTMLHeadingElement.class); + map.put("h4", DomHTMLHeadingElement.class); + map.put("h5", DomHTMLHeadingElement.class); + map.put("h6", DomHTMLHeadingElement.class); + map.put("html", DomHTMLHtmlElement.class); + map.put("iframe", DomHTMLIFrameElement.class); + map.put("img", DomHTMLImageElement.class); + map.put("input", DomHTMLInputElement.class); + map.put("isindex", DomHTMLIsIndexElement.class); + map.put("label", DomHTMLLabelElement.class); + map.put("legend", DomHTMLLegendElement.class); + map.put("li", DomHTMLLIElement.class); + map.put("link", DomHTMLLinkElement.class); + map.put("map", DomHTMLMapElement.class); + map.put("menu", DomHTMLMenuElement.class); + map.put("meta", DomHTMLMetaElement.class); + map.put("ins", DomHTMLModElement.class); + map.put("del", DomHTMLModElement.class); + map.put("object", DomHTMLObjectElement.class); + map.put("ol", DomHTMLOListElement.class); + map.put("optgroup", DomHTMLOptGroupElement.class); + map.put("option", DomHTMLOptionElement.class); + map.put("p", DomHTMLParagraphElement.class); + map.put("param", DomHTMLParamElement.class); + map.put("pre", DomHTMLPreElement.class); + map.put("q", DomHTMLQuoteElement.class); + map.put("blockquote", DomHTMLQuoteElement.class); + map.put("script", DomHTMLScriptElement.class); + map.put("select", DomHTMLSelectElement.class); + map.put("style", DomHTMLStyleElement.class); + map.put("caption", DomHTMLTableCaptionElement.class); + map.put("th", DomHTMLTableCellElement.class); + map.put("td", DomHTMLTableCellElement.class); + map.put("col", DomHTMLTableColElement.class); + map.put("colgroup", DomHTMLTableColElement.class); + map.put("table", DomHTMLTableElement.class); + map.put("tr", DomHTMLTableRowElement.class); + map.put("thead", DomHTMLTableSectionElement.class); + map.put("tfoot", DomHTMLTableSectionElement.class); + map.put("tbody", DomHTMLTableSectionElement.class); + map.put("textarea", DomHTMLTextAreaElement.class); + map.put("title", DomHTMLTitleElement.class); + map.put("ul", DomHTMLUListElement.class); + ELEMENT_CLASSES = Collections.unmodifiableMap(map); + } + + private static Set HTML_NS_URIS; + static + { + Set set = new HashSet(); + set.add("http://www.w3.org/TR/html4/strict"); + set.add("http://www.w3.org/TR/html4/loose"); + set.add("http://www.w3.org/TR/html4/frameset"); + set.add("http://www.w3.org/1999/xhtml"); + set.add("http://www.w3.org/TR/xhtml1/strict"); + set.add("http://www.w3.org/TR/xhtml1/loose"); + set.add("http://www.w3.org/TR/xhtml1/frameset"); + HTML_NS_URIS = Collections.unmodifiableSet(set); + } + + /** + * Convenience constructor. + */ + public DomHTMLDocument() + { + this(new DomHTMLImpl()); + } + + /** + * Constructor. + * This is called by the DOMImplementation. + */ + public DomHTMLDocument(DomHTMLImpl impl) + { + super(impl); + } + + private Node getChildNodeByName(Node parent, String name) + { + for (Node ctx = parent.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (name.equalsIgnoreCase(ctx.getNodeName())) + { + return ctx; + } + } + return null; + } + + public String getTitle() + { + Node html = getDocumentElement(); + if (html != null) + { + Node head = getChildNodeByName(html, "head"); + if (head != null) + { + Node title = getChildNodeByName(head, "title"); + if (title != null) + { + return title.getTextContent(); + } + } + } + return null; + } + + public void setTitle(String title) + { + Node html = getDocumentElement(); + if (html == null) + { + html = createElement("html"); + appendChild(html); + } + Node head = getChildNodeByName(html, "head"); + if (head == null) + { + head = createElement("head"); + Node first = html.getFirstChild(); + if (first != null) + { + html.insertBefore(first, head); + } + else + { + html.appendChild(head); + } + } + Node titleNode = getChildNodeByName(head, "title"); + if (titleNode == null) + { + titleNode = createElement("title"); + Node first = head.getFirstChild(); + if (first != null) + { + head.insertBefore(first, titleNode); + } + else + { + head.appendChild(titleNode); + } + } + titleNode.setTextContent(title); + } + + public String getReferrer() + { + // TODO getReferrer + return null; + } + + public String getDomain() + { + try + { + URL url = new URL(getDocumentURI()); + return url.getHost(); + } + catch (MalformedURLException e) + { + return null; + } + } + + public String getURL() + { + return getDocumentURI(); + } + + public HTMLElement getBody() + { + Node html = getDocumentElement(); + if (html != null) + { + Node body = getChildNodeByName(html, "body"); + if (body == null) + { + body = getChildNodeByName(html, "frameset"); + } + return (HTMLElement) body; + } + return null; + } + + public void setBody(HTMLElement body) + { + Node html = getDocumentElement(); + if (html == null) + { + html = createElement("html"); + appendChild(html); + } + Node ref = getBody(); + if (ref == null) + { + html.appendChild(body); + } + else + { + html.replaceChild(body, ref); + } + } + + public HTMLCollection getImages() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("img"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getApplets() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("embed"); + ret.addNodeName("object"); + ret.addNodeName("applet"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getLinks() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("area"); + ret.addNodeName("a"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getForms() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("form"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getAnchors() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("a"); + ret.addAttributeName("name"); + ret.evaluate(); + return ret; + } + + public String getCookie() + { + // TODO getCookie + return null; + } + + public void setCookie(String cookie) + { + // TODO setCookie + } + + public void open() + { + // TODO open + } + + public void close() + { + // TODO close + } + + public void write(String text) + { + // TODO write + } + + public void writeln(String text) + { + // TODO write + } + + public NodeList getElementsByName(String name) + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName(name); + ret.evaluate(); + return ret; + // TODO xhtml: return only form controls (?) + } + + public Element createElement(String tagName) + { + return createElementNS(null, tagName); + } + + public Element createElementNS(String uri, String qName) + { + /* If a non-HTML element, use the default implementation. */ + if (uri != null && !HTML_NS_URIS.contains(uri)) + { + return super.createElementNS(uri, qName); + } + String localName = qName.toLowerCase(); + int ci = qName.indexOf(':'); + if (ci != -1) + { + localName = qName.substring(ci + 1); + } + Class t = (Class) ELEMENT_CLASSES.get(localName); + /* If a non-HTML element, use the default implementation. */ + if (t == null) + { + return super.createElementNS(uri, qName); + } + try + { + Constructor c = t.getDeclaredConstructor(ELEMENT_PT); + Object[] args = new Object[] { this, uri, qName }; + return (Element) c.newInstance(args); + } + catch (Exception e) + { + DOMException e2 = new DomDOMException(DOMException.TYPE_MISMATCH_ERR); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java new file mode 100644 index 000000000..deeefec60 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java @@ -0,0 +1,286 @@ +/* DomHTMLElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import gnu.xml.dom.DomElement; +import gnu.xml.dom.DomEvent; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.events.UIEvent; +import org.w3c.dom.html2.HTMLElement; + +/** + * Abstract implementation of an HTML element node. + * + * @author Chris Burdess + */ +public abstract class DomHTMLElement + extends DomElement + implements HTMLElement +{ + + protected DomHTMLElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + /** + * Returns the value of the specified attribute. + * The attribute name is case insensitive. + */ + protected String getHTMLAttribute(String name) + { + if (hasAttributes()) + { + NamedNodeMap attrs = getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (attrName.equalsIgnoreCase(name)) + { + return attr.getNodeValue(); + } + } + } + return ""; + } + + protected int getIntHTMLAttribute(String name) + { + String value = getHTMLAttribute(name); + if (value == null) + { + return -1; + } + try + { + return Integer.parseInt(value); + } + catch (NumberFormatException e) + { + return -1; + } + } + + protected boolean getBooleanHTMLAttribute(String name) + { + String value = getHTMLAttribute(name); + return value != null; + } + + /** + * Sets the value of the specified attribute. + * The attribute name is case insensitive. + */ + protected void setHTMLAttribute(String name, String value) + { + Node attr; + NamedNodeMap attrs = getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (attrName.equalsIgnoreCase(name)) + { + if (value != null) + { + attr.setNodeValue(value); + } + else + { + attrs.removeNamedItem(attr.getNodeName()); + } + return; + } + } + if (value != null) + { + // Create a new attribute + DomHTMLDocument doc = (DomHTMLDocument) getOwnerDocument(); + // XXX namespace URI for attribute? + attr = doc.createAttribute(name); + attr.setNodeValue(value); + } + } + + protected void setIntHTMLAttribute(String name, int value) + { + setHTMLAttribute(name, Integer.toString(value)); + } + + protected void setBooleanHTMLAttribute(String name, boolean value) + { + setHTMLAttribute(name, value ? name : null); + } + + /** + * Returns the first parent element with the specified name. + */ + protected Node getParentElement(String name) + { + for (Node parent = getParentNode(); parent != null; + parent = parent.getParentNode()) + { + String parentName = parent.getLocalName(); + if (parentName == null) + { + parentName = parent.getNodeName(); + } + if (name.equalsIgnoreCase(parentName)) + { + return parent; + } + } + return null; + } + + /** + * Returns the first child element with the specified name. + */ + protected Node getChildElement(String name) + { + for (Node child = getFirstChild(); child != null; + child = child.getNextSibling()) + { + String childName = child.getLocalName(); + if (childName == null) + { + childName = child.getLocalName(); + } + if (name.equalsIgnoreCase(childName)) + { + return child; + } + } + return null; + } + + /** + * Returns the index of this element among elements of the same name, + * relative to its parent. + */ + protected int getIndex() + { + int index = 0; + Node parent = getParentNode(); + if (parent != null) + { + for (Node ctx = parent.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + protected void dispatchUIEvent(String name) + { + UIEvent event = new DomEvent.DomUIEvent(name); + dispatchEvent(event); + } + + public String getId() + { + return getHTMLAttribute("id"); + } + + public void setId(String id) + { + setHTMLAttribute("id", id); + } + + public String getTitle() + { + return getHTMLAttribute("title"); + } + + public void setTitle(String title) + { + setHTMLAttribute("title", title); + } + + public String getLang() + { + return getHTMLAttribute("lang"); + } + + public void setLang(String lang) + { + setHTMLAttribute("lang", lang); + } + + public String getDir() + { + return getHTMLAttribute("dir"); + } + + public void setDir(String dir) + { + setHTMLAttribute("dir", dir); + } + + public String getClassName() + { + return getHTMLAttribute("class"); + } + + public void setClassName(String className) + { + setHTMLAttribute("class", className); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java new file mode 100644 index 000000000..221131533 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java @@ -0,0 +1,129 @@ +/* DomHTMLEmbedElement.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.xml.dom.html2; + +public class DomHTMLEmbedElement + extends DomHTMLAppletElement +{ + protected DomHTMLEmbedElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getJavaObject() + { + return getHTMLAttribute("java_object"); + } + + public void setJavaObject(String object) + { + setHTMLAttribute("java_object", object); + } + + public String getJavaCodeBase() + { + return getHTMLAttribute("java_codebase"); + } + + public void setJavaCodeBase(String codeBase) + { + setHTMLAttribute("java_codebase", codeBase); + } + + public String getJavaArchive() + { + return getHTMLAttribute("java_archive"); + } + + public void setJavaArchive(String archive) + { + setHTMLAttribute("java_archive", archive); + } + + public void setJavaCode(String code) + { + setHTMLAttribute("java_code", code); + } + + public String getJavaCode() + { + return getHTMLAttribute("java_code"); + } + + public void setJavaType(String type) + { + setHTMLAttribute("java_type", type); + } + + public String getJavaType() + { + return getHTMLAttribute("java_type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public String getPluginsPage() + { + return getHTMLAttribute("pluginspage"); + } + + public void setPluginsPage(String pluginspage) + { + setHTMLAttribute("pluginspage", pluginspage); + } + + public String getMayscript() + { + return getHTMLAttribute("mayscript"); + } + + public void setMayscript(String mayscript) + { + setHTMLAttribute("mayscript", mayscript); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java new file mode 100644 index 000000000..252cd3d2b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java @@ -0,0 +1,64 @@ +/* DomHTMLFieldSetElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFieldSetElement; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'FIELDSET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFieldSetElement + extends DomHTMLElement + implements HTMLFieldSetElement +{ + + protected DomHTMLFieldSetElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java new file mode 100644 index 000000000..5bfbb6f36 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java @@ -0,0 +1,88 @@ +/* DomHTMLFontElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFontElement; + +/** + * An HTML 'FONT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFontElement + extends DomHTMLElement + implements HTMLFontElement +{ + + protected DomHTMLFontElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getColor() + { + return getHTMLAttribute("color"); + } + + public void setColor(String color) + { + setHTMLAttribute("color", color); + } + + public String getFace() + { + return getHTMLAttribute("face"); + } + + public void setFace(String face) + { + setHTMLAttribute("face", face); + } + + public String getSize() + { + return getHTMLAttribute("size"); + } + + public void setSize(String size) + { + setHTMLAttribute("size", size); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java new file mode 100644 index 000000000..9fe2ae802 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java @@ -0,0 +1,149 @@ +/* DomHTMLFormElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'FORM' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFormElement + extends DomHTMLElement + implements HTMLFormElement +{ + + protected DomHTMLFormElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLCollection getElements() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("input"); + ret.addNodeName("button"); + ret.addNodeName("select"); + ret.addNodeName("textarea"); + ret.addNodeName("isindex"); + ret.addNodeName("label"); + ret.addNodeName("option"); + ret.evaluate(); + return ret; + } + + public int getLength() + { + return getElements().getLength(); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getAcceptCharset() + { + return getHTMLAttribute("accept-charset"); + } + + public void setAcceptCharset(String acceptCharset) + { + setHTMLAttribute("accept-charset", acceptCharset); + } + + public String getAction() + { + return getHTMLAttribute("action"); + } + + public void setAction(String action) + { + setHTMLAttribute("action", action); + } + + public String getEnctype() + { + return getHTMLAttribute("enctype"); + } + + public void setEnctype(String enctype) + { + setHTMLAttribute("enctype", enctype); + } + + public String getMethod() + { + return getHTMLAttribute("method"); + } + + public void setMethod(String method) + { + setHTMLAttribute("method", method); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public void submit() + { + dispatchUIEvent("submit"); + } + + public void reset() + { + dispatchUIEvent("reset"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java new file mode 100644 index 000000000..2465c4b89 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java @@ -0,0 +1,145 @@ +/* DomHTMLFrameElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLFrameElement; + +/** + * An HTML 'FRAME' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFrameElement + extends DomHTMLElement + implements HTMLFrameElement +{ + + protected DomHTMLFrameElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getFrameBorder() + { + return getHTMLAttribute("frameborder"); + } + + public void setFrameBorder(String frameBorder) + { + setHTMLAttribute("frameborder", frameBorder); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getMarginHeight() + { + return getHTMLAttribute("marginheight"); + } + + public void setMarginHeight(String marginHeight) + { + setHTMLAttribute("marginheight", marginHeight); + } + + public String getMarginWidth() + { + return getHTMLAttribute("marginwidth"); + } + + public void setMarginWidth(String marginWidth) + { + setHTMLAttribute("marginwidth", marginWidth); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getNoResize() + { + return getBooleanHTMLAttribute("noresize"); + } + + public void setNoResize(boolean noResize) + { + setBooleanHTMLAttribute("noresize", noResize); + } + + public String getScrolling() + { + return getHTMLAttribute("scrolling"); + } + + public void setScrolling(String scrolling) + { + setHTMLAttribute("scrolling", scrolling); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java new file mode 100644 index 000000000..dae9430fb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java @@ -0,0 +1,78 @@ +/* DomHTMLFrameSetElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFrameSetElement; + +/** + * An HTML 'FRAMESET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFrameSetElement + extends DomHTMLElement + implements HTMLFrameSetElement +{ + + protected DomHTMLFrameSetElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCols() + { + return getHTMLAttribute("cols"); + } + + public void setCols(String cols) + { + setHTMLAttribute("cols", cols); + } + + public String getRows() + { + return getHTMLAttribute("rows"); + } + + public void setRows(String rows) + { + setHTMLAttribute("rows", rows); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java new file mode 100644 index 000000000..e27ef5595 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java @@ -0,0 +1,98 @@ +/* DomHTMLHRElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHRElement; + +/** + * An HTML 'HR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHRElement + extends DomHTMLElement + implements HTMLHRElement +{ + + protected DomHTMLHRElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public boolean getNoShade() + { + return getBooleanHTMLAttribute("noshade"); + } + + public void setNoShade(boolean noShade) + { + setBooleanHTMLAttribute("noshade", noShade); + } + + public String getSize() + { + return getHTMLAttribute("size"); + } + + public void setSize(String size) + { + setHTMLAttribute("size", size); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java new file mode 100644 index 000000000..4a8ef995b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHeadElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHeadElement; + +/** + * An HTML 'HEAD' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHeadElement + extends DomHTMLElement + implements HTMLHeadElement +{ + + protected DomHTMLHeadElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getProfile() + { + return getHTMLAttribute("profile"); + } + + public void setProfile(String profile) + { + setHTMLAttribute("profile", profile); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java new file mode 100644 index 000000000..6e78e9004 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHeadingElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHeadingElement; + +/** + * An HTML 'H1', 'H2', 'H3', 'H4', 'H5', or 'H6' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHeadingElement + extends DomHTMLElement + implements HTMLHeadingElement +{ + + protected DomHTMLHeadingElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java new file mode 100644 index 000000000..73f7243ed --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHtmlElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHtmlElement; + +/** + * An HTML 'HTML' top-level element node. + * + * @author Chris Burdess + */ +public class DomHTMLHtmlElement + extends DomHTMLElement + implements HTMLHtmlElement +{ + + protected DomHTMLHtmlElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getVersion() + { + return getHTMLAttribute("version"); + } + + public void setVersion(String version) + { + setHTMLAttribute("version", version); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java new file mode 100644 index 000000000..1a58fb73e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java @@ -0,0 +1,165 @@ +/* DomHTMLIFrameElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLIFrameElement; + +/** + * An HTML 'IFRAME' element node. + * + * @author Chris Burdess + */ +public class DomHTMLIFrameElement + extends DomHTMLElement + implements HTMLIFrameElement +{ + + protected DomHTMLIFrameElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getFrameBorder() + { + return getHTMLAttribute("frameborder"); + } + + public void setFrameBorder(String frameBorder) + { + setHTMLAttribute("frameborder", frameBorder); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getMarginHeight() + { + return getHTMLAttribute("marginheight"); + } + + public void setMarginHeight(String marginHeight) + { + setHTMLAttribute("marginheight", marginHeight); + } + + public String getMarginWidth() + { + return getHTMLAttribute("marginwidth"); + } + + public void setMarginWidth(String marginWidth) + { + setHTMLAttribute("marginwidth", marginWidth); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getScrolling() + { + return getHTMLAttribute("scrolling"); + } + + public void setScrolling(String scrolling) + { + setHTMLAttribute("scrolling", scrolling); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java new file mode 100644 index 000000000..c5d294c6f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java @@ -0,0 +1,178 @@ +/* DomHTMLImageElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLImageElement; + +/** + * An HTML 'IMG' element node. + * + * @author Chris Burdess + */ +public class DomHTMLImageElement + extends DomHTMLElement + implements HTMLImageElement +{ + + protected DomHTMLImageElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public int getHeight() + { + return getIntHTMLAttribute("height"); + } + + public void setHeight(int height) + { + setIntHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public boolean getIsMap() + { + return getBooleanHTMLAttribute("ismap"); + } + + public void setIsMap(boolean isMap) + { + setBooleanHTMLAttribute("ismap", isMap); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public int getWidth() + { + return getIntHTMLAttribute("width"); + } + + public void setWidth(int width) + { + setIntHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java new file mode 100644 index 000000000..a5faee5ce --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java @@ -0,0 +1,66 @@ +/* DomHTMLImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomImpl; +import org.w3c.dom.Document; + +/** + * Specialised DOMImplementation for creating HTML documents. + * + * @author Chris Burdess + */ +public class DomHTMLImpl + extends DomImpl +{ + + protected Document createDocument() + { + return new DomHTMLDocument(this); + } + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + return this; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java new file mode 100644 index 000000000..21201889d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java @@ -0,0 +1,265 @@ +/* DomHTMLInputElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLInputElement; + +/** + * An HTML 'INPUT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLInputElement + extends DomHTMLElement + implements HTMLInputElement +{ + + protected String value; + protected Boolean checked; + + protected DomHTMLInputElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getDefaultValue() + { + return getHTMLAttribute("value"); + } + + public void setDefaultValue(String defaultValue) + { + setHTMLAttribute("value", defaultValue); + } + + public boolean getDefaultChecked() + { + return getBooleanHTMLAttribute("checked"); + } + + public void setDefaultChecked(boolean defaultChecked) + { + setBooleanHTMLAttribute("checked", defaultChecked); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccept() + { + return getHTMLAttribute("accept"); + } + + public void setAccept(String accept) + { + setHTMLAttribute("accept", accept); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public boolean getChecked() + { + if (checked == null) + { + checked = Boolean.valueOf(getDefaultChecked()); + } + return checked.booleanValue(); + } + + public void setChecked(boolean checked) + { + this.checked = Boolean.valueOf(checked); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public int getMaxLength() + { + return getIntHTMLAttribute("maxLength"); + } + + public void setMaxLength(int maxLength) + { + setIntHTMLAttribute("maxLength", maxLength); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getReadOnly() + { + return getBooleanHTMLAttribute("readonly"); + } + + public void setReadOnly(boolean readOnly) + { + setBooleanHTMLAttribute("readonly", readOnly); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public String getValue() + { + if (value == null) + { + value = getDefaultValue(); + } + return value; + } + + public void setValue(String value) + { + this.value = value; + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + + public void select() + { + dispatchUIEvent("select"); + } + + public void click() + { + dispatchUIEvent("click"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java new file mode 100644 index 000000000..8578cb6c0 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java @@ -0,0 +1,74 @@ +/* DomHTMLIsIndexElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLIsIndexElement; + +/** + * An HTML 'ISINDEX' element node. + * + * @author Chris Burdess + */ +public class DomHTMLIsIndexElement + extends DomHTMLElement + implements HTMLIsIndexElement +{ + + protected DomHTMLIsIndexElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getPrompt() + { + return getHTMLAttribute("prompt"); + } + + public void setPrompt(String prompt) + { + setHTMLAttribute("prompt", prompt); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java new file mode 100644 index 000000000..cab1412dd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java @@ -0,0 +1,78 @@ +/* DomHTMLLIElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLLIElement; + +/** + * An HTML 'LI' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLIElement + extends DomHTMLElement + implements HTMLLIElement +{ + + protected DomHTMLLIElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public int getValue() + { + return getIntHTMLAttribute("value"); + } + + public void setValue(int value) + { + setIntHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java new file mode 100644 index 000000000..96cfbaab5 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java @@ -0,0 +1,84 @@ +/* DomHTMLLabelElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLLabelElement; + +/** + * An HTML 'LABEL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLabelElement + extends DomHTMLElement + implements HTMLLabelElement +{ + + protected DomHTMLLabelElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getHtmlFor() + { + return getHTMLAttribute("for"); + } + + public void setHtmlFor(String htmlFor) + { + setHTMLAttribute("for", htmlFor); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java new file mode 100644 index 000000000..045861cae --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java @@ -0,0 +1,84 @@ +/* DomHTMLLegendElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLLegendElement; + +/** + * An HTML 'LEGEND' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLegendElement + extends DomHTMLElement + implements HTMLLegendElement +{ + + protected DomHTMLLegendElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java new file mode 100644 index 000000000..292ec9305 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java @@ -0,0 +1,148 @@ +/* DomHTMLLinkElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLLinkElement; + +/** + * An HTML 'LINK' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLinkElement + extends DomHTMLElement + implements HTMLLinkElement +{ + + protected DomHTMLLinkElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getHreflang() + { + return getHTMLAttribute("hreflang"); + } + + public void setHreflang(String hreflang) + { + setHTMLAttribute("hreflang", hreflang); + } + + public String getMedia() + { + return getHTMLAttribute("media"); + } + + public void setMedia(String media) + { + setHTMLAttribute("media", media); + } + + public String getRel() + { + return getHTMLAttribute("rel"); + } + + public void setRel(String rel) + { + setHTMLAttribute("rel", rel); + } + + public String getRev() + { + return getHTMLAttribute("rev"); + } + + public void setRev(String rev) + { + setHTMLAttribute("rev", rev); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java new file mode 100644 index 000000000..4497b00e2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java @@ -0,0 +1,78 @@ +/* DomHTMLMapElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLMapElement; + +/** + * An HTML 'MAP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMapElement + extends DomHTMLElement + implements HTMLMapElement +{ + + protected DomHTMLMapElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLCollection getAreas() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("area"); + ret.evaluate(); + return ret; + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java new file mode 100644 index 000000000..2a6ff08f1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java @@ -0,0 +1,68 @@ +/* DomHTMLMenuElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLMenuElement; + +/** + * An HTML 'MENU' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMenuElement + extends DomHTMLElement + implements HTMLMenuElement +{ + + protected DomHTMLMenuElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java new file mode 100644 index 000000000..e555a4273 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java @@ -0,0 +1,98 @@ +/* DomHTMLMetaElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLMetaElement; + +/** + * An HTML 'META' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMetaElement + extends DomHTMLElement + implements HTMLMetaElement +{ + + protected DomHTMLMetaElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getContent() + { + return getHTMLAttribute("content"); + } + + public void setContent(String content) + { + setHTMLAttribute("content", content); + } + + public String getHttpEquiv() + { + return getHTMLAttribute("http-equiv"); + } + + public void setHttpEquiv(String httpEquiv) + { + setHTMLAttribute("http-equiv", httpEquiv); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getScheme() + { + return getHTMLAttribute("scheme"); + } + + public void setScheme(String scheme) + { + setHTMLAttribute("scheme", scheme); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java new file mode 100644 index 000000000..8c158f48a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java @@ -0,0 +1,78 @@ +/* DomHTMLModElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLModElement; + +/** + * An HTML 'INS' or 'DEL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLModElement + extends DomHTMLElement + implements HTMLModElement +{ + + protected DomHTMLModElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCite() + { + return getHTMLAttribute("cite"); + } + + public void setCite(String cite) + { + setHTMLAttribute("cite", cite); + } + + public String getDateTime() + { + return getHTMLAttribute("datetime"); + } + + public void setDateTime(String dateTime) + { + setHTMLAttribute("datetime", dateTime); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java new file mode 100644 index 000000000..54f7fd46b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java @@ -0,0 +1,88 @@ +/* DomHTMLOListElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLOListElement; + +/** + * An HTML 'OL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOListElement + extends DomHTMLElement + implements HTMLOListElement +{ + + protected DomHTMLOListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + + public int getStart() + { + return getIntHTMLAttribute("start"); + } + + public void setStart(int start) + { + setIntHTMLAttribute("start", start); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java new file mode 100644 index 000000000..2ce5f45c3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java @@ -0,0 +1,320 @@ +/* DomHTMLObjectElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLObjectElement; + +/** + * An HTML 'OBJECT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLObjectElement + extends DomHTMLElement + implements HTMLObjectElement +{ + + protected DomHTMLObjectElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getCode() + { + return getHTMLAttribute("code"); + } + + public void setCode(String code) + { + setHTMLAttribute("code", code); + } + + public String getJavaCode() + { + return getHTMLAttribute("java_code"); + } + + public void setJavaCode(String code) + { + setHTMLAttribute("java_code", code); + } + + public String getObject() + { + return getHTMLAttribute("object"); + } + + public void setObject(String obj) + { + setHTMLAttribute("object", obj); + } + + public String getJavaObject() + { + return getHTMLAttribute("java_object"); + } + + public void setJavaObject(String obj) + { + setHTMLAttribute("java_object", obj); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getArchive() + { + return getHTMLAttribute("archive"); + } + + public void setArchive(String archive) + { + setHTMLAttribute("archive", archive); + } + + public String getJavaArchive() + { + return getHTMLAttribute("java_archive"); + } + + public void setJavaArchive(String archive) + { + setHTMLAttribute("java_archive", archive); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public String getCodeBase() + { + return getHTMLAttribute("codebase"); + } + + public void setCodeBase(String codeBase) + { + setHTMLAttribute("codebase", codeBase); + } + + public String getJavaCodeBase() + { + return getHTMLAttribute("java_codebase"); + } + + public void setJavaCodeBase(String codeBase) + { + setHTMLAttribute("java_codebase", codeBase); + } + + public String getCodeType() + { + return getHTMLAttribute("codetype"); + } + + public void setCodeType(String codeType) + { + setHTMLAttribute("codetype", codeType); + } + + public String getData() + { + return getHTMLAttribute("data"); + } + + public void setData(String data) + { + setHTMLAttribute("data", data); + } + + public boolean getDeclare() + { + return getBooleanHTMLAttribute("declare"); + } + + public void setDeclare(boolean declare) + { + setBooleanHTMLAttribute("declare", declare); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getStandby() + { + return getHTMLAttribute("standby"); + } + + public void setStandby(String standby) + { + setHTMLAttribute("standby", standby); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getJavaType() + { + return getHTMLAttribute("java_type"); + } + + public void setJavaType(String type) + { + setHTMLAttribute("java_type", type); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + + public void setMayscript(String may) + { + setHTMLAttribute("mayscript", may); + } + + public String getMayscript() + { + return getHTMLAttribute("mayscript"); + } + + public void setScriptable(String scr) + { + setHTMLAttribute("scriptable", scr); + } + + public String getScriptable() + { + return getHTMLAttribute("scriptable"); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java new file mode 100644 index 000000000..acb948484 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java @@ -0,0 +1,78 @@ +/* DomHTMLOptGroupElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLOptGroupElement; + +/** + * An HTML 'OPTGROUP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOptGroupElement + extends DomHTMLElement + implements HTMLOptGroupElement +{ + + protected DomHTMLOptGroupElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getLabel() + { + return getHTMLAttribute("label"); + } + + public void setLabel(String label) + { + setHTMLAttribute("label", label); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java new file mode 100644 index 000000000..f775c138a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java @@ -0,0 +1,130 @@ +/* DomHTMLOptionElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLOptionElement; + +/** + * An HTML 'OPTION' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOptionElement + extends DomHTMLElement + implements HTMLOptionElement +{ + + protected Boolean selected; + + protected DomHTMLOptionElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public boolean getDefaultSelected() + { + return getBooleanHTMLAttribute("selected"); + } + + public void setDefaultSelected(boolean defaultSelected) + { + setBooleanHTMLAttribute("selected", defaultSelected); + } + + public String getText() + { + return getTextContent(); + } + + public int getIndex() + { + return super.getIndex(); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getLabel() + { + return getHTMLAttribute("label"); + } + + public void setLabel(String label) + { + setHTMLAttribute("label", label); + } + + public boolean getSelected() + { + if (selected == null) + { + selected = Boolean.valueOf(getDefaultSelected()); + } + return selected.booleanValue(); + } + + public void setSelected(boolean selected) + { + this.selected = Boolean.valueOf(selected); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java new file mode 100644 index 000000000..4c867fdc1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java @@ -0,0 +1,68 @@ +/* DomHTMLParagraphElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLParagraphElement; + +/** + * An HTML 'P' element node. + * + * @author Chris Burdess + */ +public class DomHTMLParagraphElement + extends DomHTMLElement + implements HTMLParagraphElement +{ + + protected DomHTMLParagraphElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java new file mode 100644 index 000000000..cdd74ad4a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java @@ -0,0 +1,98 @@ +/* DomHTMLParamElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLParamElement; + +/** + * An HTML 'PARAM' element node. + * + * @author Chris Burdess + */ +public class DomHTMLParamElement + extends DomHTMLElement + implements HTMLParamElement +{ + + protected DomHTMLParamElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + + public String getValueType() + { + return getHTMLAttribute("valuetype"); + } + + public void setValueType(String valueType) + { + setHTMLAttribute("valuetype", valueType); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java new file mode 100644 index 000000000..88656d2d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java @@ -0,0 +1,264 @@ +/* DomHTMLParser.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.xml.dom.html2; + +import java.io.IOException; +import java.io.Reader; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.TagElement; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLDocument; + +/** + * This parser reads HTML from the given stream and stores into + * {@link HTMLDocument}. The HTML tag becomes the {@link Node}. + * The tag attributes become the node attributes. The text inside + * HTML tag is inserted as one or several text nodes. The nested + * HTML tags are inserted as child nodes. + * + * If the strict tree structure, closing the tag means closing all + * nested tags. To work around this, this parser closes the nested + * tags and immediately reopens them after the closed tag. + * In this way, <b><i>c</b>d + * is parsed as <b><i>c</i></b><i>d . + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class DomHTMLParser + extends gnu.javax.swing.text.html.parser.support.Parser +{ + /** + * The target where HTML document will be inserted. + */ + protected DomHTMLDocument document; + + /** + * The subsequently created new nodes will be inserted as the + * childs of this cursor. + */ + protected Node cursor; + + /** + * Create parser using the given DTD. + * + * @param dtd the DTD (for example, + * {@link gnu.javax.swing.text.html.parser.HTML_401F}). + */ + public DomHTMLParser(DTD dtd) + { + super(dtd); + } + + /** + * Parse SGML insertion ( <! ... > ). + * Currently just treats it as comment. + */ + public boolean parseMarkupDeclarations(StringBuffer strBuff) + throws java.io.IOException + { + Node c = document.createComment(strBuff.toString()); + cursor.appendChild(c); + return false; + } + + /** + * Read the document, present in the given stream, and + * return the corresponding {@link HTMLDocument}. + * + * @param input a stream to read from. + * @return a document, reflecting the structure of the provided HTML + * text. + * + * @throws IOException if the reader throws one. + */ + public HTMLDocument parseDocument(Reader input) + throws IOException + { + try + { + document = new DomHTMLDocument(); + document.setCheckWellformedness(false); + document.setCheckingCharacters(false); + + cursor = document; + + parse(input); + + DomHTMLDocument h = document; + document = null; + return h; + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IOException("Exception: " + ex.getMessage()); + } + } + + /** + * Create a new node. + * @param name the name of node, case insensitive. + * @return the created node. + */ + protected Node createNode(String name) + { + Node new_node = document.createElement(name.toLowerCase()); + AttributeSet hatts = getAttributes(); + NamedNodeMap natts = new_node.getAttributes(); + + Enumeration enumeration = hatts.getAttributeNames(); + Object key; + Node attribute; + + while (hatts != null) + { + while (enumeration.hasMoreElements()) + { + key = enumeration.nextElement(); + attribute = document.createAttribute(key.toString()); + attribute.setNodeValue(hatts.getAttribute(key).toString()); + natts.setNamedItem(attribute); + } + + // The default values are stored in a parent node. + hatts = hatts.getResolveParent(); + } + + return new_node; + } + + /** + * Handle comment by inserting the comment node. + * @param text the comment text. + */ + protected void handleComment(char[] text) + { + Node c = document.createComment(new String(text)); + cursor.appendChild(c); + } + + /** + * Handle the tag with no content. + * @param tag the tag to handle. + */ + protected void handleEmptyTag(TagElement tag) + { + String name = tag.getHTMLTag().toString(); + + if (name.equalsIgnoreCase("#pcdata")) + return; + + Node c = createNode(name); + cursor.appendChild(c); + } + + /** + * Close the given tag. Close and reopen all nested tags. + * @param tag the tag to close. + */ + protected void handleEndTag(TagElement tag) + { + String name = tag.getHTMLTag().toString(); + String nname = cursor.getNodeName(); + + // Closing the current tag. + if (nname != null && nname.equalsIgnoreCase(name)) + { + cursor = cursor.getParentNode(); + } + else + { + Node nCursor = cursor.getParentNode(); + + // Remember the opened nodes. + LinkedList open = new LinkedList(); + Node close = cursor; + while (close != null && !close.getNodeName().equalsIgnoreCase(name)) + { + if (close != document) + open.addFirst(close); + close = close.getParentNode(); + } + if (close == null) + cursor = document; + else + cursor = close.getParentNode(); + + // Insert the copies of the opened nodes. + Iterator iter = open.iterator(); + while (iter.hasNext()) + { + Node item = (Node) iter.next(); + cursor.appendChild(item); + cursor = item; + } + } + } + + /** + * Handle the start tag by inserting the HTML element. + * @param tag the tag to handle. + */ + protected void handleStartTag(TagElement tag) + { + HTML.Tag h = tag.getHTMLTag(); + Node c = createNode(h.toString()); + cursor.appendChild(c); + cursor = c; + } + + /** + * Handle text by inserting the text node. + * @param text the text to insert. + */ + protected void handleText(char[] text) + { + Node c = document.createTextNode(text, 0, text.length); + cursor.appendChild(c); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java new file mode 100644 index 000000000..9a51aaeeb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java @@ -0,0 +1,68 @@ +/* DomHTMLPreElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLPreElement; + +/** + * An HTML 'PRE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLPreElement + extends DomHTMLElement + implements HTMLPreElement +{ + + protected DomHTMLPreElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getWidth() + { + return getIntHTMLAttribute("width"); + } + + public void setWidth(int width) + { + setIntHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java new file mode 100644 index 000000000..811aed58b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java @@ -0,0 +1,68 @@ +/* DomHTMLQuoteElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLQuoteElement; + +/** + * An HTML 'Q' or 'BLOCKQUOTE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLQuoteElement + extends DomHTMLElement + implements HTMLQuoteElement +{ + + protected DomHTMLQuoteElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCite() + { + return getHTMLAttribute("cite"); + } + + public void setCite(String cite) + { + setHTMLAttribute("cite", cite); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java new file mode 100644 index 000000000..1bd7b3417 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java @@ -0,0 +1,128 @@ +/* DomHTMLScriptElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLScriptElement; + +/** + * An HTML 'SCRIPT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLScriptElement + extends DomHTMLElement + implements HTMLScriptElement +{ + + protected DomHTMLScriptElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getText() + { + return getTextContent(); + } + + public void setText(String text) + { + setTextContent(text); + } + + public String getHtmlFor() + { + return getHTMLAttribute("for"); + } + + public void setHtmlFor(String htmlFor) + { + setHTMLAttribute("for", htmlFor); + } + + public String getEvent() + { + return getHTMLAttribute("event"); + } + + public void setEvent(String event) + { + setHTMLAttribute("event", event); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public boolean getDefer() + { + return getBooleanHTMLAttribute("defer"); + } + + public void setDefer(boolean defer) + { + setBooleanHTMLAttribute("defer", defer); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java new file mode 100644 index 000000000..fc1debbd6 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java @@ -0,0 +1,210 @@ +/* DomHTMLSelectElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLOptionElement; +import org.w3c.dom.html2.HTMLOptionsCollection; +import org.w3c.dom.html2.HTMLSelectElement; + +/** + * An HTML 'SELECT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLSelectElement + extends DomHTMLElement + implements HTMLSelectElement +{ + + protected DomHTMLSelectElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public int getSelectedIndex() + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + for (int i = 0; i < len; i++) + { + HTMLOptionElement option = (HTMLOptionElement) options.item(i); + if (option.getSelected()) + { + return i; + } + } + return -1; + } + + public void setSelectedIndex(int selectedIndex) + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + if (selectedIndex < 0 || selectedIndex >= len) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + for (int i = 0; i < len; i++) + { + HTMLOptionElement option = (HTMLOptionElement) options.item(i); + option.setSelected(i == selectedIndex); + } + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + + public int getLength() + { + return getIntHTMLAttribute("length"); + } + + public void setLength(int length) + { + setIntHTMLAttribute("length", length); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public HTMLOptionsCollection getOptions() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("option"); + ret.evaluate(); + return ret; + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public boolean getMultiple() + { + return getBooleanHTMLAttribute("multiple"); + } + + public void setMultiple(boolean multiple) + { + setBooleanHTMLAttribute("multiple", multiple); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public void add(HTMLElement element, HTMLElement before) + { + insertBefore(before, element); + } + + public void remove(int index) + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + if (index < 0 || index >= len) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + HTMLOptionElement option = (HTMLOptionElement) options.item(index); + option.getParentNode().removeChild(option); + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java new file mode 100644 index 000000000..78cef3b18 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java @@ -0,0 +1,88 @@ +/* DomHTMLStyleElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLStyleElement; + +/** + * An HTML 'STYLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLStyleElement + extends DomHTMLElement + implements HTMLStyleElement +{ + + protected DomHTMLStyleElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getMedia() + { + return getHTMLAttribute("media"); + } + + public void setMedia(String media) + { + setHTMLAttribute("media", media); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java new file mode 100644 index 000000000..2133b1412 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java @@ -0,0 +1,69 @@ +/* DomHTMLTableCaptionElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableCaptionElement; + +/** + * An HTML 'CAPTION' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableCaptionElement + extends DomHTMLElement + implements HTMLTableCaptionElement +{ + + protected DomHTMLTableCaptionElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java new file mode 100644 index 000000000..350f0bf42 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java @@ -0,0 +1,204 @@ +/* DomHTMLTableCellElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableCellElement; + +/** + * An HTML 'TH' or 'TD' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableCellElement + extends DomHTMLElement + implements HTMLTableCellElement +{ + + protected DomHTMLTableCellElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getCellIndex() + { + return getIndex(); + } + + public String getAbbr() + { + return getHTMLAttribute("abbr"); + } + + public void setAbbr(String abbr) + { + setHTMLAttribute("abbr", abbr); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAxis() + { + return getHTMLAttribute("axis"); + } + + public void setAxis(String axis) + { + setHTMLAttribute("axis", axis); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public int getColSpan() + { + return getIntHTMLAttribute("colspan"); + } + + public void setColSpan(int colSpan) + { + setIntHTMLAttribute("colspan", colSpan); + } + + public String getHeaders() + { + return getHTMLAttribute("headers"); + } + + public void setHeaders(String headers) + { + setHTMLAttribute("headers", headers); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public boolean getNoWrap() + { + return getBooleanHTMLAttribute("nowrap"); + } + + public void setNoWrap(boolean noWrap) + { + setBooleanHTMLAttribute("nowrap", noWrap); + } + + public int getRowSpan() + { + return getIntHTMLAttribute("rowspan"); + } + + public void setRowSpan(int rowSpan) + { + setIntHTMLAttribute("rowspan", rowSpan); + } + + public String getScope() + { + return getHTMLAttribute("scope"); + } + + public void setScope(String scope) + { + setHTMLAttribute("scope", scope); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java new file mode 100644 index 000000000..c7cef31eb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java @@ -0,0 +1,119 @@ +/* DomHTMLTableColElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableColElement; + +/** + * An HTML 'COL' or 'COLGROUP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableColElement + extends DomHTMLElement + implements HTMLTableColElement +{ + + protected DomHTMLTableColElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public int getSpan() + { + return getIntHTMLAttribute("span"); + } + + public void setSpan(int span) + { + setIntHTMLAttribute("span", span); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java new file mode 100644 index 000000000..ade463ef7 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java @@ -0,0 +1,397 @@ +/* DomHTMLTableElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableCaptionElement; +import org.w3c.dom.html2.HTMLTableElement; +import org.w3c.dom.html2.HTMLTableSectionElement; + +/** + * An HTML 'TABLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableElement + extends DomHTMLElement + implements HTMLTableElement +{ + + protected DomHTMLTableElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLTableCaptionElement getCaption() + { + return (HTMLTableCaptionElement) getChildElement("caption"); + } + + public void setCaption(HTMLTableCaptionElement caption) + { + HTMLTableCaptionElement ref = getCaption(); + if (ref == null) + { + appendChild(caption); + } + else + { + replaceChild(caption, ref); + } + } + + public HTMLTableSectionElement getTHead() + { + return (HTMLTableSectionElement) getChildElement("thead"); + } + + public void setTHead(HTMLTableSectionElement tHead) + { + HTMLTableSectionElement ref = getTHead(); + if (ref == null) + { + appendChild(tHead); + } + else + { + replaceChild(tHead, ref); + } + } + + public HTMLTableSectionElement getTFoot() + { + return (HTMLTableSectionElement) getChildElement("tfoot"); + } + + public void setTFoot(HTMLTableSectionElement tFoot) + { + HTMLTableSectionElement ref = getTFoot(); + if (ref == null) + { + appendChild(tFoot); + } + else + { + replaceChild(tFoot, ref); + } + } + + public HTMLCollection getRows() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tr"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getTBodies() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tbody"); + ret.evaluate(); + return ret; + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public String getCellPadding() + { + return getHTMLAttribute("cellpadding"); + } + + public void setCellPadding(String cellPadding) + { + setHTMLAttribute("cellpadding", cellPadding); + } + + public String getCellSpacing() + { + return getHTMLAttribute("cellspacing"); + } + + public void setCellSpacing(String cellSpacing) + { + setHTMLAttribute("cellspacing", cellSpacing); + } + + public String getFrame() + { + return getHTMLAttribute("frame"); + } + + public void setFrame(String frame) + { + setHTMLAttribute("frame", frame); + } + + public String getRules() + { + return getHTMLAttribute("rules"); + } + + public void setRules(String rules) + { + setHTMLAttribute("rules", rules); + } + + public String getSummary() + { + return getHTMLAttribute("summary"); + } + + public void setSummary(String summary) + { + setHTMLAttribute("summary", summary); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public HTMLElement createTHead() + { + HTMLTableSectionElement ref = getTHead(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("thead"); + } + else + { + return ref; + } + } + + public void deleteTHead() + { + HTMLTableSectionElement ref = getTHead(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement createTFoot() + { + HTMLTableSectionElement ref = getTFoot(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("tfoot"); + } + else + { + return ref; + } + } + + public void deleteTFoot() + { + HTMLTableSectionElement ref = getTFoot(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement createCaption() + { + HTMLTableCaptionElement ref = getCaption(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("caption"); + } + else + { + return ref; + } + } + + public void deleteCaption() + { + HTMLTableCaptionElement ref = getCaption(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement insertRow(int index) + { + Node ref = getRow(index); + Node row = getOwnerDocument().createElement("tr"); + if (ref == null) + { + Node tbody = getChildElement("tbody"); + if (tbody == null) + { + tbody = getOwnerDocument().createElement("tfoot"); + appendChild(tbody); + } + tbody.appendChild(row); + } + else + { + ref.getParentNode().insertBefore(row, ref); + } + return (HTMLElement) row; + } + + public void deleteRow(int index) + { + Node ref = getRow(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + ref.getParentNode().removeChild(ref); + } + + Node getRow(final int index) + { + int i = 0; + Node thead = getChildElement("thead"); + if (thead != null) + { + for (Node ctx = thead.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + } + Node tbody = getChildElement("tbody"); + if (tbody == null) + { + tbody = this; + } + for (Node ctx = tbody.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + Node tfoot = getChildElement("tfoot"); + if (tfoot != null) + { + for (Node ctx = tfoot.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java new file mode 100644 index 000000000..9943585f4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java @@ -0,0 +1,228 @@ +/* DomHTMLTableRowElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableRowElement; + +/** + * An HTML 'TR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableRowElement + extends DomHTMLElement + implements HTMLTableRowElement +{ + + protected DomHTMLTableRowElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getRowIndex() + { + return getIndex(); + } + + public int getSectionRowIndex() + { + int index = 0; + DomHTMLElement parent = (DomHTMLElement) getParentElement("table"); + if (parent != null) + { + Node thead = parent.getChildElement("thead"); + if (thead != null) + { + for (Node ctx = thead.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + Node tbody = parent.getChildElement("tbody"); + if (tbody != null) + { + for (Node ctx = tbody.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + Node tfoot = parent.getChildElement("tfoot"); + if (tfoot != null) + { + for (Node ctx = tfoot.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + public HTMLCollection getCells() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("th"); + ret.addNodeName("td"); + ret.evaluate(); + return ret; + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public HTMLElement insertCell(int index) + { + Node ref = getCell(index); + Node cell = getOwnerDocument().createElement("td"); + if (ref == null) + { + appendChild(cell); + } + else + { + insertBefore(cell, ref); + } + return (HTMLElement) cell; + } + + public void deleteCell(int index) + { + Node ref = getCell(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + removeChild(ref); + } + + Node getCell(final int index) + { + int i = 0; + for (Node ctx = getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String name = ctx.getLocalName(); + if (name == null) + { + name = ctx.getNodeName(); + } + if (!"td".equalsIgnoreCase(name) && + !"th".equalsIgnoreCase(name)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java new file mode 100644 index 000000000..389eb591b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java @@ -0,0 +1,162 @@ +/* DomHTMLTableSectionElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableSectionElement; + +/** + * An HTML 'THEAD', 'TFOOT', or 'TBODY' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableSectionElement + extends DomHTMLElement + implements HTMLTableSectionElement +{ + + protected DomHTMLTableSectionElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public HTMLCollection getRows() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tr"); + ret.evaluate(); + return ret; + } + + public HTMLElement insertRow(int index) + { + Node ref = getRow(index); + Node row = getOwnerDocument().createElement("tr"); + if (ref == null) + { + appendChild(row); + } + else + { + insertBefore(row, ref); + } + return (HTMLElement) row; + } + + public void deleteRow(int index) + { + Node ref = getRow(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + removeChild(ref); + } + + Node getRow(final int index) + { + int i = 0; + for (Node ctx = getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String name = ctx.getLocalName(); + if (name == null) + { + name = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(name)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java new file mode 100644 index 000000000..9acfab134 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java @@ -0,0 +1,181 @@ +/* DomHTMLTextAreaElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLTextAreaElement; + +/** + * An HTML 'TEXTAREA' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTextAreaElement + extends DomHTMLElement + implements HTMLTextAreaElement +{ + + protected String value; + + protected DomHTMLTextAreaElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getDefaultValue() + { + return getHTMLAttribute("value"); + } + + public void setDefaultValue(String defaultValue) + { + setHTMLAttribute("value", defaultValue); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public int getCols() + { + return getIntHTMLAttribute("cols"); + } + + public void setCols(int cols) + { + setIntHTMLAttribute("cols", cols); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getReadOnly() + { + return getBooleanHTMLAttribute("readOnly"); + } + + public void setReadOnly(boolean readOnly) + { + setBooleanHTMLAttribute("readonly", readOnly); + } + + public int getRows() + { + return getIntHTMLAttribute("rows"); + } + + public void setRows(int rows) + { + setIntHTMLAttribute("rows", rows); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return "textarea"; + } + + public String getValue() + { + if (value == null) + { + value = getDefaultValue(); + } + return value; + } + + public void setValue(String value) + { + this.value = value; + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + + public void select() + { + dispatchUIEvent("select"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java new file mode 100644 index 000000000..4f581061b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java @@ -0,0 +1,68 @@ +/* DomHTMLTitleElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTitleElement; + +/** + * An HTML 'TITLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTitleElement + extends DomHTMLElement + implements HTMLTitleElement +{ + + protected DomHTMLTitleElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getText() + { + return getTextContent(); + } + + public void setText(String text) + { + setTextContent(text); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java new file mode 100644 index 000000000..39cdce7d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java @@ -0,0 +1,78 @@ +/* DomHTMLUListElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.html2; + +import org.w3c.dom.html2.HTMLUListElement; + +/** + * An HTML 'UL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLUListElement + extends DomHTMLElement + implements HTMLUListElement +{ + + protected DomHTMLUListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSException.java b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java new file mode 100644 index 000000000..31efc845f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java @@ -0,0 +1,57 @@ +/* DomLSException.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import org.w3c.dom.ls.LSException; + +/** + * A DOM LS exception incorporating a cause. + * + * @author Chris Burdess + */ +public class DomLSException + extends LSException +{ + + public DomLSException(short type, Exception cause) + { + super(type, (cause == null) ? null : cause.getMessage()); + initCause(cause); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java new file mode 100644 index 000000000..39b17694f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java @@ -0,0 +1,159 @@ +/* DomLSInput.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import gnu.java.lang.CPStringBuilder; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import org.w3c.dom.ls.LSInput; + +/** + * Specification of XML input to parse. + * + * @author Chris Burdess + */ +public class DomLSInput + implements LSInput +{ + + private InputStream in; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + public Reader getCharacterStream() + { + return new InputStreamReader(in); + } + + public void setCharacterStream(Reader characterStream) + { + in = new ReaderInputStream(characterStream); + } + + public InputStream getByteStream() + { + return in; + } + + public void setByteStream(InputStream byteStream) + { + in = byteStream; + } + + public String getStringData() + { + CPStringBuilder acc = new CPStringBuilder(); + Reader reader = getCharacterStream(); + try + { + char[] buf = new char[4096]; + for (int len = reader.read(buf); len != -1; len = reader.read(buf)) + { + acc.append(buf, 0, len); + } + } + catch (IOException e) + { + return null; // ? + } + return acc.toString(); + } + + public void setStringData(String stringData) + { + in = new ReaderInputStream(new StringReader(stringData)); + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public String getPublicId() + { + return publicId; + } + + public void setPublicId(String publicId) + { + this.publicId = publicId; + } + + public String getBaseURI() + { + return baseURI; + } + + public void setBaseURI(String baseURI) + { + this.baseURI = baseURI; + } + + public String getEncoding() + { + return encoding; + } + + public void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public boolean getCertifiedText() + { + return certifiedText; + } + + public void setCertifiedText(boolean certifiedText) + { + this.certifiedText = certifiedText; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java new file mode 100644 index 000000000..e8bec2ec1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java @@ -0,0 +1,98 @@ +/* DomLSOutput.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import org.w3c.dom.ls.LSOutput; + +/** + * Specification of XML output to produce. + * + * @author Chris Burdess + */ +public class DomLSOutput + implements LSOutput +{ + + private OutputStream out; + private String systemId; + private String encoding; + + public Writer getCharacterStream() + { + return new OutputStreamWriter(out); + } + + public void setCharacterStream(Writer characterStream) + { + out = new WriterOutputStream(characterStream); + } + + public OutputStream getByteStream() + { + return out; + } + + public void setByteStream(OutputStream out) + { + this.out = out; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public String getEncoding() + { + return encoding; + } + + public void setEncoding(String encoding) + { + this.encoding = encoding; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java new file mode 100644 index 000000000..99db79d64 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java @@ -0,0 +1,567 @@ +/* DomLSParser.java -- + Copyright (C) 1999,2000,2001,2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.w3c.dom.Document; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Node; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSParserFilter; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDOMException; + +/** + * Parser implementation for GNU DOM. + * + * @author Chris Burdess + */ +public class DomLSParser + implements LSParser, DOMConfiguration, DOMStringList, ErrorHandler +{ + + private static final List SUPPORTED_PARAMETERS + = Arrays.asList(new String[] { "cdata-sections", + "comments", + "element-content-whitespace", + "namespaces", + "expand-entity-references", + "coalescing", + "validating", + "xinclude-aware", + "entity-resolver", + "error-handler" }); + + private LSParserFilter filter; + private final boolean async; + private String schemaType; + private SAXEventSink eventSink; + private SAXParserFactory factory; + private XMLReader reader; + + private boolean namespaceAware = true; + private boolean ignoreWhitespace; + private boolean expandEntityReferences; + private boolean ignoreComments; + private boolean coalescing; + private boolean validating; + private boolean xIncludeAware; + private EntityResolver entityResolver; + private ErrorHandler errorHandler; + + public DomLSParser(short mode, String schemaType) + throws DOMException + { + switch (mode) + { + case DOMImplementationLS.MODE_ASYNCHRONOUS: + async = true; + break; + case DOMImplementationLS.MODE_SYNCHRONOUS: + async = false; + break; + default: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + // TODO schemaType + this.schemaType = schemaType; + factory = SAXParserFactory.newInstance(); + } + + // -- LSParser -- + + public DOMConfiguration getDomConfig() + { + return this; + } + + public LSParserFilter getFilter() + { + return filter; + } + + public void setFilter(LSParserFilter filter) + { + this.filter = filter; + } + + public boolean getAsync() + { + return async; + } + + public boolean getBusy() + { + return eventSink != null; + } + + public Document parse(LSInput input) + throws DOMException, LSException + { + if (async) + { + return doParse(input); + } + else + { + synchronized (this) + { + return doParse(input); + } + } + } + + public Document parseURI(String uri) + throws DOMException, LSException + { + LSInput input = new DomLSInput(); + input.setSystemId(uri); + return parse(input); + } + + public Node parseWithContext(LSInput input, Node context, short action) + throws DOMException, LSException + { + Document doc = (context.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) context : context.getOwnerDocument(); + input.setBaseURI(doc.getDocumentURI()); + // TODO use namespaces defined on context node + Document ret = parse(input); + Node root = ret.getDocumentElement(); + root = doc.adoptNode(root); + switch (action) + { + case ACTION_APPEND_AS_CHILDREN: + context.appendChild(root); + break; + case ACTION_REPLACE_CHILDREN: + Node c1 = context.getFirstChild(); + while (c1 != null) + { + Node next = c1.getNextSibling(); + context.removeChild(c1); + c1 = next; + } + context.appendChild(root); + break; + case ACTION_INSERT_BEFORE: + Node p1 = context.getParentNode(); + p1.insertBefore(root, context); + break; + case ACTION_INSERT_AFTER: + Node p2 = context.getParentNode(); + Node r1 = context.getNextSibling(); + if (r1 == null) + { + p2.appendChild(root); + } + else + { + p2.insertBefore(root, r1); + } + break; + case ACTION_REPLACE: + Node p3 = context.getParentNode(); + Node r2 = context.getNextSibling(); + p3.removeChild(context); + if (r2 == null) + { + p3.appendChild(root); + } + else + { + p3.insertBefore(root, r2); + } + break; + } + return root; + } + + public void abort() + { + if (eventSink != null) + { + eventSink.interrupt(); + } + } + + private Document doParse(LSInput input) + throws DOMException, LSException + { + // create event sink + if (eventSink != null) + { + throw new LSException(LSException.PARSE_ERR, "parse in progress"); + } + InputSource source = getInputSource(input); + eventSink = (filter == null) ? new SAXEventSink() : + new FilteredSAXEventSink(filter); + // configure sink + eventSink.setNamespaceAware(namespaceAware); + eventSink.ignoreWhitespace = ignoreWhitespace; + eventSink.expandEntityReferences = expandEntityReferences; + eventSink.ignoreComments = ignoreComments; + eventSink.coalescing = coalescing; + // get and configure reader + XMLReader reader = getXMLReader(); + eventSink.reader = reader; + try + { + reader.setContentHandler(eventSink); + reader.setDTDHandler(eventSink); + reader.setProperty("http://xml.org/sax/properties/lexical-handler", + eventSink); + reader.setProperty("http://xml.org/sax/properties/declaration-handler", + eventSink); + reader.setFeature("http://xml.org/sax/features/namespaces", + namespaceAware); + reader.setFeature("http://xml.org/sax/features/namespace-prefixes", + true); + reader.setFeature("http://xml.org/sax/features/validation", + validating); + try + { + reader.setFeature("http://gnu.org/sax/features/coalescing", + coalescing); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + try + { + reader.setFeature("http://xml.org/sax/features/use-attributes2", + true); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + try + { + reader.setFeature("http://xml.org/sax/features/external-general-entities", + true); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + reader.setEntityResolver(entityResolver); + reader.setErrorHandler(errorHandler); + // parse + reader.parse(source); + } + catch (DOMException e) + { + reader = null; + eventSink = null; + throw e; + } + catch (SAXException e) + { + reader = null; + eventSink = null; + throw new DomLSException(LSException.PARSE_ERR, e); + } + catch (IOException e) + { + reader = null; + eventSink = null; + throw new DomLSException(LSException.PARSE_ERR, e); + } + // return document + Document ret = eventSink.doc; + String systemId = input.getSystemId(); + if (systemId != null && ret instanceof DomDocument) + { + ((DomDocument) ret).setDocumentURI(systemId); + } + eventSink = null; + return ret; + } + + private XMLReader getXMLReader() + throws LSException + { + if (reader == null) + { + factory.setNamespaceAware(namespaceAware); + factory.setValidating(validating); + factory.setXIncludeAware(xIncludeAware); + try + { + SAXParser parser = factory.newSAXParser(); + reader = parser.getXMLReader(); + } + catch (ParserConfigurationException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + catch (SAXException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + } + return reader; + } + + private InputSource getInputSource(LSInput input) + throws LSException + { + InputSource source = null; + String systemId = input.getSystemId(); + InputStream in = input.getByteStream(); + if (in != null) + { + source = new InputSource(in); + source.setSystemId(systemId); + } + if (source == null) + { + URL url = null; + String base = input.getBaseURI(); + try + { + try + { + URL baseURL = (base == null) ? null : new URL(base); + url = (baseURL == null) ? new URL(systemId) : + new URL(baseURL, systemId); + } + catch (MalformedURLException e) + { + File baseFile = (base == null) ? null : new File(base); + url = (baseFile == null) ? new File(systemId).toURL() : + new File(baseFile, systemId).toURL(); + } + in = url.openStream(); + systemId = url.toString(); + source = new InputSource(in); + source.setSystemId(systemId); + } + catch (IOException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + } + return source; + } + + // -- DOMConfiguration -- + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + coalescing = !((Boolean) value).booleanValue(); + } + else if ("comments".equals(name)) + { + ignoreComments = !((Boolean) value).booleanValue(); + } + else if ("element-content-whitespace".equals(name)) + { + ignoreWhitespace = !((Boolean) value).booleanValue(); + } + else if ("namespaces".equals(name)) + { + namespaceAware = ((Boolean) value).booleanValue(); + } + else if ("expand-entity-references".equals(name)) + { + expandEntityReferences = ((Boolean) value).booleanValue(); + } + else if ("coalescing".equals(name)) + { + coalescing = ((Boolean) value).booleanValue(); + } + else if ("validating".equals(name)) + { + validating = ((Boolean) value).booleanValue(); + } + else if ("xinclude-aware".equals(name)) + { + xIncludeAware = ((Boolean) value).booleanValue(); + } + else if ("entity-resolver".equals(name)) + { + entityResolver = (EntityResolver) value; + } + else if ("error-handler".equals(name)) + { + errorHandler = (ErrorHandler) value; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + // invalidate reader, a new one will be created + reader = null; + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + return coalescing ? Boolean.FALSE : Boolean.TRUE; + } + else if ("comments".equals(name)) + { + return ignoreComments ? Boolean.FALSE : Boolean.TRUE; + } + else if ("element-content-whitespace".equals(name)) + { + return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE; + } + else if ("namespaces".equals(name)) + { + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + } + else if ("expand-entity-references".equals(name)) + { + return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE; + } + else if ("coalescing".equals(name)) + { + return coalescing ? Boolean.TRUE : Boolean.FALSE; + } + else if ("validating".equals(name)) + { + return validating ? Boolean.TRUE : Boolean.FALSE; + } + else if ("xinclude-aware".equals(name)) + { + return xIncludeAware ? Boolean.TRUE : Boolean.FALSE; + } + else if ("entity-resolver".equals(name)) + { + return entityResolver; + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean canSetParameter(String name, Object value) + { + return contains(name); + } + + public DOMStringList getParameterNames() + { + return this; + } + + // -- DOMStringList -- + + public String item(int i) + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + return SUPPORTED_PARAMETERS.contains(str); + } + + // -- ErrorHandler -- + + public void warning(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.warning(e); + } + } + + public void error(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.error(e); + } + } + + public void fatalError(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.fatalError(e); + } + abort(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java new file mode 100644 index 000000000..c282b0b9f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java @@ -0,0 +1,353 @@ +/* DomLSSerializer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.List; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; +import org.w3c.dom.ls.LSSerializerFilter; +import org.w3c.dom.traversal.NodeFilter; +import gnu.xml.dom.DomDOMException; +import gnu.xml.transform.StreamSerializer; + +/** + * Serialize a DOM node to a stream. + * + * @author Chris Burdess + */ +public class DomLSSerializer + extends StreamSerializer + implements LSSerializer, DOMConfiguration, DOMStringList +{ + + private static final List SUPPORTED_PARAMETERS = + Arrays.asList(new String[] {"discard-default-content", + "xml-declaration"}); + + private LSSerializerFilter filter; + private StreamSerializer serializer; + + public DomLSSerializer() + { + super(); + discardDefaultContent = true; + } + + // -- LSSerializer -- + + public DOMConfiguration getDomConfig() + { + return this; + } + + public String getNewLine() + { + return eol; + } + + public void setNewLine(String newLine) + { + if (newLine == null) + { + newLine = System.getProperty("line.separator"); + } + eol = newLine; + } + + public LSSerializerFilter getFilter() + { + return filter; + } + + public void setFilter(LSSerializerFilter filter) + { + this.filter = filter; + } + + public boolean write(Node node, LSOutput output) + throws LSException + { + OutputStream out = output.getByteStream(); + try + { + if (out == null) + { + String systemId = output.getSystemId(); + try + { + URL url = new URL(systemId); + URLConnection connection = url.openConnection(); + connection.setDoOutput(true); + if (connection instanceof HttpURLConnection) + { + ((HttpURLConnection) connection).setRequestMethod("PUT"); + } + out = connection.getOutputStream(); + } + catch (MalformedURLException e) + { + File file = new File(systemId); + out = new FileOutputStream(file); + } + } + serialize(node, out); + out.flush(); + return true; + } + catch (IOException e) + { + throw new DomLSException(LSException.SERIALIZE_ERR, e); + } + } + + public boolean writeToURI(Node node, String uri) + throws LSException + { + LSOutput output = new DomLSOutput(); + output.setSystemId(uri); + return write(node, output); + } + + public String writeToString(Node node) + throws DOMException, LSException + { + Writer writer = new StringWriter(); + LSOutput output = new DomLSOutput(); + output.setCharacterStream(writer); + write(node, output); + return writer.toString(); + } + + public void serialize(Node node, OutputStream out) + throws IOException + { + if (filter == null) + { + super.serialize(node, out); + } + else + { + int wts = filter.getWhatToShow(); + if (wts != NodeFilter.SHOW_ALL) + { + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + if ((wts & NodeFilter.SHOW_ATTRIBUTE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.TEXT_NODE: + if ((wts & NodeFilter.SHOW_TEXT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ELEMENT_NODE: + if ((wts & NodeFilter.SHOW_ELEMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.CDATA_SECTION_NODE: + if ((wts & NodeFilter.SHOW_CDATA_SECTION) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.COMMENT_NODE: + if ((wts & NodeFilter.SHOW_COMMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_TYPE_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT_TYPE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + if ((wts & NodeFilter.SHOW_PROCESSING_INSTRUCTION) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_FRAGMENT_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT_FRAGMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ENTITY_NODE: + if ((wts & NodeFilter.SHOW_ENTITY) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ENTITY_REFERENCE_NODE: + if ((wts & NodeFilter.SHOW_ENTITY_REFERENCE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.NOTATION_NODE: + if ((wts & NodeFilter.SHOW_NOTATION) == 0) + { + super.serialize(node, out); + return; + } + break; + } + } + switch (filter.acceptNode(node)) + { + case NodeFilter.FILTER_ACCEPT: + super.serialize(node, out); + break; + case NodeFilter.FILTER_REJECT: + break; + case NodeFilter.FILTER_SKIP: + Node first = node.getFirstChild(); + if (first != null) + { + serialize(first, out); + } + break; + } + } + } + + // -- DOMConfiguration -- + + public void setParameter(String name, Object value) + throws DOMException + { + if ("discard-default-content".equals(name)) + { + discardDefaultContent = "true".equals(value.toString()); + } + else if ("xml-declaration".equals(name)) + { + xmlDeclaration = "false".equals(value.toString()); + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public Object getParameter(String name) + throws DOMException + { + if ("discard-default-content".equals(name)) + { + return discardDefaultContent ? "true" : "false"; + } + else if ("xml-declaration".equals(name)) + { + return xmlDeclaration ? "true" : "false"; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean canSetParameter(String name, Object value) + { + return contains(name); + } + + public DOMStringList getParameterNames() + { + return this; + } + + // -- DOMStringList -- + + public String item(int i) + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + return SUPPORTED_PARAMETERS.contains(str); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java new file mode 100644 index 000000000..65c1d37a4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java @@ -0,0 +1,353 @@ +/* FilteredSAXEventSink.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.util.LinkedList; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.ls.LSParserFilter; +import org.w3c.dom.traversal.NodeFilter; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * A SAX event sink that calls out to a parser filter in order to decide + * whether to insert nodes into the tree. + * + * @author Chris Burdess + */ +class FilteredSAXEventSink + extends SAXEventSink +{ + + final LSParserFilter filter; + final int whatToShow; + + /** + * Stack of elements to insert. + */ + LinkedList nodes; + + /** + * Corresponding stack of filter decisions about the nodes. + */ + LinkedList decisions; + + /** + * True when rejecting child nodes. + */ + boolean rejecting; + + FilteredSAXEventSink(LSParserFilter filter) + { + this.filter = filter; + whatToShow = filter.getWhatToShow(); + } + + public void startDocument() + throws SAXException + { + if (interrupted) + { + return; + } + nodes = new LinkedList(); + decisions = new LinkedList(); + + super.startDocument(); + } + + public void endDocument() + throws SAXException + { + if (interrupted) + { + return; + } + super.endDocument(); + + switch (getDecision(ctx, false)) + { + case LSParserFilter.FILTER_REJECT: + ctx = null; + doc = null; + break; + } + + nodes = null; + decisions = null; + } + + public void startElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + Element element = createElement(uri, localName, qName, atts); + ctx = element; + + short decision = getDecision(element, true); + nodes.addLast(element); + decisions.addLast(new Short(decision)); + + switch (decision) + { + case LSParserFilter.FILTER_REJECT: + rejecting = true; + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + protected Attr createAttr(Attributes atts, int index) + { + Attr attr = super.createAttr(atts, index); + short decision = getDecision(attr, false); + switch (decision) + { + case LSParserFilter.FILTER_REJECT: + return null; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + return null; + } + return attr; + } + + public void endElement(String uri, String localName, String qName) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + super.endElement(uri, localName, qName); + + Element element = (Element) nodes.removeLast(); + Node parent = nodes.isEmpty() ? doc : (Node) nodes.getLast(); + ctx = parent; + short decision = ((Short) decisions.removeLast()).shortValue(); + switch (decision) + { + case LSParserFilter.FILTER_SKIP: + // Add all children of element to parent + for (Node child = element.getFirstChild(); child != null; + child = child.getNextSibling()) + { + parent.insertBefore(child, element); + } + return; + case LSParserFilter.FILTER_REJECT: + rejecting = false; + break; + } + decision = getDecision(element, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + parent.appendChild(element); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void characters(char[] c, int off, int len) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + Text text = createText(c, off, len); + short decision = getDecision(text, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(text); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void processingInstruction(String target, String data) + throws SAXException + { + if (rejecting || interrupted || inDTD) + { + return; + } + Node pi = createProcessingInstruction(target, data); + short decision = getDecision(pi, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(pi); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void startDTD(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = createDocumentType(name, publicId, systemId); + ctx = doctype; + inDTD = true; + nodes.addLast(doctype); + decisions.addLast(new Short(LSParserFilter.FILTER_ACCEPT)); + } + + public void endDTD() + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = (Node) nodes.removeLast(); + decisions.removeLast(); + inDTD = false; + ctx = doc; + short decision = getDecision(doctype, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(doctype); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void comment(char[] c, int off, int len) + throws SAXException + { + if (rejecting || interrupted || inDTD) + { + return; + } + Node comment = createComment(c, off, len); + short decision = getDecision(comment, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(comment); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + // TODO declarations + + short getDecision(Node node, boolean start) + { + boolean show = (whatToShow == NodeFilter.SHOW_ALL); + if (!show) + { + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + show = ((whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0); + break; + case Node.TEXT_NODE: + show = ((whatToShow & NodeFilter.SHOW_TEXT) != 0); + break; + case Node.CDATA_SECTION_NODE: + show = ((whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0); + break; + case Node.ELEMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_ELEMENT) != 0); + break; + case Node.COMMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_COMMENT) != 0); + break; + case Node.DOCUMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT) != 0); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + show = ((whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0); + break; + case Node.DOCUMENT_FRAGMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0); + break; + case Node.DOCUMENT_TYPE_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0); + break; + case Node.ENTITY_REFERENCE_NODE: + show = ((whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0); + break; + case Node.ENTITY_NODE: + show = ((whatToShow & NodeFilter.SHOW_ENTITY) != 0); + break; + case Node.NOTATION_NODE: + show = ((whatToShow & NodeFilter.SHOW_NOTATION) != 0); + break; + } + } + if (!show) + { + return LSParserFilter.FILTER_ACCEPT; + } + if (start) + { + return filter.startElement((Element) node); + } + return filter.acceptNode(node); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java new file mode 100644 index 000000000..cf279ab39 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java @@ -0,0 +1,236 @@ +/* ReaderInputStream.java -- + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; + +/** + * Character stream wrapper. + * + * @author Chris Burdess + * @author Mark Wielaard + */ +public class ReaderInputStream + extends InputStream +{ + + private Reader reader; + private String encoding; + + // Holds extra spillover data if necessary + private byte extra[]; + private int pos; + + private byte extra_marked[]; + private int pos_marked; + + public ReaderInputStream(Reader reader) + { + this.reader = reader; + this.encoding = "UTF-8"; + } + + void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public int read() + throws IOException + { + if (extra != null) + { + int result = extra[pos]; + pos++; + if (pos >= extra.length) + { + extra = null; + } + return result; + } + return reader.read(); + } + + public int read(byte[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) + throws IOException + { + if (len == 0) + { + return 0; + } + + if (extra != null) + { + int available = extra.length - pos; + int l = available < len ? available : len; + System.arraycopy(extra, 0, b, off, l); + pos += l; + if (pos >= extra.length) + { + extra = null; + } + return l; + } + + char[] c = new char[len]; + int l = reader.read(c, 0, len); + if (l == -1) + { + return -1; + } + + String s = new String(c, 0, l); + byte[] d = s.getBytes(encoding); + + int available = d.length; + int more = d.length - len; + if (more > 0) + { + extra = new byte[more]; + pos = 0; + System.arraycopy(d, len, extra, 0, more); + available -= more; + } + + System.arraycopy(d, 0, b, off, available); + return available; + } + + public void close() + throws IOException + { + reader.close(); + } + + public boolean markSupported() + { + return reader.markSupported(); + } + + public void mark(int limit) + { + if (extra != null) + { + extra_marked = new byte[extra.length]; + System.arraycopy(extra, 0, extra_marked, 0, extra.length); + pos_marked = pos; + } + else + { + extra_marked = null; + } + + try + { + // Note that this might be a bit more than asked for. + // Because we might also have the extra_marked bytes. + // That is fine (and necessary for reset() to work). + reader.mark(limit); + } + catch (IOException ioe) + { + throw new RuntimeException(ioe); + } + } + + public void reset() + throws IOException + { + extra = extra_marked; + pos = pos_marked; + extra_marked = null; + + reader.reset(); + } + + public long skip(long n) + throws IOException + { + long done = 0; + if (extra != null) + { + int available = extra.length - pos; + done = available < n ? available : n; + pos += done; + if (pos >= extra.length) + { + extra = null; + } + } + + n -= done; + if (n > 0) + { + return reader.skip(n) + done; + } + else + { + return done; + } + } + + /** + * Returns conservative number of bytes available without blocking. + * Actual number of bytes that can be read without blocking might + * be (much) bigger. + */ + public int available() + throws IOException + { + if (extra != null) + { + return pos - extra.length; + } + + return reader.ready() ? 1 : 0; + } + + public String toString() + { + return getClass().getName() + "[" + reader + ", " + encoding + "]"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java new file mode 100644 index 000000000..06333dd7e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java @@ -0,0 +1,603 @@ +/* SAXEventSink.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.XMLConstants; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.ext.Locator2; +import gnu.xml.dom.DomAttr; +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDoctype; +import gnu.xml.dom.DomNode; + +/** + * A SAX content and lexical handler used to construct a DOM document. + * + * @author Chris Burdess + */ +public class SAXEventSink + implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler +{ + + private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE; + private static final HashSet PREDEFINED_ENTITIES = new HashSet(); + static + { + PREDEFINED_ENTITIES.add("amp"); + PREDEFINED_ENTITIES.add("lt"); + PREDEFINED_ENTITIES.add("gt"); + PREDEFINED_ENTITIES.add("quot"); + PREDEFINED_ENTITIES.add("apos"); + } + + private boolean namespaceAware; + boolean ignoreWhitespace; + boolean expandEntityReferences; + boolean ignoreComments; + boolean coalescing; + + XMLReader reader; // reference back to the parser to get features + + DomDocument doc; // document being constructed + Node ctx; // current context (parent node) + LinkedList entityCtx; // entity context + List pending; // namespace nodes waiting for a declaring element + Locator locator; + boolean inCDATA; + boolean inDTD; + boolean interrupted; + + void interrupt() + { + interrupted = true; + } + + public Document getDocument() + { + return doc; + } + + public void setReader(XMLReader reader) + { + this.reader = reader; + } + + // -- ContentHandler2 -- + + public void setDocumentLocator(Locator locator) + { + this.locator = locator; + } + + public void setNamespaceAware(boolean namespaceAware) + { + this.namespaceAware = namespaceAware; + } + + public void startDocument() + throws SAXException + { + if (namespaceAware) + { + pending = new LinkedList(); + } + doc = new DomDocument(); + doc.setStrictErrorChecking(false); + doc.setBuilding(true); + doc.setDefaultAttributes(false); + ctx = doc; + + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_PROPERTIES = "http://gnu.org/sax/properties/"; + + if (reader != null) + { + boolean standalone = reader.getFeature(FEATURES + "is-standalone"); + doc.setXmlStandalone(standalone); + try + { + String version = (String) reader.getProperty(PROPERTIES + + "document-xml-version"); + doc.setXmlVersion(version); + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } + try + { + String encoding = (String) reader.getProperty(GNU_PROPERTIES + + "document-xml-encoding"); + doc.setXmlEncoding(encoding); + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } + } + if (locator != null && locator instanceof Locator2) + { + String encoding = ((Locator2) locator).getEncoding(); + doc.setInputEncoding(encoding); + } + } + + public void endDocument() + throws SAXException + { + doc.setStrictErrorChecking(true); + doc.setBuilding(false); + doc.setDefaultAttributes(true); + DomDoctype doctype = (DomDoctype) doc.getDoctype(); + if (doctype != null) + { + doctype.makeReadonly(); + } + ctx = null; + locator = null; + } + + public void startPrefixMapping(String prefix, String uri) + throws SAXException + { + if (namespaceAware) + { + String nsName = (prefix != null && prefix.length() > 0) ? + XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX; + DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName); + ns.setNodeValue(uri); + if (ctx.getNodeType() == Node.ATTRIBUTE_NODE) + { + // Add to owner element + Node target = ((Attr) ctx).getOwnerElement(); + target.getAttributes().setNamedItemNS(ns); + } + else + { + // Add to pending list; namespace node will be inserted when + // element is seen + pending.add(ns); + } + } + } + + public void endPrefixMapping(String prefix) + throws SAXException + { + } + + public void startElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + if (interrupted) + { + return; + } + Element element = createElement(uri, localName, qName, atts); + // add element to context + ctx.appendChild(element); + ctx = element; + } + + protected Element createElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + // create element node + Element element = namespaceAware ? + doc.createElementNS(uri, qName) : + doc.createElement(qName); + NamedNodeMap attrs = element.getAttributes(); + if (namespaceAware && !pending.isEmpty()) + { + // add pending namespace nodes + for (Iterator i = pending.iterator(); i.hasNext(); ) + { + Node ns = (Node) i.next(); + attrs.setNamedItemNS(ns); + } + pending.clear(); + } + // add attributes + int len = atts.getLength(); + for (int i = 0; i < len; i++) + { + // create attribute + Attr attr = createAttr(atts, i); + if (attr != null) + { + // add attribute to element + if (namespaceAware) + { + attrs.setNamedItemNS(attr); + } + else + { + attrs.setNamedItem(attr); + } + } + } + return element; + } + + protected Attr createAttr(Attributes atts, int index) + { + DomAttr attr; + if (namespaceAware) + { + String a_uri = atts.getURI(index); + String a_qName = atts.getQName(index); + attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName); + } + else + { + String a_qName = atts.getQName(index); + attr = (DomAttr) doc.createAttribute(a_qName); + } + attr.setNodeValue(atts.getValue(index)); + if (atts instanceof Attributes2) + { + Attributes2 atts2 = (Attributes2) atts; + // TODO attr.setDeclared(atts2.isDeclared(index)); + attr.setSpecified(atts2.isSpecified(index)); + } + return attr; + } + + public void endElement(String uri, String localName, String qName) + throws SAXException + { + if (interrupted) + { + return; + } + if (namespaceAware) + { + pending.clear(); + } + ctx = ctx.getParentNode(); + } + + public void characters(char[] c, int off, int len) + throws SAXException + { + if (interrupted || len < 1) + { + return; + } + ctx.appendChild(createText(c, off, len)); + } + + protected Text createText(char[] c, int off, int len) + throws SAXException + { + Text text = (inCDATA && !coalescing) ? + doc.createCDATASection(new String(c, off, len)) : + doc.createTextNode(new String(c, off, len)); + return text; + } + + public void ignorableWhitespace(char[] c, int off, int len) + throws SAXException + { + if (interrupted) + { + return; + } + if (!ignoreWhitespace) + { + characters(c, off, len); + } + } + + public void processingInstruction(String target, String data) + throws SAXException + { + if (interrupted) + { + return; + } + Node pi = createProcessingInstruction(target, data); + ctx.appendChild(pi); + } + + protected Node createProcessingInstruction(String target, String data) + { + return doc.createProcessingInstruction(target, data); + } + + public void skippedEntity(String name) + throws SAXException + { + // This callback is totally pointless + } + + // -- LexicalHandler -- + + public void startDTD(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = createDocumentType(name, publicId, systemId); + doc.appendChild(doctype); + ctx = doctype; + inDTD = true; + } + + protected Node createDocumentType(String name, String publicId, + String systemId) + { + return new DomDoctype(doc, name, publicId, systemId); + } + + public void endDTD() + throws SAXException + { + if (interrupted) + { + return; + } + inDTD = false; + ctx = ctx.getParentNode(); + } + + public void startEntity(String name) + throws SAXException + { + if (interrupted) + return; + DocumentType doctype = doc.getDoctype(); + if (doctype == null) + { + throw new SAXException("SAX parser error: " + + "reference to entity in undeclared doctype"); + } + if ("[dtd]".equals(name) || name.charAt(0) == '%') + return; + if (PREDEFINED_ENTITIES.contains(name)) + return; + // Get entity + NamedNodeMap entities = doctype.getEntities(); + Entity entity = (Entity) entities.getNamedItem(name); + if (entity == null) + { + throw new SAXException("SAX parser error: " + + "reference to undeclared entity: " + name); + } + EntityReference ref = doc.createEntityReference(name); + // DomDocument populates with the entity replacement text, remove this + Node child = ref.getFirstChild(); + while (child != null) + { + Node nextChild = child.getNextSibling(); + ref.removeChild(child); + child = nextChild; + } + ctx.appendChild(ref); + ctx = ref; + } + + public void endEntity(String name) + throws SAXException + { + if (interrupted) + return; + if ("[dtd]".equals(name) || name.charAt(0) == '%') + return; + if (PREDEFINED_ENTITIES.contains(name)) + return; + // Get entity reference + EntityReference ref = (EntityReference) ctx; + if (!ref.getNodeName().equals(name)) + throw new SAXException("expecting end of "+ref.getNodeName()+" entity"); + ctx = ctx.getParentNode(); + if (ref instanceof DomNode) + ((DomNode) ref).makeReadonly(); + if (expandEntityReferences) + { + // Move entity content from reference node onto context + Node child = ref.getFirstChild(); + while (child != null) + { + Node nextChild = child.getNextSibling(); + ctx.appendChild(child); + child = nextChild; + } + ctx.removeChild(ref); + } + } + + public void startCDATA() + throws SAXException + { + inCDATA = true; + } + + public void endCDATA() + throws SAXException + { + inCDATA = false; + } + + public void comment(char[] c, int off, int len) + throws SAXException + { + if (interrupted) + { + return; + } + Node comment = createComment(c, off, len); + ctx.appendChild(comment); + } + + protected Node createComment(char[] c, int off, int len) + { + return doc.createComment(new String(c, off, len)); + } + + // -- DTDHandler -- + + public void notationDecl(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("notation decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + doctype.declareNotation(name, publicId, systemId); + } + + public void unparsedEntityDecl(String name, String publicId, String systemId, + String notationName) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("unparsed entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, publicId, systemId, + notationName); + } + + // -- DeclHandler -- + + public void elementDecl(String name, String model) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("element decl outside DTD"); + // Ignore fake element declarations generated by ValidationConsumer. + // If an element is not really declared in the DTD it will not be + // declared in the document model. + if (!(ctx instanceof DomDoctype)) + { + return; + } + DomDoctype doctype = (DomDoctype) ctx; + doctype.elementDecl(name, model); + } + + public void attributeDecl(String eName, String aName, String type, + String mode, String value) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("attribute decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + doctype.attributeDecl(eName, aName, type, mode, value); + } + + public void internalEntityDecl(String name, String value) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("internal entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, null, null, null); + if (entity != null) + { + Node text = doc.createTextNode(value); + entity.appendChild(text); + } + } + + public void externalEntityDecl(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("external entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, publicId, systemId, null); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java new file mode 100644 index 000000000..f1ae344f4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java @@ -0,0 +1,97 @@ +/* WriterOutputStream.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.dom.ls; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +/** + * Character stream wrapper. + * + * @author Chris Burdess + */ +public class WriterOutputStream + extends OutputStream +{ + + private Writer writer; + private String encoding; + + public WriterOutputStream(Writer writer) + { + this.writer = writer; + this.encoding = "UTF-8"; + } + + void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public void write(int c) + throws IOException + { + writer.write(c); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + writer.write(new String(b, off, len, encoding)); + } + + public void close() + throws IOException + { + writer.close(); + } + + public void flush() + throws IOException + { + writer.flush(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/package.html b/libjava/classpath/gnu/xml/dom/package.html new file mode 100644 index 000000000..fbc864a4d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/package.html @@ -0,0 +1,273 @@ + + + +

+This is a Free Software DOM Level 3 implementation, supporting these features: +

+It is intended to be a reasonable base both for +experimentation and supporting additional DOM modules as clean layers. +

+ +

+Note that while DOM does not specify its behavior in the +face of concurrent access, this implementation does. +Specifically: +

+

+ +

Design Goals

+ +

+A number of DOM implementations are available in Java, including +commercial ones from Sun, IBM, Oracle, and DataChannel as well as +noncommercial ones from Docuverse, OpenXML, and Silfide. Why have +another? Some of the goals of this version: +

+ + + +

+This also works with the GNU Compiler for Java (GCJ). GCJ promises +to be quite the environment for programming Java, both directly and from +C++ using the new CNI interfaces (which really use C++, unlike JNI).

+ + +

Open Issues

+ +

At this writing:

+ + +

+I ran a profiler a few times and remove some of the performance hotspots, +but it's not tuned. Reporting mutation events, in particular, is +rather costly -- it started at about a 40% penalty for appendNode calls, +I've got it down around 12%, but it'll be hard to shrink it much further. +The overall code size is relatively small, though you may want to be rid of +many of the unused DOM interface classes (HTML, CSS, and so on). +

+ + +

Features of this Package

+ +

Starting with DOM Level 2, you can really see that DOM is constructed +as a bunch of optional modules around a core of either XML or HTML +functionality. Different implementations will support different optional +modules. This implementation provides a set of features that should be +useful if you're not depending on the HTML functionality (lots of convenience +functions that mostly don't buy much except API surface area) and user +interface support. That is, browsers will want more -- but what they +need should be cleanly layered over what's already here.

+ +

Core Feature Set: "XML"

+ +

This DOM implementation supports the "XML" feature set, which basically +gets you four things over the bare core (which you're officially not supposed +to implement except in conjunction with the "XML" or "HTML" feature). In +order of decreasing utility, those four things are:

    + +
  1. ProcessingInstruction nodes. These are probably the most + valuable thing. Handy little buggers, in part because all the APIs + you need to use them are provided, and they're designed to let you + escape XML document structure rules in controlled ways.
  2. + +
  3. CDATASection nodes. These are of of limited utility since CDATA + is just text that prints funny. These are of use to some sorts of + applications, though I encourage folk to not use them.
  4. + +
  5. DocumentType nodes, and associated Notation and Entity nodes. + These appear to be useless. Briefly, these "Type" nodes expose no + typing information. They're only really usable to expose some lexical + structure that almost every application needs to ignore. (XML editors + might like to see them, but they need true typing information much more.) + I strongly encourage people not to use these.
  6. + +
  7. EntityReference nodes can show up. These are actively annoying, + since they add an extra level of hierarchy, are the cause of most of + the complexity in attribute values, and their contents are immutable. + Avoid these.
  8. + +
+ +

Optional Feature Sets: "Events", and friends

+ +

Events may be one of the more interesting new features in Level 2. +This package provides the core feature set and exposes mutation events. +No gooey events though; if you want that, write a layered implementation!

+ +

Three mutation events aren't currently generated:

+ +

In addition, certain kinds of attribute modification aren't reported. +A fix is known, but it couldn't report the previous value of the attribute. +More work could fix all of this (as well as reduce the generally high cost +of childful attributes), but that's not been done yet.

+ +

Also, note that it is a Bad Thing™ to have the listener +for a mutation event change the ancestry for the target of that event. +Or to prevent mutation events from bubbling to where they're needed. +Just don't do those, OK?

+ +

As an experimental feature (named "USER-Events"), you can provide +your own "user" events. Just name them anything starting with "USER-" +and you're set. Dispatch them through, bubbling, capturing, or what +ever takes your fancy. One important thing you can't currently do is +pass any data (like an object) with those events. Maybe later there +will be a "UserEvent" interface letting you get some substantial use +out of this mechanism even if you're not "inside" of a DOM package.

+ +

You can create and send HTML events. Ditto UIEvents. Since DOM +doesn't require a UI, it's the UI's job to send them; perhaps that's +part of your application.

+ +

This package may be built without the ability to report mutation +events, gaining a significant speedup in DOM construction time. However, +if that is done then certain other features -- notably node iterators +and getElementsByTagname -- will not be available. + + +

Optional Feature: "Traversal"

+ +

Each DOM node has all you need to walk to everything connected +to that node. Lightweight, efficient utilities are easily layered on +top of just the core APIs.

+ +

Traversal APIs are an optional part of DOM Level 2, providing +a not-so-lightweight way to walk over DOM trees, if your application +didn't already have such utilities for use with data represented via +DOM. Implementing this helped debug the (optional) event and mutation +event subsystems, so it's provided here.

+ +

At this writing, the "TreeWalker" interface isn't implemented.

+ + + +

DOM Functionality to Avoid

+ +

For what appear to be a combination of historical and "committee +logic" reasons, DOM has a number of features which I strongly advise +you to avoid using in your library and application code. These +include the following types of DOM nodes; see the documentation for the +implementation class for more information:

+ +

If you really need to use unparsed entities or notations, use SAX; +it offers better support for all DTD-related functionality. +It also exposes actual +document typing information (such as element content models).

+ +

Also, when accessing attribute values, use methods that provide their +values as single strings, rather than those which expose value substructure +(Text and EntityReference nodes). (See the DomAttr +documentation for more information.)

+ +

Note that many of these features were provided as partial support for +editor functionality (including the incomplete DTD access). Full editor +functionality requires access to potentially malformed lexical structure, +at the level of unparsed tokens and below. Access at such levels is so +complex that using it in non-editor applications sacrifices all the +benefits of XML; editor aplications need extremely specialized APIs.

+ +

(This isn't a slam against DTDs, note; only against the broken support +for them in DOM. Even despite inclusion of some dubious SGML legacy features +such as notations and unparsed entities, +and the ongoing proliferation of alternative schema and validation tools, +DTDs are still the most widely adopted tool +to constrain XML document structure. +Alternative schemes generally focus on data transfer style +applications; open document architectures comparable to +DocBook 4.0 don't yet exist in the schema world. +Feel free to use DTDs; just don't expect DOM to help you.)

+ + + + diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java new file mode 100644 index 000000000..da9c62c9d --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java @@ -0,0 +1,117 @@ +/* GnomeAttr.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + * A DOM attribute node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeAttr + extends GnomeNode + implements Attr +{ + + GnomeAttr(Object id) + { + super(id); + } + + public String getName() + { + return getNodeName(); + } + + public native boolean getSpecified(); + + public native String getValue(); + + public native void setValue(String value) + throws DOMException; + + public Node getParentNode() + { + return null; + } + + public Element getOwnerElement() + { + return (Element) super.getParentNode(); + } + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public boolean isId() + { + if (xmljIsId()) + { + return true; + } + GnomeElement element = (GnomeElement) getOwnerElement(); + return (element != null && + element.userIdAttrs != null && + element.userIdAttrs.contains(this)); + } + + private native boolean xmljIsId(); + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[name="); + buffer.append(getName()); + buffer.append(",value="); + buffer.append(getValue()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java new file mode 100644 index 000000000..3e408e653 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java @@ -0,0 +1,57 @@ +/* GnomeCDATASection.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.CDATASection; + +/** + * A DOM CDATA section node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeCDATASection + extends GnomeText + implements CDATASection +{ + + GnomeCDATASection(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java new file mode 100644 index 000000000..3f3d6ecb5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java @@ -0,0 +1,119 @@ +/* GnomeCharacterData.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; + +/** + * A DOM character data node implemented in libxml2. + * + * @author Chris Burdess + */ +abstract class GnomeCharacterData + extends GnomeNode + implements CharacterData +{ + + GnomeCharacterData(Object id) + { + super(id); + } + + public String getData() + throws DOMException + { + return getNodeValue(); + } + + public void setData(String data) + throws DOMException + { + setNodeValue(data); + } + + public int getLength() + { + return getData().length(); + } + + public String substringData(int offset, int count) + throws DOMException + { + return getData().substring(offset, offset + count); + } + + public void appendData(String arg) + throws DOMException + { + setData(getData() + arg); + } + + public void insertData(int offset, String arg) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + arg + data.substring(offset)); + } + + public void deleteData(int offset, int count) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + data.substring(offset + count)); + } + + public void replaceData(int offset, int count, String arg) + { + String data = getData(); + setData(data.substring(0, offset) + arg + + data.substring(offset + count)); + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[data="); + buffer.append(getData()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java new file mode 100644 index 000000000..b6985c4a4 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java @@ -0,0 +1,57 @@ +/* GnomeComment.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.Comment; + +/** + * A DOM comment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeComment + extends GnomeCharacterData + implements Comment +{ + + GnomeComment(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java new file mode 100644 index 000000000..a1af82335 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java @@ -0,0 +1,98 @@ +/* GnomeDOMException.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; + +class GnomeDOMException + extends DOMException +{ + + GnomeDOMException(short code, String message) + { + super(code, createMessage(code, message)); + } + + private static String createMessage(int code, String message) + { + if (message != null) + { + return message; + } + switch (code) + { + case INDEX_SIZE_ERR: + return "INDEX_SIZE_ERR"; + case DOMSTRING_SIZE_ERR: + return "DOMSTRING_SIZE_ERR"; + case HIERARCHY_REQUEST_ERR: + return "HIERARCHY_REQUEST_ERR"; + case WRONG_DOCUMENT_ERR: + return "WRONG_DOCUMENT_ERR"; + case INVALID_CHARACTER_ERR: + return "INVALID_CHARACTER_ERR"; + case NO_DATA_ALLOWED_ERR: + return "NO_DATA_ALLOWED_ERR"; + case NO_MODIFICATION_ALLOWED_ERR: + return "NO_MODIFICATION_ALLOWED_ERR"; + case NOT_FOUND_ERR: + return "NOT_FOUND_ERR"; + case NOT_SUPPORTED_ERR: + return "NOT_SUPPORTED_ERR"; + case INUSE_ATTRIBUTE_ERR: + return "INUSE_ATTRIBUTE_ERR"; + case INVALID_STATE_ERR: + return "INVALID_STATE_ERR"; + case SYNTAX_ERR: + return "SYNTAX_ERR"; + case INVALID_MODIFICATION_ERR: + return "INVALID_MODIFICATION_ERR"; + case NAMESPACE_ERR: + return "NAMESPACE_ERR"; + case INVALID_ACCESS_ERR: + return "INVALID_ACCESS_ERR"; + case VALIDATION_ERR: + return "VALIDATION_ERR"; + case TYPE_MISMATCH_ERR: + return "TYPE_MISMATCH_ERR"; + default: + return null; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java new file mode 100644 index 000000000..c415ec782 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java @@ -0,0 +1,84 @@ +/* GnomeDOMStringList.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMStringList; + +/** + * Implementation of a string list using an array of strings. + * + * @author Chris Burdess + */ +class GnomeDOMStringList + implements DOMStringList +{ + + final String[] values; + + GnomeDOMStringList(String[] values) + { + this.values = values; + } + + public int getLength() + { + return values.length; + } + + public String item(int index) + { + if (index < 0 || index >= values.length) + { + return null; + } + return values[index]; + } + + public boolean contains(String value) + { + for (int i = 0; i < values.length; i++) + { + if (values[i].equalsIgnoreCase(value)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java new file mode 100644 index 000000000..0d1b487d8 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java @@ -0,0 +1,562 @@ +/* GnomeDocument.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; +import gnu.xml.dom.DomNodeIterator; + +import java.util.Iterator; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * A DOM document node implemented in libxml2. + * + * @author Chris Burdess + */ +public class GnomeDocument + extends GnomeNode + implements Document, DOMConfiguration, XPathEvaluator, DocumentTraversal +{ + + DOMImplementation dom; + + /** + * Not currently used. + */ + boolean strictErrorChecking; + + /* DOMConfiguration */ + boolean canonicalForm = false; + boolean cdataSections = true; + boolean checkCharacterNormalization = false; + boolean comments = true; + boolean datatypeNormalization = false; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaces = true; + boolean namespaceDeclarations = true; + boolean normalizeCharacters = false; + boolean splitCdataSections = true; + boolean validate = false; + boolean validateIfSchema = false; + boolean wellFormed = true; + + GnomeDocument(Object id) + { + super(id); + strictErrorChecking = true; + } + + protected void finalize() + { + free(id); + } + + private native void free(Object id); + + public native DocumentType getDoctype(); + + public DOMImplementation getImplementation() + { + return dom; + } + + public native Element getDocumentElement(); + + public Element createElement(String tagName) + throws DOMException + { + return createElementNS(null, tagName); + } + + public native DocumentType createDocumentType(String name, String publicId, + String systemId); + + public native DocumentFragment createDocumentFragment(); + + public native Text createTextNode(String data); + + public native Comment createComment(String data); + + public native CDATASection createCDATASection(String data) + throws DOMException; + + public native ProcessingInstruction createProcessingInstruction(String target, + String data) + throws DOMException; + + public Attr createAttribute(String name) + throws DOMException + { + return createAttributeNS(null, name); + } + + public native EntityReference createEntityReference(String name) + throws DOMException; + + public native NodeList getElementsByTagName(String tagName); + + public Node importNode(Node importedNode, boolean deep) + throws DOMException + { + Node ret = xmljImportNode(importedNode, deep); + if (importedNode instanceof GnomeNode) + { + ((GnomeNode) importedNode) + .notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + importedNode, ret); + } + return ret; + } + + private native Node xmljImportNode(Node importedNode, boolean deep) + throws DOMException; + + public native Element createElementNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native Attr createAttributeNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public Element getElementById(String elementId) + { + Element element = xmljGetElementById(elementId); + if (element == null) + { + TreeWalker walker = createTreeWalker(this, NodeFilter.SHOW_ELEMENT, + null, false); + for (Node node = walker.nextNode(); node != null; + node = walker.nextNode()) + { + GnomeElement e = (GnomeElement) node; + if (e.userIdAttrs != null) + { + for (Iterator i = e.userIdAttrs.iterator(); i.hasNext(); ) + { + Attr attr = (Attr) i.next(); + if (attr.getNodeValue().equals(elementId)) + { + return e; + } + } + } + } + } + return element; + } + + private native Element xmljGetElementById(String elementId); + + // DOM Level 3 methods + + public native String getInputEncoding(); + + public native String getXmlEncoding(); + + public native boolean getXmlStandalone(); + + public native void setXmlStandalone(boolean xmlStandalone); + + public native String getXmlVersion(); + + public native void setXmlVersion(String xmlVersion); + + public boolean getStrictErrorChecking() + { + return strictErrorChecking; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + this.strictErrorChecking = strictErrorChecking; + } + + public native String getDocumentURI(); + + public native void setDocumentURI(String documentURI); + + public Node adoptNode(Node source) + throws DOMException + { + if (source == null || !(source instanceof GnomeNode)) + { + return null; + } + Node ret = xmljAdoptNode(source); + if (source instanceof GnomeNode) + { + ((GnomeNode) source). + notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, + source, ret); + } + return ret; + } + + private native Node xmljAdoptNode(Node source) + throws DOMException; + + public DOMConfiguration getDomConfig() + { + return this; + } + + public void normalizeDocument() + { + normalize(); + } + + public native Node renameNode(Node n, String namespaceURI, + String qualifiedName); + + // -- DOMConfiguration methods -- + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + /* optional + canonicalForm = getBooleanValue(value);*/ + } + else if ("cdata-sections".equals(name)) + { + cdataSections = getBooleanValue(value); + } + else if ("check-character-normalization".equals(name)) + { + /* optional + checkCharacterNormalization = getBooleanValue(value);*/ + } + else if ("comments".equals(name)) + { + comments = getBooleanValue(value); + } + else if ("datatype-normalization".equals(name)) + { + /* optional + datatypeNormalization = getBooleanValue(value);*/ + } + else if ("element-content-whitespace".equals(name)) + { + /* optional + elementContentWhitespace = getBooleanValue(value);*/ + } + else if ("entities".equals(name)) + { + entities = getBooleanValue(value); + } + else if ("error-handler".equals(name)) + { + errorHandler = (DOMErrorHandler) value; + } + else if ("infoset".equals(name)) + { + if (getBooleanValue(value)) + { + validateIfSchema = false; + entities = false; + datatypeNormalization = false; + cdataSections = false; + namespaceDeclarations = true; + wellFormed = true; + elementContentWhitespace = true; + comments = true; + namespaces = true; + } + } + else if ("namespaces".equals(name)) + { + /* optional + namespaces = getBooleanValue(value);*/ + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = getBooleanValue(value); + } + else if ("normalize-characters".equals(name)) + { + /* optional + normalizeCharacters = getBooleanValue(value);*/ + } + else if ("split-cdata-sections".equals(name)) + { + splitCdataSections = getBooleanValue(value); + } + else if ("validate".equals(name)) + { + /* optional + validate = getBooleanValue(value);*/ + } + else if ("validate-if-schema".equals(name)) + { + /* optional + validateIfSchema = getBooleanValue(value);*/ + } + else if ("well-formed".equals(name)) + { + /* optional + wellFormed = getBooleanValue(value);*/ + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + return Boolean.valueOf(canonicalForm); + } + else if ("cdata-sections".equals(name)) + { + return Boolean.valueOf(cdataSections); + } + else if ("check-character-normalization".equals(name)) + { + return Boolean.valueOf(checkCharacterNormalization); + } + else if ("comments".equals(name)) + { + return Boolean.valueOf(comments); + } + else if ("datatype-normalization".equals(name)) + { + return Boolean.valueOf(datatypeNormalization); + } + else if ("element-content-whitespace".equals(name)) + { + return Boolean.valueOf(elementContentWhitespace); + } + else if ("entities".equals(name)) + { + return Boolean.valueOf(entities); + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("infoset".equals(name)) + { + return Boolean.valueOf(!validateIfSchema && + !entities && + !datatypeNormalization && + !cdataSections && + namespaceDeclarations && + wellFormed && + elementContentWhitespace && + comments && + namespaces); + } + else if ("namespaces".equals(name)) + { + return Boolean.valueOf(namespaces); + } + else if ("namespace-declarations".equals(name)) + { + return Boolean.valueOf(namespaceDeclarations); + } + else if ("normalize-characters".equals(name)) + { + return Boolean.valueOf(normalizeCharacters); + } + else if ("split-cdata-sections".equals(name)) + { + return Boolean.valueOf(splitCdataSections); + } + else if ("validate".equals(name)) + { + return Boolean.valueOf(validate); + } + else if ("validate-if-schema".equals(name)) + { + return Boolean.valueOf(validateIfSchema); + } + else if ("well-formed".equals(name)) + { + return Boolean.valueOf(wellFormed); + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + return ("cdata-sections".equals(name) || + "comments".equals(name) || + "entities".equals(name) || + "namespace-declarations".equals(name) || + "split-cdata-sections".equals(name)); + } + + public DOMStringList getParameterNames() + { + String[] names = new String[] { + "canonical-form", + "cdata-sections", + "check-character-normalization", + "comments", + "datatype-normalization", + "element-content-whitespace", + "entities", + "error-handler", + "infoset", + "namespaces", + "namespace-declarations", + "normalize-characters", + "split-cdata-sections", + "validate", + "validate-if-schema", + "well-formed" + }; + return new GnomeDOMStringList(names); + } + + private boolean getBooleanValue(Object value) + { + if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue(); + } + else if (value instanceof String) + { + return Boolean.valueOf ((String) value).booleanValue(); + } + return false; + } + + // -- XPathEvaluator methods -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new GnomeXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new GnomeXPathNSResolver(nodeResolver); + } + + public native Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException; + + // -- DocumentTraversal methods -- + + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, true); + } + + // -- Debugging -- + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[version="); + buffer.append(getXmlVersion()); + buffer.append(",standalone="); + buffer.append(getXmlStandalone()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java new file mode 100644 index 000000000..6dea87226 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java @@ -0,0 +1,326 @@ +/* GnomeDocumentBuilder.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import java.io.InputStream; +import java.io.IOException; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMImplementation; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneDocumentType; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A JAXP DOM implementation that uses Gnome libxml2 as the underlying + * parser and node representation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilder + extends DocumentBuilder + implements DOMImplementation +{ + + static + { + XMLJ.init(); + } + + // -- DocumentBuilder -- + + private boolean validate; + private boolean coalesce; + private boolean expandEntities; + private EntityResolver entityResolver; + private ErrorHandler errorHandler; + private boolean seenFatalError; + + /** + * Constructs a new validating document builder. + */ + public GnomeDocumentBuilder() + { + this(true, false, false); + } + + /** + * Constructs a new document builder. + * @param validate whether to validate during parsing + * @param coalesce whether to merge CDATA as text nodes + * @param expandEntities whether to expand entity references + */ + public GnomeDocumentBuilder(boolean validate, + boolean coalesce, + boolean expandEntities) + { + this.validate = validate; + this.coalesce = coalesce; + this.expandEntities = expandEntities; + } + + public DOMImplementation getDOMImplementation() + { + return this; + } + + public boolean isNamespaceAware() + { + return true; + } + + public boolean isValidating() + { + return validate; + } + + public Document newDocument() + { + return createDocument(null, null, null); + } + + public Document parse(InputSource input) + throws SAXException, IOException + { + NamedInputStream in = XMLJ.getInputStream(input); + byte[] detectBuffer = in.getDetectBuffer(); + String publicId = input.getPublicId(); + String systemId = input.getSystemId(); + String base = XMLJ.getBaseURI(systemId); + // Handle zero-length document + if (detectBuffer == null) + { + throw new SAXParseException("No document element", publicId, + systemId, 0, 0); + } + seenFatalError = false; + return parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validate, + coalesce, + expandEntities, + true, //entityResolver != null, + errorHandler != null); + } + + private native Document parseStream(InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean coalesce, + boolean expandEntities, + boolean entityResolver, + boolean errorHandler); + + public void setEntityResolver(EntityResolver resolver) + { + entityResolver = resolver; + } + + public void setErrorHandler(ErrorHandler handler) + { + errorHandler = handler; + } + + // -- DOMImplementation -- + + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + // TODO + /* + return (version == null || + "".equals(version) || + "3.0".equals(version)); + */ + return false; + } + else if ("traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + return false; + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + return this; + } + return null; + } + + public native Document createDocument(String namespaceURI, + String qualifiedName, + DocumentType doctype); + + public DocumentType createDocumentType(String qualifiedName, + String publicId, + String systemId) + { + return new StandaloneDocumentType(qualifiedName, publicId, systemId); + } + + // Callback hooks from JNI + + private void setDocumentLocator(Object ctx, Object loc) + { + // ignore + } + + private InputStream resolveEntity(String publicId, String systemId, + String base) + throws SAXException, IOException + { + String url = XMLJ.getAbsoluteURI(base, systemId); + InputStream in = null; + if (entityResolver != null) + { + InputSource source = entityResolver.resolveEntity(publicId, url); + if (source != null) + { + in = XMLJ.getInputStream(source); + } + } + if (in == null) + { + in = XMLJ.getInputStream(new URL(url)); + } + return in; + } + + private void warning(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.warning(new SAXParseException(message, l)); + } + } + + private void error(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.error(new SAXParseException(message, l)); + } + } + + private void fatalError(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + seenFatalError = true; + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.fatalError(new SAXParseException(message, l)); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java new file mode 100644 index 000000000..448e12351 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java @@ -0,0 +1,118 @@ +/* GnomeDocumentBuilderFactory.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Factory for JAXP document builders using the libxml2 implementation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilderFactory + extends DocumentBuilderFactory +{ + + private boolean secureProcessing; + + public GnomeDocumentBuilderFactory () + { + setNamespaceAware (true); + } + + public Object getAttribute (String name) + { + // TODO + return null; + } + + public DocumentBuilder newDocumentBuilder () + throws ParserConfigurationException + { + /* + if (!isNamespaceAware ()) + { + String msg = "Parser must be namespace-aware"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringComments ()) + { + String msg = "Ignoring comments not supported"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringElementContentWhitespace ()) + { + String msg = "Ignoring element content whitespace not supported"; + throw new ParserConfigurationException (msg); + } + */ + return new GnomeDocumentBuilder (isValidating (), + isCoalescing (), + isExpandEntityReferences ()); + } + + public void setAttribute (String name, Object value) + { + // TODO + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java new file mode 100644 index 000000000..3623eb6cf --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java @@ -0,0 +1,57 @@ +/* GnomeDocumentFragment.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.DocumentFragment; + +/** + * A DOM document fragment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentFragment +extends GnomeNode +implements DocumentFragment +{ + + GnomeDocumentFragment (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java new file mode 100644 index 000000000..7649b7339 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java @@ -0,0 +1,98 @@ +/* GnomeDocumentType.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; + +/** + * A DOM document type node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentType +extends GnomeNode +implements DocumentType +{ + + GnomeDocumentType (Object id) + { + super (id); + } + + public String getName () + { + return getNodeName (); + } + + public NamedNodeMap getEntities () + { + return new GnomeNamedNodeMap (id, 1); + } + + public NamedNodeMap getNotations () + { + return new GnomeNamedNodeMap (id, 2); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getInternalSubset (); + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java new file mode 100644 index 000000000..19889d663 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java @@ -0,0 +1,184 @@ +/* GnomeElement.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; + +/** + * A DOM element node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeElement + extends GnomeNode + implements Element +{ + + /** + * User-defined ID attributes. + */ + Set userIdAttrs; + + GnomeElement(Object id) + { + super(id); + } + + public String getTagName() + { + return getNodeName(); + } + + public native String getAttribute(String name); + + public native void setAttribute(String name, String value) + throws DOMException; + + public void removeAttribute(String name) + throws DOMException + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNode(String name); + + public native Attr setAttributeNode(Attr newAttr) + throws DOMException; + + public native Attr removeAttributeNode(Attr oldAttr) + throws DOMException; + + public native NodeList getElementsByTagName(String name); + + public native String getAttributeNS(String namespaceURI, String localName); + + public native void setAttributeNS(String namespaceURI, String + qualifiedName, String value) + throws DOMException; + + public void removeAttributeNS(String namespaceURI, String localName) + throws DOMException + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNodeNS(String namespaceURI, + String localName); + + public native Attr setAttributeNodeNS(Attr newAttr) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public native boolean hasAttribute(String name); + + public native boolean hasAttributeNS(String namespaceURI, + String localName); + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public void setIdAttribute(String name, boolean isId) + { + Attr attr = getAttributeNode(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (attr == null)// FIXME || !attr.getOwnerElement().equals(this)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[tagName="); + buffer.append(getTagName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java new file mode 100644 index 000000000..a05217473 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java @@ -0,0 +1,104 @@ +/* GnomeEntity.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Entity; + +/** + * A DOM entity node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntity +extends GnomeNode +implements Entity +{ + + GnomeEntity (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getNotationName (); + + // DOM Level 3 methods + + public String getInputEncoding () + { + // TODO + return null; + } + + public String getXmlEncoding () + { + // TODO + return null; + } + + public String getXmlVersion () + { + // TODO + return null; + } + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append (",notationName="); + buffer.append (getNotationName ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java new file mode 100644 index 000000000..aa2fcf1e5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java @@ -0,0 +1,57 @@ +/* GnomeEntityReference.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.EntityReference; + +/** + * A DOM entity reference node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntityReference +extends GnomeNode +implements EntityReference +{ + + GnomeEntityReference (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java new file mode 100644 index 000000000..b8df4fede --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java @@ -0,0 +1,92 @@ +/* GnomeNamedNodeMap.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A DOM named node map implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNamedNodeMap +implements NamedNodeMap +{ + + /** + * The node id. + */ + private final Object id; + + /** + * The map type. + * 0=attributes + * 1=entities + * 2=notations + */ + private final int type; + + GnomeNamedNodeMap (Object id, int type) + { + this.id = id; + this.type = type; + } + + public native Node getNamedItem (String name); + + public native Node setNamedItem (Node arg) + throws DOMException; + + public native Node removeNamedItem (String name) + throws DOMException; + + public native Node item (int index); + + public native int getLength (); + + public native Node getNamedItemNS (String namespaceURI, String localName); + + public native Node setNamedItemNS (Node arg) + throws DOMException; + + public native Node removeNamedItemNS (String namespaceURI, + String localName); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java new file mode 100644 index 000000000..5874916e5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java @@ -0,0 +1,501 @@ +/* GnomeNode.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; + +import gnu.xml.libxmlj.util.StandaloneDocumentType; + +/** + * A DOM node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNode + implements Node, Comparable +{ + + /** + * Maps document pointers to a map of node pointers to node instances. + */ + static Map instances; + + /** + * Retrieves the node instance for the specified node pointer. + * This creates a new instance and adds it to the cache if required. + * @param doc the document pointer + * @param node the node pointer + * @param type the node type + */ + static GnomeNode newInstance(final Object doc, final Object node, + final int type) + { + if (doc == null) + { + throw new NullPointerException("doc"); + } + if (node == null) + { + throw new NullPointerException("node"); + } + if (instances == null) + { + instances = new HashMap(); + } + Map docNodes = (Map) instances.get(doc); + if (docNodes == null) + { + docNodes = new HashMap(1024); // TODO review optimal initial capacity + instances.put(doc, docNodes); + } + GnomeNode nodeInstance = (GnomeNode) docNodes.get(node); + if (nodeInstance != null) + { + return nodeInstance; // Return cached version + } + switch (type) + { + case ELEMENT_NODE: + nodeInstance = new GnomeElement(node); + break; + case ATTRIBUTE_NODE: + nodeInstance = new GnomeAttr(node); + break; + case TEXT_NODE: + nodeInstance = new GnomeText(node); + break; + case CDATA_SECTION_NODE: + nodeInstance = new GnomeCDATASection(node); + break; + case ENTITY_REFERENCE_NODE: + nodeInstance = new GnomeEntityReference(node); + break; + case ENTITY_NODE: + nodeInstance = new GnomeEntity(node); + break; + case PROCESSING_INSTRUCTION_NODE: + nodeInstance = new GnomeProcessingInstruction(node); + break; + case COMMENT_NODE: + nodeInstance = new GnomeComment(node); + break; + case DOCUMENT_NODE: + nodeInstance = new GnomeDocument(node); + break; + case DOCUMENT_TYPE_NODE: + nodeInstance = new GnomeDocumentType(node); + break; + case DOCUMENT_FRAGMENT_NODE: + nodeInstance = new GnomeDocumentFragment(node); + break; + case NOTATION_NODE: + nodeInstance = new GnomeNotation(node); + break; + default: + throw new IllegalArgumentException("Unknown node type: " + type); + } + docNodes.put(node, nodeInstance); + return nodeInstance; + } + + /** + * Frees the specified document. + * This removes all its nodes from the cache. + */ + static void freeDocument(final Object doc) + { + if (instances == null || doc == null) + { + return; + } + instances.remove(doc); + //System.out.println("Freed "+instances.remove(doc)); + } + + /** + * xmlNodePtr + */ + final Object id; + + Map userData; + Map userDataHandlers; + + GnomeNode(final Object id) + { + this.id = id; + } + + public native String getNodeName(); + + public native String getNodeValue() + throws DOMException; + + public native void setNodeValue(String nodeValue) + throws DOMException; + + public native short getNodeType(); + + public native Node getParentNode(); + + public NodeList getChildNodes() + { + return new GnomeNodeList(id); + } + + public native Node getFirstChild(); + + public native Node getLastChild(); + + public native Node getPreviousSibling(); + + public native Node getNextSibling(); + + public NamedNodeMap getAttributes() + { + return new GnomeNamedNodeMap(id, 0); + } + + public native Document getOwnerDocument(); + + public Node insertBefore(Node newChild, Node refChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + if (refChild == null || !(refChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljInsertBefore(newChild, refChild); + } + + private native Node xmljInsertBefore(Node newChild, Node refChild) + throws DOMException; + + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, newChild.toString()); + } + if (oldChild == null || !(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljReplaceChild(newChild, oldChild); + } + + private native Node xmljReplaceChild(Node newChild, Node oldChild) + throws DOMException; + + public Node removeChild(Node oldChild) + throws DOMException + { + if (!(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljRemoveChild(oldChild); + } + + private native Node xmljRemoveChild(Node oldChild) + throws DOMException; + + public Node appendChild(Node newChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljAppendChild(newChild); + } + + private native Node xmljAppendChild(Node newChild) + throws DOMException; + + public native boolean hasChildNodes(); + + public Node cloneNode(boolean deep) + { + Node ret = xmljCloneNode(deep); + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, ret); + return ret; + } + + private native Node xmljCloneNode(boolean deep); + + public native void normalize(); + + public boolean isSupported(String feature, String version) + { + return getOwnerDocument().getImplementation() + .hasFeature(feature, version); + } + + public native String getNamespaceURI(); + + public native String getPrefix(); + + public native void setPrefix(String prefix) + throws DOMException; + + public native String getLocalName(); + + public native boolean hasAttributes(); + + public int hashCode() + { + return id.hashCode(); + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + return (other instanceof GnomeNode && + ((GnomeNode) other).id == id); + } + + // DOM Level 3 methods + + public native String getBaseURI(); + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + public final int compareTo(Object other) + { + if (other instanceof GnomeNode) + { + return xmljCompareTo(other); + } + return 0; + } + + private native int xmljCompareTo(Object other); + + public String getTextContent() + throws DOMException + { + switch (getNodeType()) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + CPStringBuilder buffer = new CPStringBuilder(); + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + String textContent = child.getTextContent(); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return getNodeValue(); + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (getNodeType()) + { + case ENTITY_REFERENCE_NODE: + // entity references are read only + throw new GnomeDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null); + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case DOCUMENT_FRAGMENT_NODE: + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + removeChild(child); + } + if (textContent != null) + { + Text text = getOwnerDocument().createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return equals(other); + } + + public native String lookupPrefix(String namespaceURI); + + public native boolean isDefaultNamespace(String namespaceURI); + + public native String lookupNamespaceURI(String prefix); + + public native boolean isEqualNode(Node arg); + + public Object getFeature(String feature, String version) + { + return getOwnerDocument().getImplementation() + .getFeature(feature, version); + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + // TODO handler + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[nodeName="); + buffer.append(getNodeName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java new file mode 100644 index 000000000..51a6d0bfa --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java @@ -0,0 +1,66 @@ +/* GnomeNodeList.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A DOM node list implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNodeList +implements NodeList +{ + + /** + * The node id. + */ + private final Object id; + + GnomeNodeList (Object id) + { + this.id = id; + } + + public native Node item (int index); + + public native int getLength (); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java new file mode 100644 index 000000000..50e48e2a3 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java @@ -0,0 +1,80 @@ +/* GnomeNotation.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Notation; + +/** + * A DOM notation node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNotation +extends GnomeNode +implements Notation +{ + + GnomeNotation (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java new file mode 100644 index 000000000..fad6e108a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java @@ -0,0 +1,79 @@ +/* GnomeProcessingInstruction.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + * A DOM processing instruction node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeProcessingInstruction +extends GnomeNode +implements ProcessingInstruction +{ + + GnomeProcessingInstruction (Object id) + { + super (id); + } + + public String getTarget () + { + return getNodeName (); + } + + public native String getData (); + + public native void setData (String data) + throws DOMException; + + public String toString () + { + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("[data="); + buffer.append (getData ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java new file mode 100644 index 000000000..e00be18a9 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java @@ -0,0 +1,132 @@ +/* GnomeText.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * A DOM text node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeText +extends GnomeCharacterData +implements Text +{ + + GnomeText (Object id) + { + super (id); + } + + public Text splitText (int offset) + throws DOMException + { + String value = getNodeValue (); + String part1 = value.substring (0, offset); + String part2 = value.substring (offset); + Text text = getOwnerDocument ().createTextNode (part1); + getParentNode ().insertBefore (text, this); + setNodeValue (part2); + return text; + } + + // DOM Level 3 + + public boolean isElementContentWhitespace () + { + return getTextContent ().trim ().length () == 0; + } + + public String getWholeText () + { + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + CPStringBuilder buf = new CPStringBuilder (first.getNodeValue ()); + node = first.getNextSibling (); + while (node != null && node instanceof Text) + { + buf.append (node.getNodeValue ()); + node = node.getNextSibling (); + } + return buf.toString (); + } + + public Text replaceWholeText (String content) throws DOMException + { + boolean isEmpty = (content == null || content.length () == 0); + if (!isEmpty) + { + setNodeValue (content); + } + + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + node = first.getNextSibling (); + Node parent = getParentNode (); + if (first != this || isEmpty) + { + parent.removeChild (first); + } + while (node != null && node instanceof Text) + { + Node tmp = node; + node = node.getNextSibling (); + if (tmp != this || isEmpty) + { + parent.removeChild (tmp); + } + } + return (isEmpty) ? null : this; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java new file mode 100644 index 000000000..5517e8a99 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java @@ -0,0 +1,65 @@ +/* GnomeTypeInfo.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Provides XML Schema information about an element or attribute. + * + * @author Chris Burdess + */ +class GnomeTypeInfo implements TypeInfo +{ + + final Object id; + + GnomeTypeInfo(Object id) + { + this.id = id; + } + + public native String getTypeName (); + + public native String getTypeNamespace (); + + public native boolean isDerivedFrom (String typeNamespaceArg, + String typeNameArg, + int derivationMethod); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java new file mode 100644 index 000000000..52f4daa21 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java @@ -0,0 +1,86 @@ +/* GnomeXPathExpression.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * A compiled XPath expression implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathExpression +implements XPathExpression +{ + + /** + * xmlXPathCompExprPtr + */ + final Object expr; + + GnomeXPathExpression (GnomeDocument doc, String expression, + XPathNSResolver resolver) + { + expr = init (expression); + // TODO resolver + } + + protected void finalize () + { + free (expr); + } + + private native Object init (String expression); + + private native void free (Object expr); + + public Object evaluate (Node contextNode, short type, Object result) + throws XPathException, DOMException + { + return doEvaluate (expr, contextNode, type, result); + } + + private native Object doEvaluate (Object expr, Node contextNode, + short type, Object result) + throws XPathException, DOMException; + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java new file mode 100644 index 000000000..039a79a03 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java @@ -0,0 +1,64 @@ +/* GnomeXPathNSResolver.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * XPath namespace URI resolver implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathNSResolver + implements XPathNSResolver +{ + + Node node; + + GnomeXPathNSResolver(Node node) + { + this.node = node; + } + + public String lookupNamespaceURI(String prefix) + { + return node.lookupNamespaceURI(prefix); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java new file mode 100644 index 000000000..b8d0a3d0a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java @@ -0,0 +1,73 @@ +/* GnomeXPathNodeList.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A node list that uses an XPath result object. + * + * @author Chris Burdess + */ +class GnomeXPathNodeList +implements NodeList +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathNodeList (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free(obj); + } + + private native void free (Object obj); + + public native int getLength (); + + public native Node item (int index); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java new file mode 100644 index 000000000..b2c706f65 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java @@ -0,0 +1,134 @@ +/* GnomeXPathResult.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathResult; + +/** + * An XPath result object implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathResult +implements XPathResult +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathResult (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free (obj); + } + + private native void free (Object obj); + + public native short getResultType (); + + public native double getNumberValue () + throws XPathException; + + public native String getStringValue () + throws XPathException; + + public native boolean getBooleanValue () + throws XPathException; + + public native Node getSingleNodeValue () + throws XPathException; + + public native boolean getInvalidIteratorState(); + + public native int getSnapshotLength () + throws XPathException; + + public native Node iterateNext () + throws XPathException, DOMException; + + public native Node snapshotItem (int index) + throws XPathException; + + public String toString () + { + short type = getResultType (); + switch (type) + { + case STRING_TYPE: + return getStringValue (); + case NUMBER_TYPE: + return Double.toString (getNumberValue ()); + case BOOLEAN_TYPE: + return Boolean.valueOf (getBooleanValue ()).toString (); + case UNORDERED_NODE_SNAPSHOT_TYPE: + int len = getSnapshotLength (); + switch (len) { + case 0: + return "[no matches]"; + case 1: + return getSingleNodeValue ().toString (); + default: + CPStringBuilder buffer = new CPStringBuilder (); + for (int i = 0; i < len; i++) + { + if (i > 0) + { + buffer.append (','); + } + buffer.append (snapshotItem (i)); + } + return buffer.toString (); + } + default: + return getClass ().getName () + "[type=" + type + ",length=" + + getSnapshotLength () + ']'; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java new file mode 100644 index 000000000..dba0a72c0 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java @@ -0,0 +1,99 @@ +/* GnomeLocator.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import org.xml.sax.Locator; + +/** + * SAX Locator implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeLocator +implements Locator +{ + + // An xmlParserCtxtPtr + private final Object ctx; + + // An xmlSAXLocatorPtr + private final Object loc; + + GnomeLocator (Object ctx, Object loc) + { + this.ctx = ctx; + this.loc = loc; + if (ctx == null) + { + throw new NullPointerException ("ctx"); + } + if (loc == null) + { + throw new NullPointerException ("loc"); + } + } + + public String getPublicId () + { + return publicId (ctx, loc); + } + + private native String publicId (Object ctx, Object loc); + + public String getSystemId () + { + return systemId (ctx, loc); + } + + private native String systemId (Object ctx, Object loc); + + public int getLineNumber () + { + return lineNumber (ctx, loc); + } + + private native int lineNumber (Object ctx, Object loc); + + public int getColumnNumber () + { + return columnNumber (ctx, loc); + } + + private native int columnNumber (Object ctx, Object loc); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java new file mode 100644 index 000000000..86d326b7c --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java @@ -0,0 +1,105 @@ +/* GnomeSAXParser.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import javax.xml.parsers.SAXParser; + +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * JAXP SAX parser implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeSAXParser +extends SAXParser +{ + + private boolean namespaceAware; + private boolean validating; + + /** + * Creates a new SAX parser. + */ + GnomeSAXParser (boolean namespaceAware, boolean validating) + { + this.namespaceAware = namespaceAware; + this.validating = validating; + } + + public Parser getParser () + throws SAXException + { + throw new SAXNotSupportedException ("SAX version 1 not supported"); + } + + public XMLReader getXMLReader () + throws SAXException + { + return new GnomeXMLReader (namespaceAware, validating); + } + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public boolean isNamespaceAware () + { + return namespaceAware; + } + + public boolean isValidating () + { + return validating; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java new file mode 100644 index 000000000..0c2881240 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java @@ -0,0 +1,92 @@ +/* GnomeSAXParserFactory.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import java.util.Map; +import java.util.HashMap; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * JAXP SAX parser factory implementation that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeSAXParserFactory +extends SAXParserFactory +{ + + private Map features; + + /** + * Creates a new SAX parser factory. + */ + public GnomeSAXParserFactory () + { + features = new HashMap (); + } + + public SAXParser newSAXParser () + throws ParserConfigurationException, SAXException + { + // TODO features + return new GnomeSAXParser (isNamespaceAware (), isValidating ()); + } + + public boolean getFeature (String name) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + Boolean val = (Boolean) features.get (name); + return (val == null) ? false : val.booleanValue (); + } + + public void setFeature (String name, boolean flag) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + features.put (name, flag ? Boolean.TRUE : Boolean.FALSE); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java new file mode 100644 index 000000000..3a34bc934 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java @@ -0,0 +1,1065 @@ +/* GnomeXMLReader.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A SAX2 parser that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeXMLReader +implements XMLReader +{ + + static + { + XMLJ.init (); + } + + private static final String FEATURES_PREFIX = + "http://xml.org/sax/features/"; + + private static final List RECOGNIZED_FEATURES = + Arrays.asList (new String[] + { + "external-general-entities", + "external-parameter-entities", + "is-standalone", + "lexical-handler/parameter-entities", + "namespaces", + "namespace-prefixes", + "resolve-dtd-uris", + "string-interning", + "use-attributes2", + "use-locator2", + "use-entity-resolver2", + "validation" + }); + + private static final String PROPERTIES_PREFIX = + "http://xml.org/sax/properties/"; + + private static final List RECOGNIZED_PROPERTIES = + Arrays.asList (new String[] + { + "declaration-handler", + "dom-node", + "lexical-handler", + "xml-string" + }); + + // Features + + private transient boolean standalone; + private boolean namespaces; + private boolean namespacePrefixes; + private boolean validation; + + // Callback handlers + + private ContentHandler contentHandler; + + private DTDHandler dtdHandler; + + private EntityResolver entityResolver; + + private ErrorHandler errorHandler; + + private DeclHandler declarationHandler; + + private LexicalHandler lexicalHandler; + + private GnomeLocator locator; + + // Namespace helper for handling callbacks + private transient Namespaces ns; + + // If true, do not invoke callback methods except endDocument + private transient boolean seenFatalError; + + private transient boolean seenStartDocument; + + private transient String base; + + public GnomeXMLReader () + { + this (true, true); + } + + public GnomeXMLReader (boolean namespaces, boolean validation) + { + this.namespaces = namespaces; + this.validation = validation; + ns = new Namespaces (); + } + + public ContentHandler getContentHandler () + { + return contentHandler; + } + + public void setContentHandler (ContentHandler handler) + { + contentHandler = handler; + } + + public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + public void setDTDHandler (DTDHandler handler) + { + dtdHandler = handler; + } + + public EntityResolver getEntityResolver () + { + return entityResolver; + } + + public void setEntityResolver (EntityResolver resolver) + { + entityResolver = resolver; + } + + public ErrorHandler getErrorHandler () + { + return errorHandler; + } + + public void setErrorHandler (ErrorHandler handler) + { + errorHandler = handler; + } + + // Features + + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("external-general-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("external-parameter-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("is-standalone".equals (key)) + { + return standalone; + } + else if ("namespaces".equals (key)) + { + return namespaces; + } + else if ("namespace-prefixes".equals (key)) + { + return namespacePrefixes; + } + else if ("resolve-dtd-uris".equals (key)) + { + return true; + } + else if ("validation".equals (key)) + { + return validation; + } + else + { + return false; + } + } + + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("namespaces".equals (key)) + { + namespaces = value; + } + else if ("namespace-prefixes".equals (key)) + { + namespacePrefixes = value; + } + else if ("validation".equals (key)) + { + validation = value; + } + } + + /** + * Check that the specified feature name is recognized. + */ + static void checkFeatureName (String name) + throws SAXNotRecognizedException + { + if (name == null || !name.startsWith (FEATURES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (FEATURES_PREFIX.length ()); + if (!RECOGNIZED_FEATURES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Properties + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + return getDeclarationHandler (); + } + else if ("lexical-handler".equals (key)) + { + return getLexicalHandler (); + } + else + { + throw new SAXNotSupportedException (name); + } + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + setDeclarationHandler ((DeclHandler) value); + } + else if ("lexical-handler".equals (key)) + { + setLexicalHandler ((LexicalHandler) value); + } + } + + public DeclHandler getDeclarationHandler () + { + return declarationHandler; + } + + public void setDeclarationHandler (DeclHandler declarationHandler) + { + this.declarationHandler = declarationHandler; + } + + public LexicalHandler getLexicalHandler () + { + return lexicalHandler; + } + + public void setLexicalHandler (LexicalHandler lexicalHandler) + { + this.lexicalHandler = lexicalHandler; + } + + /** + * Check that the specified property name is recognized. + */ + static void checkPropertyName (String name) + throws SAXNotRecognizedException + { + if (!name.startsWith (PROPERTIES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (PROPERTIES_PREFIX.length ()); + if (!RECOGNIZED_PROPERTIES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Parse + + public void parse (String systemId) + throws IOException, SAXException + { + URL url = null; + try + { + url = new URL (systemId); + } + catch (MalformedURLException e) + { + File file = new File(systemId); + if (!file.exists ()) + { + throw new FileNotFoundException (systemId); + } + String path = file.getAbsolutePath(); + if (File.separatorChar != '/') + { + path = path.replace (File.separatorChar, '/'); + } + if (!path.startsWith ("/")) + { + path = "/" + path; + } + if (!path.endsWith ("/") && file.isDirectory ()) + { + path = path + "/"; + } + url = new URL ("file:" + path); + } + InputSource source = new InputSource(url.toString ()); + source.setByteStream (url.openStream ()); + parse (source); + } + + public synchronized void parse (InputSource input) + throws IOException, SAXException + { + NamedInputStream in = XMLJ.getInputStream (input); + byte[] detectBuffer = in.getDetectBuffer (); + String publicId = input.getPublicId (); + String systemId = input.getSystemId (); + base = XMLJ.getBaseURI (systemId); + // Reset state + standalone = false; + seenFatalError = false; + seenStartDocument = false; + if (systemId != null) + { + int lsi = systemId.lastIndexOf ('/'); + if (lsi != -1) + { + base = systemId.substring (0, lsi + 1); + } + } + // Handle zero-length document + if (detectBuffer == null) + { + startDocument (true); + fatalError ("No document element", 0, 0, publicId, systemId); + endDocument (); + return; + } + // Parse + parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validation, + contentHandler != null, + dtdHandler != null, + entityResolver != null, + errorHandler != null, + declarationHandler != null, + lexicalHandler != null); + in.close (); + } + + native void parseStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean contentHandler, + boolean dtdHandler, + boolean entityResolver, + boolean errorHandler, + boolean declarationHandler, + boolean lexicalHandler) + throws IOException, SAXException; + + String getURI (String prefix) + { + if (!namespaces) + { + return null; + } + return ns.getURI (prefix); + } + + // Callbacks from libxmlj + + private void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || lexicalHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + lexicalHandler.startDTD (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void externalEntityDecl (String name, String publicId, + String systemId) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + declarationHandler.externalEntityDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void internalEntityDecl (String name, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.internalEntityDecl (name, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private InputStream resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + if (entityResolver == null) + { + return null; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + InputSource source = entityResolver.resolveEntity (publicId, systemId); + return (source == null) ? null : XMLJ.getInputStream (source); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.notationDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void attributeDecl (String eName, String aName, String type, + String mode, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.attributeDecl (eName, aName, type, mode, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void elementDecl (String name, String model) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.elementDecl (name, model); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.unparsedEntityDecl (name, publicId, systemId, + notationName); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void setDocumentLocator (Object ctx, Object loc) + { + locator = new GnomeLocator (ctx, loc); + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + contentHandler.setDocumentLocator (locator); + } + catch (Exception e) + { + } + } + + private void startDocument (boolean standalone) + throws SAXException + { + this.standalone = standalone; + seenStartDocument = true; + if (contentHandler == null) + { + return; + } + try + { + contentHandler.startDocument (); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endDocument () + throws SAXException + { + if (contentHandler == null) + { + return; + } + try + { + contentHandler.endDocument(); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startElement(String name, String[] attrs) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + if (namespaces) + { + // Handle defined namespaces + ns.push (); + int len = (attrs == null) ? 0 : attrs.length; + if (len > 0) + { + ArrayList filtered = new ArrayList (len); + for (int i = 0; i < len; i += 2) + { + String attName = attrs[i]; + String attValue = attrs[i + 1]; + if (attName.equals ("xmlns")) + { + startPrefixMapping ("", attValue); + } + else if (attName.startsWith ("xmlns:")) + { + startPrefixMapping (attName.substring (6), attValue); + } + else + { + filtered.add (attName); + filtered.add (attValue); + } + } + // Remove xmlns attributes + attrs = new String[filtered.size ()]; + filtered.toArray (attrs); + } + } + // Construct attributes + Attributes atts = new StringArrayAttributes (this, attrs); + contentHandler.startElement (xName.uri, xName.localName, xName.qName, + atts); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endElement (String name) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + String uri = (xName.uri == null) ? "" : xName.uri; + contentHandler.endElement (uri, xName.localName, xName.qName); + // Handle undefining namespaces + if (namespaces) + { + for (Iterator i = ns.currentPrefixes (); i.hasNext (); ) + { + endPrefixMapping ((String) i.next ()); + } + ns.pop (); // releases current depth + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + ns.define (prefix, uri); + contentHandler.startPrefixMapping (prefix, uri); + } + + private void endPrefixMapping (String prefix) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + contentHandler.endPrefixMapping (prefix); + } + + private void characters (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.characters (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void ignorableWhitespace (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.ignorableWhitespace (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void processingInstruction (String target, String data) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + if (data == null) + { + data = ""; + } + contentHandler.processingInstruction (target, data); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void comment (String text) + throws SAXException + { + if (seenFatalError || lexicalHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + lexicalHandler.comment (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void cdataBlock (String text) + throws SAXException + { + if (seenFatalError || text == null) + { + return; + } + try + { + if (lexicalHandler == null) + { + characters(text); + } + else + { + lexicalHandler.startCDATA(); + characters(text); + lexicalHandler.endCDATA(); + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void warning (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.warning (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void error (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.error (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void fatalError (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + if (!seenStartDocument) + { + startDocument (false); + } + seenFatalError = true; + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.fatalError (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java new file mode 100644 index 000000000..473d02028 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java @@ -0,0 +1,122 @@ +/* Namespaces.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for managing namespaces. + * + * @author Chris Burdess + */ +class Namespaces +{ + + ArrayList stack = new ArrayList (); + + /** + * Increments the tree depth. + * This allocates a new potential namespace entry. + */ + void push () + { + stack.add (null); + } + + /** + * Decrements the tree depth. + * This removes namespaces defined at the extremity. + */ + void pop () + { + stack.remove (stack.size() - 1); + } + + /** + * Searches for the namespace URI corresponding to the specified prefix. + */ + String getURI (String prefix) + { + for (int i = stack.size () - 1; i >= 0; i--) + { + HashMap ns = (HashMap) stack.get (i); + if (ns != null && ns.containsKey (prefix)) + { + String ret = (String) ns.get (prefix); + return (ret == null) ? "" : ret; + } + } + return ""; + } + + /** + * Defines the specified prefix-URI mapping at the current depth in the + * tree. + */ + void define (String prefix, String uri) + { + int index = stack.size () - 1; + HashMap ns = (HashMap) stack.get (index); + if (ns == null) + { + ns = new HashMap (); + stack.set (index, ns); + } + ns.put (prefix, uri); + } + + /** + * Returns an iterator over the prefixes defined at the current depth. + */ + Iterator currentPrefixes () + { + HashMap ns = (HashMap) stack.get (stack.size () - 1); + if (ns == null) + { + return Collections.EMPTY_LIST.iterator (); + } + else + { + return ns.keySet ().iterator (); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java new file mode 100644 index 000000000..f5a753c56 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java @@ -0,0 +1,170 @@ +/* StringArrayAttributes.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +import org.xml.sax.Attributes; + +/** + * An implementation of Attributes that reads values from an array of + * strings, supplied by libxml2. + * Each pair of elements in the array represents a key followed by a value. + * + * @author Chris Burdess + */ +class StringArrayAttributes +implements Attributes +{ + + private int len; + private XMLName[] keys; + private String[] values; + + StringArrayAttributes (GnomeXMLReader parser, String[] pairs) + { + len = (pairs == null) ? 0 : pairs.length / 2; + keys = new XMLName[len]; + values = new String[len]; + for (int i = 0; i < len; i++) + { + int pairIndex = i * 2; + keys[i] = new XMLName (parser, pairs[pairIndex]); + values[i] = pairs[pairIndex + 1]; + } + } + + public int getLength () + { + return len; + } + + public String getURI (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].uri; + } + + public String getLocalName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].localName; + } + + public String getQName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].qName; + } + + public String getType (int index) + { + if (index < 0 || index >= len) + { + return null; + } + // TODO can we get this information from libxml2? + return "CDATA"; + } + + public String getValue (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return values[index]; + } + + public int getIndex (String uri, String localName) + { + for (int i = 0; i < len; i++) + { + XMLName key = keys[i]; + if (key.localName.equals (localName)) + { + if ((key.uri == null && uri == null) || + (key.uri != null && key.uri.equals(uri))) + { + return i; + } + } + } + return -1; + } + + public int getIndex (String qName) + { + for (int i = 0; i < len; i++) + { + if (keys[i].qName.equals (qName)) + { + return i; + } + } + return -1; + } + + public String getType (String uri, String localName) + { + return getType (getIndex (uri, localName)); + } + + public String getType (String qName) + { + return getType (getIndex (qName)); + } + + public String getValue (String uri, String localName) + { + return getValue (getIndex (uri, localName)); + } + + public String getValue (String qName) + { + return getValue (getIndex (qName)); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java new file mode 100644 index 000000000..b9bdf9159 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java @@ -0,0 +1,92 @@ +/* XMLName.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.sax; + +/** + * Structure containing the components of an XML element/attribute name. + * + * @author Chris Burdess + */ +class XMLName +{ + + private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; + + final String uri; + final String localName; + final String qName; + final String prefix; + + XMLName (GnomeXMLReader parser, String qName) + { + this.qName = qName; + int ci = qName.lastIndexOf (':'); + if (ci < 1) + { + localName = qName; + prefix = null; + uri = ""; + } + else + { + localName = qName.substring (ci + 1); + prefix = qName.substring (0, ci); + if ("xml".equals (prefix)) + { + if ("lang".equals (localName) || "space".equals (localName)) + { + uri = XML_URI; + } + else + { + uri = parser.getURI (prefix); + } + } + else + { + uri = parser.getURI (prefix); + } + } + } + + public String toString () + { + return qName; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java new file mode 100644 index 000000000..398a0ba2e --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java @@ -0,0 +1,111 @@ +/* ErrorListenerErrorHandler.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.transform; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * Provides a SAX ErrorHandler interface to an ErrorListener. + * + * @author Chris Burdess + */ +class ErrorListenerErrorHandler +implements ErrorHandler +{ + + private ErrorListener listener; + + ErrorListenerErrorHandler (ErrorListener listener) + { + this.listener = listener; + } + + public void warning (SAXParseException e) + throws SAXException + { + try + { + listener.warning (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void error (SAXParseException e) + throws SAXException + { + try + { + listener.error (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void fatalError (SAXParseException e) + throws SAXException + { + try + { + listener.fatalError (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + private SAXException getSAXException (TransformerException e) + { + Throwable cause = e.getCause (); + if (cause instanceof SAXException) + { + return (SAXException) cause; + } + return new SAXException (e); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java new file mode 100755 index 000000000..5f31cb898 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java @@ -0,0 +1,572 @@ +/* GnomeTransformer.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.transform; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URL; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Node; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; + +import gnu.xml.libxmlj.dom.GnomeDocument; +import gnu.xml.libxmlj.sax.GnomeXMLReader; +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * An implementation of {@link javax.xml.transform.Transformer} which + * performs XSLT transformation using libxslt. + * + * @author Julian Scheid + * @author Chris Burdess + */ +public class GnomeTransformer + extends Transformer + implements Templates +{ + + /** + * The parameters added by the user via {@link setParameter()}. + */ + private Map parameters; + + /** + * The output properties set by the user. + */ + private Properties outputProperties; + + /** + * The URI resolver to use during transformation. + */ + private URIResolver resolver; + + /** + * The error listener for transformation errors. + */ + private ErrorListener errorListener; + + /** + * Handle to the source stylesheet. + * This is a native pointer of type xsltStylesheetPtr. + */ + private Object stylesheet; + + /** + * Constructor. + * @param source the XSLT stylesheet document source + * @param resolver the resolver to use during transformation + * @param errorListener the error listener for transformation errors + */ + GnomeTransformer (Source source, + URIResolver resolver, + ErrorListener errorListener) + throws TransformerConfigurationException + { + this.resolver = resolver; + this.errorListener = errorListener; + parameters = new HashMap (); + outputProperties = new Properties (); + + if (source == null) + { + stylesheet = newStylesheet (); + } + else if (source instanceof StreamSource) + { + try + { + StreamSource ss = (StreamSource) source; + NamedInputStream in = XMLJ.getInputStream (ss); + String systemId = ss.getSystemId (); + String publicId = ss.getPublicId (); + String base = XMLJ.getBaseURI (systemId); + byte[] detectBuffer = in.getDetectBuffer (); + if (detectBuffer == null) + { + String msg = "No document element"; + throw new TransformerConfigurationException (msg); + } + stylesheet = newStylesheetFromStream (in, detectBuffer, publicId, + systemId, base, + (resolver != null), + (errorListener != null)); + } + catch (IOException e) + { + throw new TransformerConfigurationException (e); + } + } + else if (source instanceof DOMSource) + { + DOMSource ds = (DOMSource) source; + Node node = ds.getNode (); + if (!(node instanceof GnomeDocument)) + { + String msg = "Node is not a GnomeDocument"; + throw new TransformerConfigurationException (msg); + } + GnomeDocument doc = (GnomeDocument) node; + stylesheet = newStylesheetFromDoc (doc); + } + else + { + String msg = "Source type not supported (" + source + ")"; + throw new TransformerConfigurationException (msg); + } + } + + /** + * Copy constructor. + */ + private GnomeTransformer (Object stylesheet, + URIResolver resolver, + ErrorListener errorListener, + Map parameters, + Properties outputProperties) + { + this.stylesheet = stylesheet; + this.resolver = resolver; + this.errorListener = errorListener; + this.parameters = parameters; + this.outputProperties = outputProperties; + } + + private native Object newStylesheet () + throws TransformerConfigurationException; + + private native Object newStylesheetFromStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler) + throws TransformerConfigurationException; + + private native Object newStylesheetFromDoc (GnomeDocument doc) + throws TransformerConfigurationException; + + //--- Implementation of javax.xml.transform.Transformer follows. + + // Set, get and clear the parameters to use on transformation + + public synchronized void setParameter (String parameter, Object value) + { + parameters.put (parameter, value); + } + + public synchronized Object getParameter (String name) + { + return parameters.get (name); + } + + public synchronized void clearParameters () + { + parameters.clear (); + } + + // Set and get the ErrorListener to use on transformation + + public void setErrorListener (ErrorListener listener) + { + this.errorListener = listener; + } + + public ErrorListener getErrorListener () + { + return errorListener; + } + + // Set and get the URIResolver to use on transformation + + public void setURIResolver (URIResolver resolver) + { + this.resolver = resolver; + } + + public URIResolver getURIResolver () + { + return resolver; + } + + // Set the output properties to use on transformation; get default + // output properties and output properties specified in the + // stylesheet or by the user. + + public void setOutputProperties (Properties outputProperties) + { + // Note: defensive copying + this.outputProperties = new Properties (outputProperties); + } + + public void setOutputProperty (String name, String value) + { + outputProperties.setProperty (name, value); + } + + public Properties getOutputProperties () + { + // Note: defensive copying + return new Properties (this.outputProperties); + } + + public String getOutputProperty (String name) + { + return outputProperties.getProperty (name); + } + + // -- Templates -- + + public Transformer newTransformer () + { + return new GnomeTransformer (stylesheet, resolver, errorListener, + new HashMap (parameters), + new Properties (outputProperties)); + } + + // -- transform -- + + /** + * Transforms the given source and writes the result to the + * given target. + */ + public void transform (Source source, Result result) + throws TransformerException + { + if (source instanceof StreamSource) + { + try + { + StreamSource ss = (StreamSource) source; + NamedInputStream in = XMLJ.getInputStream (ss); + String publicId = ss.getPublicId (); + String systemId = ss.getSystemId (); + String base = XMLJ.getBaseURI (systemId); + byte[] detectBuffer = in.getDetectBuffer (); + if (detectBuffer == null) + { + throw new TransformerException ("No document element"); + } + if (result instanceof StreamResult) + { + OutputStream out = XMLJ.getOutputStream ((StreamResult) result); + transformStreamToStream (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null), out); + } + else if (result instanceof DOMResult) + { + DOMResult dr = (DOMResult) result; + GnomeDocument ret = + transformStreamToDoc (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null)); + dr.setNode (ret); + dr.setSystemId (null); + } + else if (result instanceof SAXResult) + { + SAXResult sr = (SAXResult) result; + transformStreamToSAX (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null), + getSAXContext (sr)); + } + else + { + String msg = "Result type not supported (" + result + ")"; + throw new TransformerConfigurationException (msg); + } + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + else if (source instanceof DOMSource) + { + DOMSource ds = (DOMSource) source; + Node node = ds.getNode (); + if (!(node instanceof GnomeDocument)) + { + String msg = "Node is not a GnomeDocument (" + node + ")"; + throw new TransformerException (msg); + } + GnomeDocument doc = (GnomeDocument) node; + if (result instanceof StreamResult) + { + try + { + OutputStream out = XMLJ.getOutputStream ((StreamResult) result); + transformDocToStream (doc, out); + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + else if (result instanceof DOMResult) + { + DOMResult dr = (DOMResult) result; + GnomeDocument ret = transformDocToDoc (doc); + dr.setNode (ret); + dr.setSystemId (null); + } + else if (result instanceof SAXResult) + { + SAXResult sr = (SAXResult) result; + transformDocToSAX (doc, getSAXContext (sr)); + } + else + { + String msg = "Result type not supported"; + throw new TransformerConfigurationException (msg); + } + } + else + { + String msg = "Source type not supported"; + throw new TransformerConfigurationException (msg); + } + } + + private GnomeXMLReader getSAXContext (SAXResult result) + { + GnomeXMLReader ctx = new GnomeXMLReader (); + ctx.setContentHandler (result.getHandler ()); + ctx.setLexicalHandler (result.getLexicalHandler ()); + if (errorListener != null) + { + ErrorHandler errorHandler = + new ErrorListenerErrorHandler (errorListener); + ctx.setErrorHandler (errorHandler); + } + if (resolver != null) + { + EntityResolver entityResolver = + new URIResolverEntityResolver (resolver); + ctx.setEntityResolver (entityResolver); + } + return ctx; + } + + private native void transformStreamToStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler, + OutputStream out) + throws TransformerException; + + private native GnomeDocument transformStreamToDoc (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler) + throws TransformerException; + + private native void transformStreamToSAX (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler, + GnomeXMLReader out) + throws TransformerException; + + private native void transformDocToStream (GnomeDocument in, + OutputStream out) + throws TransformerException; + + private native GnomeDocument transformDocToDoc (GnomeDocument in) + throws TransformerException; + + private native void transformDocToSAX (GnomeDocument in, + GnomeXMLReader out) + throws TransformerException; + + /* + * Retrieve parameters as a string array. + * This is a convenience method called from native code. + */ + private String[] getParameterArray () + { + String[] parameterArray = new String[parameters.size () * 2]; + int index = 0; + for (Iterator it = parameters.keySet ().iterator (); + it.hasNext (); + ++index) + { + String parameterKey = (String) it.next (); + String parameterValue = (String) parameters.get (parameterKey); + parameterArray[index * 2 + 0] = parameterKey; + parameterArray[index * 2 + 1] = + "'" + ((parameterValue != null) ? parameterValue : "") + "'"; + // FIXME encode parameter value correctly for XPath + } + return parameterArray; + } + + // -- Free xsltStylesheet handle -- + + public void finalize () + { + if (stylesheet != null) + { + free (); + stylesheet = null; + } + } + + private native void free (); + + // -- Callbacks -- + + private InputStream resolveEntity (String publicId, String systemId) + throws TransformerException + { + if (resolver != null) + { + systemId = resolver.resolve (null, systemId).getSystemId (); + } + if (systemId == null) + { + return null; + } + try + { + URL url = new URL (systemId); + return XMLJ.getInputStream (url); + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + + private void setDocumentLocator (Object ctx, Object loc) + { + } + + private void warning (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.warning (new TransformerException (message, l)); + } + + private void error (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.error (new TransformerException (message, l)); + } + + private void fatalError (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.fatalError (new TransformerException (message, l)); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java new file mode 100755 index 000000000..4a0100a21 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java @@ -0,0 +1,349 @@ +/* GnomeTransformerFactory.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.transform; + +import java.io.InputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.URIResolver; + +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import gnu.xml.libxmlj.util.XMLJ; + +/** + * An implementation of TransformerFactory producing + * Transformer objects which use libxslt + * for transformation. + * + * @author Julian Scheid + * @author Chris Burdess + */ +public class GnomeTransformerFactory + extends TransformerFactory +{ + + static + { + XMLJ.init (); + } + + /** + * URIResolver set by user, or default implementation. + */ + private URIResolver uriResolver; + + /** + * ErrorListener set by user, or default implementation. + */ + private ErrorListener errorListener; + + /** + * Attributes set by user. + */ + private Map attributes = new HashMap (); + + //--- Implementation of javax.xml.transform.TransformerFactory + //--- follows. + + // -- begin getAssociatedStylesheet implementation -- + + /** + * Returns the stylesheet associated with the specified XML source, or + * null if no associated stylesheet could be found. + */ + public Source getAssociatedStylesheet(Source source, String media, + String title, String charset) + throws TransformerConfigurationException + { + String href= null; + String base = source.getSystemId(); + if (source instanceof DOMSource) + { + Node node = ((DOMSource) source).getNode(); + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) node : node.getOwnerDocument(); + if (base == null) + { + base = doc.getDocumentURI(); + } + for (node = doc.getFirstChild(); node != null; + node = node.getNextSibling()) + { + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && + "xml-stylesheet".equals(node.getNodeName())) + { + String data = node.getNodeValue(); + if (media != null && + !media.equals(parseParameter(data, "type"))) + { + continue; + } + if (title != null && + !title.equals(parseParameter(data, "title"))) + { + continue; + } + href = parseParameter(data, "href"); + } + } + } + else + { + InputSource input; + XMLReader parser = null; + try + { + if (source instanceof SAXSource) + { + SAXSource sax = (SAXSource) source; + input = sax.getInputSource(); + parser = sax.getXMLReader(); + } + else + { + StreamSource stream = (StreamSource) source; + InputStream in = stream.getInputStream(); + input = new InputSource(in); + } + input.setSystemId(base); + if (parser == null) + { + parser = createXMLReader(); + } + AssociatedStylesheetHandler ash = + new AssociatedStylesheetHandler(); + ash.media = media; + ash.title = title; + parser.setContentHandler(ash); + parser.parse(input); + href = ash.href; + } + catch (SAXException e) + { + throw new TransformerConfigurationException(e); + } + catch (IOException e) + { + throw new TransformerConfigurationException(e); + } + } + if (href == null) + { + return null; + } + if (base != null) + { + base = XMLJ.getBaseURI(base); + } + href = XMLJ.getAbsoluteURI(base, href); + return new StreamSource(href); + } + + private XMLReader createXMLReader() + throws TransformerConfigurationException + { + try + { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser parser = factory.newSAXParser(); + return parser.getXMLReader(); + } + catch (FactoryConfigurationError e) + { + throw new TransformerConfigurationException(e); + } + catch (ParserConfigurationException e) + { + throw new TransformerConfigurationException(e); + } + catch (SAXException e) + { + throw new TransformerConfigurationException(e); + } + } + + class AssociatedStylesheetHandler + extends DefaultHandler + { + + String media; + String title; + String href; + + public void processingInstruction(String target, String data) + throws SAXException + { + if ("xml-stylesheet".equals(target)) + { + if (media != null && !media.equals(parseParameter(data, "type"))) + { + return; + } + if (title != null && !title.equals(parseParameter(data, "title"))) + { + return; + } + href = parseParameter(data, "href"); + } + } + + } + + String parseParameter(String data, String name) + { + int start = data.indexOf(name + "="); + if (start != -1) + { + start += name.length() + 2; + char delim = data.charAt(start - 1); + int end = data.indexOf(delim, start); + if (end != -1) + { + return data.substring(start, end); + } + } + return null; + } + + // -- end getAssociatedStylesheet implementation -- + + public synchronized void setAttribute (String name, Object value) + { + this.attributes.put (name, value); + } + + public synchronized Object getAttribute (String name) + { + return attributes.get (name); + } + + public void setErrorListener (ErrorListener errorListener) + { + this.errorListener = errorListener; + } + + public ErrorListener getErrorListener () + { + return errorListener; + } + + public void setURIResolver (URIResolver uriResolver) + { + this.uriResolver = uriResolver; + } + + public URIResolver getURIResolver () + { + return uriResolver; + } + + public boolean getFeature (String name) + { + return (StreamSource.FEATURE.equals (name) || + StreamResult.FEATURE.equals (name) || + DOMSource.FEATURE.equals (name) || + DOMResult.FEATURE.equals (name)); + } + + public void setFeature(String name, boolean value) + throws TransformerConfigurationException + { + throw new TransformerConfigurationException(name); + } + + /** + * Returns a new instance of class {@link Transformer} for a + * null souce. + */ + public Transformer newTransformer () + throws TransformerConfigurationException + { + return newTransformer (null); + } + + /** + * Returns a new instance of class {@link Transformer} for + * the given souce. + */ + public Transformer newTransformer (Source source) + throws TransformerConfigurationException + { + return new GnomeTransformer (source, uriResolver, errorListener); + } + + /** + * Returns a new instance of class {@link Templates} for + * the given souce. + */ + public Templates newTemplates (Source source) + throws TransformerConfigurationException + { + return new GnomeTransformer (source, uriResolver, errorListener); + } + + /** + * Perform native cleanup. + */ + public static native void freeLibxsltGlobal (); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java new file mode 100644 index 000000000..0ce71d0ef --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java @@ -0,0 +1,87 @@ +/* URIResolverEntityResolver.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.transform; + +import java.io.IOException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.TransformerException; +import javax.xml.transform.sax.SAXSource; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Provides an EntityResolver interface to a URIResolver. + * + * @author Chris Burdess + */ +class URIResolverEntityResolver +implements EntityResolver +{ + + private URIResolver resolver; + + URIResolverEntityResolver (URIResolver resolver) + { + this.resolver = resolver; + } + + public InputSource resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + try + { + return SAXSource.sourceToInputSource (resolver.resolve (systemId, + null)); + } + catch (TransformerException e) + { + Throwable cause = e.getCause (); + if (cause instanceof SAXException) + { + throw (SAXException) cause; + } + else if (cause instanceof IOException) + { + throw (IOException) cause; + } + throw new SAXException (e); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/package.html b/libjava/classpath/gnu/xml/libxmlj/transform/package.html new file mode 100755 index 000000000..dac1027ff --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/package.html @@ -0,0 +1,14 @@ + +

+ A JAXP-compliant wrapper for the XSLT C library for Gnome, also + known as libxslt. Allows to use libxslt via the Java API for XML + processing. +

+ +

+ Usage: +

  • Set the system property javax.xml.transform.TransformerFactory + to gnu.xml.libxmlj.GnomeTransformerFactory.
  • + +

    + diff --git a/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java b/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java new file mode 100644 index 000000000..60019ddd4 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java @@ -0,0 +1,62 @@ +/* EmptyNodeList.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.util; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * An empty node list. + * + * @author Chris Burdess + */ +class EmptyNodeList +implements NodeList +{ + + public Node item (int index) + { + return null; + } + + public int getLength () + { + return 0; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java b/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java new file mode 100644 index 000000000..01b3af90d --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java @@ -0,0 +1,99 @@ +/* NamedInputStream.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.util; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PushbackInputStream; + +/** + * An input stream associated with an XML system ID. + * It can report the system ID and the first few bytes of the stream + * in order to detect the character encoding of the stream. + * + * @author Chris Burdess + */ +public class NamedInputStream +extends FilterInputStream +{ + + private static int DETECT_BUFFER_SIZE = 50; + + private String name; + + NamedInputStream (String name, InputStream in, int size) + { + super (new PushbackInputStream (in, size)); + this.name = name; + } + + /** + * Returns the name of the stream (the XML system ID). + */ + public String getName () + { + return name; + } + + /** + * Returns the first few bytes of the stream for character encoding + * purposes. The entire stream can thereafter be read normally from the + * beginning. This method is only valid if no bytes have yet been read + * from the stream. + */ + public byte[] getDetectBuffer () + throws IOException + { + PushbackInputStream p = (PushbackInputStream) in; + byte[] buffer = new byte[DETECT_BUFFER_SIZE]; + int len = p.read (buffer); + if (len < 0) + { + return null; + } + else + { + p.unread (buffer, 0, len); + byte[] ret = new byte[len]; + System.arraycopy (buffer, 0, ret, 0, len); + return ret; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java new file mode 100644 index 000000000..5c3316611 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java @@ -0,0 +1,294 @@ +/* StandaloneDocumentType.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.util; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; + +/** + * A "standalone" document type, i.e. one that isn't attached to a document + * node. + * This can be used to create new documents. + */ +public final class StandaloneDocumentType +implements DocumentType +{ + + private final String name; + private final String publicId; + private final String systemId; + + public StandaloneDocumentType (String name, String publicId, String systemId) + { + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public String getName () + { + return name; + } + + public NamedNodeMap getEntities () + { + // TODO + return null; + } + + public NamedNodeMap getNotations () + { + // TODO + return null; + } + + public String getPublicId () + { + return publicId; + } + + public String getSystemId () + { + return systemId; + } + + public String getInternalSubset () + { + return null; + } + + // -- Node -- + + public String getNodeName () + { + return getName (); + } + + public String getNodeValue () + throws DOMException + { + return null; + } + + public void setNodeValue (String nodeValue) + throws DOMException + { + } + + public short getNodeType () + { + return DOCUMENT_TYPE_NODE; + } + + public Node getParentNode () + { + return null; + } + + public NodeList getChildNodes () + { + return new EmptyNodeList (); + } + + public Node getFirstChild () + { + return null; + } + + public Node getLastChild () + { + return null; + } + + public Node getPreviousSibling () + { + return null; + } + + public Node getNextSibling () + { + return null; + } + + public NamedNodeMap getAttributes () + { + return null; + } + + public Document getOwnerDocument () + { + return null; + } + + public Node insertBefore (Node newChild, Node refChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node replaceChild (Node newChild, Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node removeChild (Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node appendChild (Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public boolean hasChildNodes () + { + return false; + } + + public Node cloneNode (boolean deep) + { + return new StandaloneDocumentType (name, publicId, systemId); + } + + public void normalize () + { + } + + public boolean isSupported (String feature, String version) + { + return false; + } + + public String getNamespaceURI () + { + return null; + } + + public String getPrefix () + { + return null; + } + + public void setPrefix (String prefix) + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public String getLocalName () + { + return getName (); + } + + public boolean hasAttributes () + { + return false; + } + + // DOM Level 3 + + public String getBaseURI () + { + return null; + } + + public short compareDocumentPosition (Node node) + { + return -1; + } + + public String getTextContent () + { + return null; + } + + public void setTextContent (String content) + { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public boolean isSameNode (Node other) + { + return equals (other); + } + + public String lookupPrefix (String namespace) + { + return null; + } + + public boolean isDefaultNamespace (String namespace) + { + return false; + } + + public String lookupNamespaceURI (String prefix) + { + return null; + } + + public boolean isEqualNode (Node other) + { + return equals (other); + } + + public Object getFeature (String feature, String version) + { + return null; + } + + public Object setUserData (String name, Object value, + UserDataHandler handler) + { + return null; + } + + public Object getUserData (String name) + { + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java new file mode 100644 index 000000000..75b40bdf1 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java @@ -0,0 +1,89 @@ +/* StandaloneLocator.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.util; + +import javax.xml.transform.SourceLocator; +import org.xml.sax.Locator; + +/** + * SAX Locator implementation that uses the specified values. + * + * @author Chris Burdess + */ +public final class StandaloneLocator +implements Locator, SourceLocator +{ + + private final int lineNumber; + + private final int columnNumber; + + private final String publicId; + + private final String systemId; + + public StandaloneLocator (int lineNumber, int columnNumber, + String publicId, String systemId) + { + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.publicId = publicId; + this.systemId = systemId; + } + + public String getPublicId () + { + return publicId; + } + + public String getSystemId () + { + return systemId; + } + + public int getLineNumber () + { + return lineNumber; + } + + public int getColumnNumber () + { + return columnNumber; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java b/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java new file mode 100644 index 000000000..8d954d0be --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java @@ -0,0 +1,280 @@ +/* XMLJ.java - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.libxmlj.util; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.InputSource; + +import gnu.xml.libxmlj.transform.GnomeTransformerFactory; + +import gnu.xml.dom.ls.ReaderInputStream; +import gnu.xml.dom.ls.WriterOutputStream; + +/** + * Utility functions for libxmlj. + */ +public final class XMLJ +{ + + static class XMLJShutdownHook + implements Runnable + { + + public void run () + { + // Make sure finalizers are run + System.gc (); + Runtime.getRuntime ().runFinalization (); + + // Perform global cleanup on the native level + GnomeTransformerFactory.freeLibxsltGlobal (); + } + + } + + private static boolean initialised = false; + + public static void init () + { + if (!initialised) + { + System.loadLibrary ("xmlj"); + + XMLJShutdownHook hook = new XMLJShutdownHook (); + Runtime.getRuntime ().addShutdownHook (new Thread (hook)); + } + initialised = true; + } + + private static final int LOOKAHEAD = 50; + + /** + * Returns an input stream for the specified input source. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (InputSource input) + throws IOException + { + InputStream in = input.getByteStream (); + String systemId = input.getSystemId (); + if (in == null) + { + Reader r = input.getCharacterStream(); + if (r != null) + in = new ReaderInputStream(r); + } + if (in == null) + { + in = getInputStream(systemId); + } + return new NamedInputStream (systemId, in, LOOKAHEAD); + } + + /** + * Returns an input stream for the specified transformer source. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (Source source) + throws IOException + { + if (source instanceof SAXSource) + { + return getInputStream (((SAXSource) source).getInputSource ()); + } + InputStream in = null; + String systemId = source.getSystemId (); + if (source instanceof StreamSource) + { + in = ((StreamSource) source).getInputStream (); + } + if (in == null) + { + in = getInputStream(systemId); + } + return new NamedInputStream (systemId, in, LOOKAHEAD); + } + + private static InputStream getInputStream(String systemId) + throws IOException + { + if (systemId == null) + { + throw new IOException("no system ID"); + } + try + { + return new URL(systemId).openStream(); + } + catch (MalformedURLException e) + { + return new FileInputStream(systemId); + } + } + + /** + * Returns an input stream for the specified URL. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (URL url) + throws IOException + { + return new NamedInputStream (url.toString (), url.openStream(), + LOOKAHEAD); + } + + /** + * Convenience method for xmljDocLoader + */ + static NamedInputStream xmljGetInputStream(String base, String url) + throws IOException + { + try + { + if (base != null) + { + url = new URL(new URL(base), url).toString(); + } + } + catch (MalformedURLException e) + { + } + InputStream in = getInputStream(url); + return new NamedInputStream(url, in, LOOKAHEAD); + } + + /** + * Returns an output stream for the specified transformer result. + */ + public static OutputStream getOutputStream (Result result) + throws IOException + { + OutputStream out = null; + if (result instanceof StreamResult) + { + out = ((StreamResult) result).getOutputStream (); + } + if (out == null) + { + Writer w = ((StreamResult) result).getWriter (); + if (w != null) + out = new WriterOutputStream (w); + } + if (out == null) + { + String systemId = result.getSystemId (); + if (systemId == null) + { + throw new IOException ("no system ID"); + } + try + { + URL url = new URL (systemId); + URLConnection connection = url.openConnection (); + connection.setDoOutput (true); + out = connection.getOutputStream (); + } + catch (MalformedURLException e) + { + out = new FileOutputStream (systemId); + } + } + + return out; + } + + /** + * Returns the absolute form of the specified URI. + * If the URI is already absolute, returns it as-is. + * Otherwise returns a new URI relative to the given base URI. + */ + public static String getAbsoluteURI (String base, String uri) + { + if (uri != null && + base != null && + (uri.length() > 0) && + (uri.indexOf(':') == -1) && + (uri.charAt(0) != '/')) + { + // URI is relative + if (base.charAt(base.length() - 1) != '/') + { + int i = base.lastIndexOf('/'); + base = base.substring(0, i + 1); + } + return base + uri; + } + else + { + // URI is absolute or no base specified + return uri; + } + } + + public static String getBaseURI(String uri) + { + if (uri != null) + { + int si = uri.lastIndexOf('/'); + if (si != -1) + { + uri = uri.substring(0, si + 1); + } + } + return uri; + } + +} diff --git a/libjava/classpath/gnu/xml/pipeline/CallFilter.java b/libjava/classpath/gnu/xml/pipeline/CallFilter.java new file mode 100644 index 000000000..2398b8685 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/CallFilter.java @@ -0,0 +1,257 @@ +/* CallFilter.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.net.URLConnection; +import java.io.Writer; + +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import gnu.xml.util.Resolver; +import gnu.xml.util.XMLWriter; + + +/** + * Input is sent as an XML request to given URI, and the output of this + * filter is the parsed response to that request. + * A connection is opened to the remote URI when the startDocument call is + * issued through this filter, and the request is finished when the + * endDocument call is issued. Events should be written quickly enough to + * prevent the remote HTTP server from aborting the connection due to + * inactivity; you may want to buffer text in an earlier pipeline stage. + * If your application requires validity checking of such + * outputs, have the output pipeline include a validation stage. + * + *

    In effect, this makes a remote procedure call to the URI, with the + * request and response document syntax as chosen by the application. + * Note that all the input events must be seen, and sent to the URI, + * before the first output event can be seen. Clients are delayed + * at least by waiting for the server to respond, constraining concurrency. + * Services can thus be used to synchronize concurrent activities, and + * even to prioritize service among different clients. + * + *

    You are advised to avoid restricting yourself to an "RPC" model + * for distributed computation. With a World Wide Web, network latencies + * and failures (e.g. non-availability) + * are significant; adopting a "procedure" model, rather than a workflow + * model where bulk requests are sent and worked on asynchronously, is not + * generally an optimal system-wide architecture. When the messages may + * need authentication, such as with an OpenPGP signature, or when server + * loads don't argue in favor of immediate responses, non-RPC models can + * be advantageous. (So-called "peer to peer" computing models are one + * additional type of model, though too often that term is applied to + * systems that still have a centralized control structure.) + * + *

    Be strict in what you send, liberal in what you accept, as + * the Internet tradition goes. Strictly conformant data should never cause + * problems to its receiver; make your request pipeline be very strict, and + * don't compromise on that. Make your response pipeline strict as well, + * but be ready to tolerate specific mild, temporary, and well-documented + * variations from specific communications peers. + * + * @see XmlServlet + * + * @author David Brownell + */ +final public class CallFilter implements EventConsumer +{ + private Requestor req; + private EventConsumer next; + private URL target; + private URLConnection conn; + private ErrorHandler errHandler; + + + /** + * Initializes a call filter so that its inputs are sent to the + * specified URI, and its outputs are sent to the next consumer + * provided. + * + * @exception IOException if the URI isn't accepted as a URL + */ + // constructor used by PipelineFactory + public CallFilter (String uri, EventConsumer next) + throws IOException + { + this.next = next; + req = new Requestor (); + setCallTarget (uri); + } + + /** + * Assigns the URI of the call target to be used. + * Does not affect calls currently being made. + */ + final public void setCallTarget (String uri) + throws IOException + { + target = new URL (uri); + } + + /** + * Assigns the error handler to be used to present most fatal + * errors. + */ + public void setErrorHandler (ErrorHandler handler) + { + req.setErrorHandler (handler); + } + + + /** + * Returns the call target's URI. + */ + final public String getCallTarget () + { + return target.toString (); + } + + /** Returns the content handler currently in use. */ + final public org.xml.sax.ContentHandler getContentHandler () + { + return req; + } + + /** Returns the DTD handler currently in use. */ + final public DTDHandler getDTDHandler () + { + return req; + } + + + /** + * Returns the declaration or lexical handler currently in + * use, or throws an exception for other properties. + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (EventFilter.DECL_HANDLER.equals (id)) + return req; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return req; + throw new SAXNotRecognizedException (id); + } + + + // JDK 1.1 seems to need it to be done this way, sigh + ErrorHandler getErrorHandler () { return errHandler; } + + // + // Takes input and echoes to server as POST input. + // Then sends the POST reply to the next pipeline element. + // + final class Requestor extends XMLWriter + { + Requestor () + { + super ((Writer)null); + } + + public synchronized void startDocument () throws SAXException + { + // Connect to remote object and set up to send it XML text + try { + if (conn != null) + throw new IllegalStateException ("call is being made"); + + conn = target.openConnection (); + conn.setDoOutput (true); + conn.setRequestProperty ("Content-Type", + "application/xml;charset=UTF-8"); + + setWriter (new OutputStreamWriter ( + conn.getOutputStream (), + "UTF8"), "UTF-8"); + + } catch (IOException e) { + fatal ("can't write (POST) to URI: " + target, e); + } + + // NOW base class can safely write that text! + super.startDocument (); + } + + public void endDocument () throws SAXException + { + // + // Finish writing the request (for HTTP, a POST); + // this closes the output stream. + // + super.endDocument (); + + // + // Receive the response. + // Produce events for the next stage. + // + InputSource source; + XMLReader producer; + String encoding; + + try { + + source = new InputSource (conn.getInputStream ()); + +// FIXME if status is anything but success, report it!! It'd be good to +// save the request data just in case we need to deal with a forward. + + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding != null) + source.setEncoding (encoding); + + producer = XMLReaderFactory.createXMLReader (); + producer.setErrorHandler (getErrorHandler ()); + EventFilter.bind (producer, next); + producer.parse (source); + conn = null; + + } catch (IOException e) { + fatal ("I/O Exception reading response, " + e.getMessage (), e); + } + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/DomConsumer.java b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java new file mode 100644 index 000000000..141f36eca --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java @@ -0,0 +1,967 @@ +/* DomConsumer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import gnu.xml.util.DomParser; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + * This consumer builds a DOM Document from its input, acting either as a + * pipeline terminus or as an intermediate buffer. When a document's worth + * of events has been delivered to this consumer, that document is read with + * a {@link DomParser} and sent to the next consumer. It is also available + * as a read-once property. + * + *

    The DOM tree is constructed as faithfully as possible. There are some + * complications since a DOM should expose behaviors that can't be implemented + * without API backdoors into that DOM, and because some SAX parsers don't + * report all the information that DOM permits to be exposed. The general + * problem areas involve information from the Document Type Declaration (DTD). + * DOM only represents a limited subset, but has some behaviors that depend + * on much deeper knowledge of a document's DTD. You shouldn't have much to + * worry about unless you change handling of "noise" nodes from its default + * setting (which ignores them all); note if you use JAXP to populate your + * DOM trees, it wants to save "noise" nodes by default. (Such nodes include + * ignorable whitespace, comments, entity references and CDATA boundaries.) + * Otherwise, your + * main worry will be if you use a SAX parser that doesn't flag ignorable + * whitespace unless it's validating (few don't). + * + *

    The SAX2 events used as input must contain XML Names for elements + * and attributes, with original prefixes. In SAX2, + * this is optional unless the "namespace-prefixes" parser feature is set. + * Moreover, many application components won't provide completely correct + * structures anyway. Before you convert a DOM to an output document, + * you should plan to postprocess it to create or repair such namespace + * information. The {@link NSFilter} pipeline stage does such work. + * + *

    Note: changes late in DOM L2 process made it impractical to + * attempt to create the DocumentType node in any implementation-neutral way, + * much less to populate it (L1 didn't support even creating such nodes). + * To create and populate such a node, subclass the inner + * {@link DomConsumer.Handler} class and teach it about the backdoors into + * whatever DOM implementation you want. It's possible that some revised + * DOM API (L3?) will make this problem solvable again. + * + * @see DomParser + * + * @author David Brownell + */ +public class DomConsumer implements EventConsumer +{ + private Class domImpl; + + private boolean hidingCDATA = true; + private boolean hidingComments = true; + private boolean hidingWhitespace = true; + private boolean hidingReferences = true; + + private Handler handler; + private ErrorHandler errHandler; + + private EventConsumer next; + + // FIXME: this can't be a generic pipeline stage just now, + // since its input became a Class not a String (to be turned + // into a class, using the right class loader) + + + /** + * Configures this pipeline terminus to use the specified implementation + * of DOM when constructing its result value. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified implementation + */ + public DomConsumer (Class impl) + throws SAXException + { + domImpl = impl; + handler = new Handler (this); + } + + /** + * This is the hook through which a subclass provides a handler + * which knows how to access DOM extensions, specific to some + * implementation, to record additional data in a DOM. + * Treat this as part of construction; don't call it except + * before (or between) parses. + */ + protected void setHandler (Handler h) + { + handler = h; + } + + + private Document emptyDocument () + throws SAXException + { + try { + return (Document) domImpl.newInstance (); + } catch (IllegalAccessException e) { + throw new SAXException ("can't access constructor: " + + e.getMessage ()); + } catch (InstantiationException e) { + throw new SAXException ("can't instantiate Document: " + + e.getMessage ()); + } + } + + + /** + * Configures this consumer as a buffer/filter, using the specified + * DOM implementation when constructing its result value. + * + *

    This event consumer acts as a buffer and filter, in that it + * builds a DOM tree and then writes it out when endDocument + * is invoked. Because of the limitations of DOM, much information + * will as a rule not be seen in that replay. To get a full fidelity + * copy of the input event stream, use a {@link TeeConsumer}. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * @param next receives a "replayed" sequence of parse events when + * the endDocument method is invoked. + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified DOM implementation + */ + public DomConsumer (Class impl, EventConsumer n) + throws SAXException + { + this (impl); + next = n; + } + + + /** + * Returns the document constructed from the preceding + * sequence of events. This method should not be + * used again until another sequence of events has been + * given to this EventConsumer. + */ + final public Document getDocument () + { + return handler.clearDocument (); + } + + public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + } + + + /** + * Returns true if the consumer is hiding entity references nodes + * (the default), and false if EntityReference nodes should + * instead be created. Such EntityReference nodes will normally be + * empty, unless an implementation arranges to populate them and then + * turn them back into readonly objects. + * + * @see #setHidingReferences + */ + final public boolean isHidingReferences () + { return hidingReferences; } + + /** + * Controls whether the consumer will hide entity expansions, + * or will instead mark them with entity reference nodes. + * + * @see #isHidingReferences + * @param flag False if entity reference nodes will appear + */ + final public void setHidingReferences (boolean flag) + { hidingReferences = flag; } + + + /** + * Returns true if the consumer is hiding comments (the default), + * and false if they should be placed into the output document. + * + * @see #setHidingComments + */ + public final boolean isHidingComments () + { return hidingComments; } + + /** + * Controls whether the consumer is hiding comments. + * + * @see #isHidingComments + */ + public final void setHidingComments (boolean flag) + { hidingComments = flag; } + + + /** + * Returns true if the consumer is hiding ignorable whitespace + * (the default), and false if such whitespace should be placed + * into the output document as children of element nodes. + * + * @see #setHidingWhitespace + */ + public final boolean isHidingWhitespace () + { return hidingWhitespace; } + + /** + * Controls whether the consumer hides ignorable whitespace + * + * @see #isHidingComments + */ + public final void setHidingWhitespace (boolean flag) + { hidingWhitespace = flag; } + + + /** + * Returns true if the consumer is saving CDATA boundaries, or + * false (the default) otherwise. + * + * @see #setHidingCDATA + */ + final public boolean isHidingCDATA () + { return hidingCDATA; } + + /** + * Controls whether the consumer will save CDATA boundaries. + * + * @see #isHidingCDATA + * @param flag True to treat CDATA text differently from other + * text nodes + */ + final public void setHidingCDATA (boolean flag) + { hidingCDATA = flag; } + + + + /** Returns the document handler being used. */ + final public ContentHandler getContentHandler () + { return handler; } + + /** Returns the DTD handler being used. */ + final public DTDHandler getDTDHandler () + { return handler; } + + /** + * Returns the lexical handler being used. + * (DOM construction can't really use declaration handlers.) + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if ("http://xml.org/sax/properties/lexical-handler".equals (id)) + return handler; + if ("http://xml.org/sax/properties/declaration-handler".equals (id)) + return handler; + throw new SAXNotRecognizedException (id); + } + + EventConsumer getNext () { return next; } + + ErrorHandler getErrorHandler () { return errHandler; } + + /** + * Class used to intercept various parsing events and use them to + * populate a DOM document. Subclasses would typically know and use + * backdoors into specific DOM implementations, used to implement + * DTD-related functionality. + * + *

    Note that if this ever throws a DOMException (runtime exception) + * that will indicate a bug in the DOM (e.g. doesn't support something + * per specification) or the parser (e.g. emitted an illegal name, or + * accepted illegal input data).

    + */ + public static class Handler + implements ContentHandler, LexicalHandler, + DTDHandler, DeclHandler + { + protected DomConsumer consumer; + + private DOMImplementation impl; + private Document document; + private boolean isL2; + + private Locator locator; + private Node top; + private boolean inCDATA; + private boolean mergeCDATA; + private boolean inDTD; + private String currentEntity; + + private boolean recreatedAttrs; + private AttributesImpl attributes = new AttributesImpl (); + + /** + * Subclasses may use SAX2 events to provide additional + * behaviors in the resulting DOM. + */ + protected Handler (DomConsumer consumer) + throws SAXException + { + this.consumer = consumer; + document = consumer.emptyDocument (); + impl = document.getImplementation (); + isL2 = impl.hasFeature ("XML", "2.0"); + } + + private void fatal (String message, Exception x) + throws SAXException + { + SAXParseException e; + ErrorHandler errHandler = consumer.getErrorHandler (); + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1, x); + else + e = new SAXParseException (message, locator, x); + if (errHandler != null) + errHandler.fatalError (e); + throw e; + } + + /** + * Returns and forgets the document produced. If the handler is + * reused, a new document may be created. + */ + Document clearDocument () + { + Document retval = document; + document = null; + locator = null; + return retval; + } + + /** + * Returns the document under construction. + */ + protected Document getDocument () + { return document; } + + /** + * Returns the current node being populated. This is usually + * an Element or Document, but it might be an EntityReference + * node if some implementation-specific code knows how to put + * those into the result tree and later mark them as readonly. + */ + protected Node getTop () + { return top; } + + + // SAX1 + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + } + + // SAX1 + public void startDocument () + throws SAXException + { + if (document == null) + try { + if (isL2) { + // couple to original implementation + document = impl.createDocument (null, "foo", null); + document.removeChild (document.getFirstChild ()); + } else { + document = consumer.emptyDocument (); + } + } catch (Exception e) { + fatal ("DOM create document", e); + } + top = document; + } + + // SAX1 + public void endDocument () + throws SAXException + { + try { + if (consumer.getNext () != null && document != null) { + DomParser parser = new DomParser (document); + + EventFilter.bind (parser, consumer.getNext ()); + parser.parse ("ignored"); + } + } finally { + top = null; + } + } + + // SAX1 + public void processingInstruction (String target, String data) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + ProcessingInstruction pi; + + if (isL2 + // && consumer.isUsingNamespaces () + && target.indexOf (':') != -1) + namespaceError ( + "PI target name is namespace nonconformant: " + + target); + if (inDTD) + return; + pi = document.createProcessingInstruction (target, data); + top.appendChild (pi); + } + + /** + * Subclasses may overrride this method to provide a more efficient + * way to construct text nodes. + * Typically, copying the text into a single character array will + * be more efficient than doing that as well as allocating other + * needed for a String, including an internal StringBuffer. + * Those additional memory and CPU costs can be incurred later, + * if ever needed. + * Unfortunately the standard DOM factory APIs encourage those costs + * to be incurred early. + */ + protected Text createText ( + boolean isCDATA, + char ch [], + int start, + int length + ) { + String value = new String (ch, start, length); + + if (isCDATA) + return document.createCDATASection (value); + else + return document.createTextNode (value); + } + + // SAX1 + public void characters (char ch [], int start, int length) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly + // at creation time) + if (currentEntity != null) + return; + + Node lastChild = top.getLastChild (); + + // merge consecutive text or CDATA nodes if appropriate. + if (lastChild instanceof Text) { + if (consumer.isHidingCDATA () + // consecutive Text content ... always merge + || (!inCDATA + && !(lastChild instanceof CDATASection)) + // consecutive CDATASection content ... don't + // merge between sections, only within them + || (inCDATA && mergeCDATA + && lastChild instanceof CDATASection) + ) { + CharacterData last = (CharacterData) lastChild; + String value = new String (ch, start, length); + + last.appendData (value); + return; + } + } + if (inCDATA && !consumer.isHidingCDATA ()) { + top.appendChild (createText (true, ch, start, length)); + mergeCDATA = true; + } else + top.appendChild (createText (false, ch, start, length)); + } + + // SAX2 + public void skippedEntity (String name) + throws SAXException + { + // this callback is useless except to report errors, since + // we can't know if the ref was in content, within an + // attribute, within a declaration ... only one of those + // cases supports more intelligent action than a panic. + fatal ("skipped entity: " + name, null); + } + + // SAX2 + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + // reconstruct "xmlns" attributes deleted by all + // SAX2 parsers without "namespace-prefixes" = true + if ("".equals (prefix)) + attributes.addAttribute ("", "", "xmlns", + "CDATA", uri); + else + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", uri); + recreatedAttrs = true; + } + + // SAX2 + public void endPrefixMapping (String prefix) + throws SAXException + { } + + // SAX2 + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + // parser discarded basic information; DOM tree isn't writable + // without massaging to assign prefixes to all nodes. + // the "NSFilter" class does that massaging. + if (qName.length () == 0) + qName = localName; + + + Element element; + int length = atts.getLength (); + + if (!isL2) { + element = document.createElement (qName); + + // first the explicit attributes ... + length = atts.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (atts.getQName (i), + atts.getValue (i)); + // ... then any recreated ones (DOM deletes duplicates) + if (recreatedAttrs) { + recreatedAttrs = false; + length = attributes.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (attributes.getQName (i), + attributes.getValue (i)); + attributes.clear (); + } + + top.appendChild (element); + top = element; + return; + } + + // For an L2 DOM when namespace use is enabled, use + // createElementNS/createAttributeNS except when + // (a) it's an element in the default namespace, or + // (b) it's an attribute with no prefix + String namespace; + + if (localName.length () != 0) + namespace = (uri.length () == 0) ? null : uri; + else + namespace = getNamespace (getPrefix (qName), atts); + + if (namespace == null) + element = document.createElement (qName); + else + element = document.createElementNS (namespace, qName); + + populateAttributes (element, atts); + if (recreatedAttrs) { + recreatedAttrs = false; + // ... DOM deletes any duplicates + populateAttributes (element, attributes); + attributes.clear (); + } + + top.appendChild (element); + top = element; + } + + final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + private void populateAttributes (Element element, Attributes attrs) + throws SAXParseException + { + int length = attrs.getLength (); + + for (int i = 0; i < length; i++) { + String type = attrs.getType (i); + String value = attrs.getValue (i); + String name = attrs.getQName (i); + String local = attrs.getLocalName (i); + String uri = attrs.getURI (i); + + // parser discarded basic information, DOM tree isn't writable + if (name.length () == 0) + name = local; + + // all attribute types other than these three may not + // contain scoped names... enumerated attributes get + // reported as NMTOKEN, except for NOTATION values + if (!("CDATA".equals (type) + || "NMTOKEN".equals (type) + || "NMTOKENS".equals (type))) { + if (value.indexOf (':') != -1) { + namespaceError ( + "namespace nonconformant attribute value: " + + "<" + element.getNodeName () + + " " + name + "='" + value + "' ...>"); + } + } + + // xmlns="" is legal (undoes default NS) + // xmlns:foo="" is illegal + String prefix = getPrefix (name); + String namespace; + + if ("xmlns".equals (prefix)) { + if ("".equals (value)) + namespaceError ("illegal null namespace decl, " + name); + namespace = xmlnsURI; + } else if ("xmlns".equals (name)) + namespace = xmlnsURI; + + else if (prefix == null) + namespace = null; + else if (!"".equals(uri) && uri.length () != 0) + namespace = uri; + else + namespace = getNamespace (prefix, attrs); + + if (namespace == null) + element.setAttribute (name, value); + else + element.setAttributeNS (namespace, name, value); + } + } + + private String getPrefix (String name) + { + int temp; + + if ((temp = name.indexOf (':')) > 0) + return name.substring (0, temp); + return null; + } + + // used with SAX1-level parser output + private String getNamespace (String prefix, Attributes attrs) + throws SAXParseException + { + String namespace; + String decl; + + // defaulting + if (prefix == null) { + decl = "xmlns"; + namespace = attrs.getValue (decl); + if ("".equals (namespace)) + return null; + else if (namespace != null) + return namespace; + + // "xmlns" is like a keyword + // ... according to the Namespace REC, but DOM L2 CR2+ + // and Infoset violate that by assigning a namespace. + // that conflict is resolved elsewhere. + } else if ("xmlns".equals (prefix)) + return null; + + // "xml" prefix is fixed + else if ("xml".equals (prefix)) + return "http://www.w3.org/XML/1998/namespace"; + + // otherwise, expect a declaration + else { + decl = "xmlns:" + prefix; + namespace = attrs.getValue (decl); + } + + // if we found a local declaration, great + if (namespace != null) + return namespace; + + + // ELSE ... search up the tree we've been building + for (Node n = top; + n != null && n.getNodeType () != Node.DOCUMENT_NODE; + n = n.getParentNode ()) { + if (n.getNodeType () == Node.ENTITY_REFERENCE_NODE) + continue; + Element e = (Element) n; + Attr attr = e.getAttributeNode (decl); + if (attr != null) + return attr.getNodeValue (); + } + // see above re "xmlns" as keyword + if ("xmlns".equals (decl)) + return null; + + namespaceError ("Undeclared namespace prefix: " + prefix); + return null; + } + + // SAX2 + public void endElement (String uri, String localName, String qName) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + top = top.getParentNode (); + } + + // SAX1 (mandatory reporting if validating) + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (consumer.isHidingWhitespace ()) + return; + characters (ch, start, length); + } + + // SAX2 lexical event + public void startCDATA () + throws SAXException + { + inCDATA = true; + // true except for the first fragment of a cdata section + mergeCDATA = false; + } + + // SAX2 lexical event + public void endCDATA () + throws SAXException + { + inCDATA = false; + } + + // SAX2 lexical event + // + // this SAX2 callback merges two unrelated things: + // - Declaration of the root element type ... belongs with + // the other DTD declaration methods, NOT HERE. + // - IDs for the optional external subset ... belongs here + // with other lexical information. + // + // ...and it doesn't include the internal DTD subset, desired + // both to support DOM L2 and to enable "pass through" processing + // + public void startDTD (String name, String publicId, String SystemId) + throws SAXException + { + // need to filter out comments and PIs within the DTD + inDTD = true; + } + + // SAX2 lexical event + public void endDTD () + throws SAXException + { + inDTD = false; + } + + // SAX2 lexical event + public void comment (char ch [], int start, int length) + throws SAXException + { + Node comment; + + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (consumer.isHidingComments () + || inDTD + || currentEntity != null) + return; + comment = document.createComment (new String (ch, start, length)); + top.appendChild (comment); + } + + /** + * May be overridden by subclasses to return true, indicating + * that entity reference nodes can be populated and then made + * read-only. + */ + public boolean canPopulateEntityRefs () + { return false; } + + // SAX2 lexical event + public void startEntity (String name) + throws SAXException + { + // are we ignoring what would be contents of an + // entity ref, since we can't populate it? + if (currentEntity != null) + return; + + // Are we hiding all entity boundaries? + if (consumer.isHidingReferences ()) + return; + + // SAX2 shows parameter entities; DOM hides them + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + + // Since we can't create a populated entity ref node in any + // standard way, we create an unpopulated one. + EntityReference ref = document.createEntityReference (name); + top.appendChild (ref); + top = ref; + + // ... allowing subclasses to populate them + if (!canPopulateEntityRefs ()) + currentEntity = name; + } + + // SAX2 lexical event + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + if (name.equals (currentEntity)) + currentEntity = null; + if (!consumer.isHidingReferences ()) + top = top.getParentNode (); + } + + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String SystemId, + String notationName + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void elementDecl (String name, String model) + throws SAXException + { + /* IGNORE -- no content model support in DOM L2 */ + } + + // SAX2 declaration event + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + /* IGNORE -- no attribute model support in DOM L2 */ + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // + // These really should offer the option of nonfatal handling, + // like other validity errors, though that would cause major + // chaos in the DOM data structures. DOM is already spec'd + // to treat many of these as fatal, so this is consistent. + // + private void namespaceError (String description) + throws SAXParseException + { + SAXParseException err; + + err = new SAXParseException (description, locator); + throw err; + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventConsumer.java b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java new file mode 100644 index 000000000..a0a8824f7 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java @@ -0,0 +1,95 @@ +/* EventConsumer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import org.xml.sax.*; + + +/** + * Collects the event consumption apparatus of a SAX pipeline stage. + * Consumers which permit some handlers or other characteristics to be + * configured will provide methods to support that configuration. + * + *

    Two important categories of consumers include filters, which + * process events and pass them on to other consumers, and terminus + * (or terminal) stages, which don't pass events on. Filters are not + * necessarily derived from the {@link EventFilter} class, although that + * class can substantially simplify their construction by automating the + * most common activities. + * + *

    Event consumers which follow certain conventions for the signatures + * of their constructors can be automatically assembled into pipelines + * by the {@link PipelineFactory} class. + * + * @author David Brownell + */ +public interface EventConsumer +{ + /** Most stages process these core SAX callbacks. */ + public ContentHandler getContentHandler (); + + /** Few stages will use unparsed entities. */ + public DTDHandler getDTDHandler (); + + /** + * This method works like the SAX2 XMLReader method of the same name, + * and is used to retrieve the optional lexical and declaration handlers + * in a pipeline. + * + * @param id This is a URI identifying the type of property desired. + * @return The value of that property, if it is defined. + * + * @exception SAXNotRecognizedException Thrown if the particular + * pipeline stage does not understand the specified identifier. + */ + public Object getProperty (String id) + throws SAXNotRecognizedException; + + /** + * This method provides a filter stage with a handler that abstracts + * presentation of warnings and both recoverable and fatal errors. + * Most pipeline stages should share a single policy and mechanism + * for such reports, since application components require consistency + * in such activities. Accordingly, typical responses to this method + * invocation involve saving the handler for use; filters will pass + * it on to any other consumers they use. + * + * @param handler encapsulates error handling policy for this stage + */ + public void setErrorHandler (ErrorHandler handler); +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventFilter.java b/libjava/classpath/gnu/xml/pipeline/EventFilter.java new file mode 100644 index 000000000..b3cc2d654 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventFilter.java @@ -0,0 +1,796 @@ +/* EventFilter.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * A customizable event consumer, used to assemble various kinds of filters + * using SAX handlers and an optional second consumer. It can be constructed + * in two ways:

    + * + *

    Additionally, SAX handlers may be assigned, which completely replace + * the "upstream" view (through {@link EventConsumer}) of handlers, initially + * null or the "next" consumer provided to the constructor. To make + * it easier to build specialized filter classes, this class implements + * all the standard SAX consumer handlers, and those implementations + * delegate "downstream" to the consumer accessed by {@link #getNext}. + * + *

    The simplest way to create a custom a filter class is to create a + * subclass which overrides one or more handler interface methods. The + * constructor for that subclass then registers itself as a handler for + * those interfaces using a call such as setContentHandler(this), + * so the "upstream" view of event delivery is modified from the state + * established in the base class constructor. That way, + * the overridden methods intercept those event callbacks + * as they go "downstream", and + * all other event callbacks will pass events to any next consumer. + * Overridden methods may invoke superclass methods (perhaps after modifying + * parameters) if they wish to delegate such calls. Such subclasses + * should use {@link #getErrorHandler} to report errors using the + * common error reporting mechanism. + * + *

    Another important technique is to construct a filter consisting + * of only a few specific types of handler. For example, one could easily + * prune out lexical events or various declarations by providing handlers + * which don't pass those events downstream, or by providing null handlers. + * + *


    + * + *

    This may be viewed as the consumer oriented analogue of the SAX2 + * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class. + * Key differences include:

    + * + *

    The {@link #chainTo chainTo()} convenience routine supports chaining to + * an XMLFilterImpl, in its role as a limited functionality event + * consumer. Its event producer role ({@link XMLFilter}) is ignored. + * + *


    + * + *

    The {@link #bind bind()} routine may be used associate event pipelines + * with any kind of {@link XMLReader} that will produce the events. + * Such pipelines don't necessarily need to have any members which are + * implemented using this class. That routine has some intelligence + * which supports automatic changes to parser feature flags, letting + * event piplines become largely independent of the particular feature + * sets of parsers. + * + * @author David Brownell + */ +public class EventFilter + implements EventConsumer, ContentHandler, DTDHandler, + LexicalHandler, DeclHandler +{ + // SAX handlers + private ContentHandler docHandler, docNext; + private DTDHandler dtdHandler, dtdNext; + private LexicalHandler lexHandler, lexNext; + private DeclHandler declHandler, declNext; + // and ideally, one more for the stuff SAX2 doesn't show + + private Locator locator; + private EventConsumer next; + private ErrorHandler errHandler; + + + /** SAX2 URI prefix for standard feature flags. */ + public static final String FEATURE_URI + = "http://xml.org/sax/features/"; + /** SAX2 URI prefix for standard properties (mostly for handlers). */ + public static final String PROPERTY_URI + = "http://xml.org/sax/properties/"; + + /** SAX2 property identifier for {@link DeclHandler} events */ + public static final String DECL_HANDLER + = PROPERTY_URI + "declaration-handler"; + /** SAX2 property identifier for {@link LexicalHandler} events */ + public static final String LEXICAL_HANDLER + = PROPERTY_URI + "lexical-handler"; + + // + // These class objects will be null if the relevant class isn't linked. + // Small configurations (pJava and some kinds of embedded systems) need + // to facilitate smaller executables. So "instanceof" is undesirable + // when bind() sees if it can remove some stages. + // + // SECURITY NOTE: assuming all these classes are part of the same sealed + // package, there's no problem saving these in the instance of this class + // that's associated with "this" class loader. But that wouldn't be true + // for classes in another package. + // + private static boolean loaded; + private static Class nsClass; + private static Class validClass; + private static Class wfClass; + private static Class xincClass; + + static ClassLoader getClassLoader () + { + Method m = null; + + try { + m = Thread.class.getMethod("getContextClassLoader"); + } catch (NoSuchMethodException e) { + // Assume that we are running JDK 1.1, use the current ClassLoader + return EventFilter.class.getClassLoader(); + } + + try { + return (ClassLoader) m.invoke(Thread.currentThread()); + } catch (IllegalAccessException e) { + // assert(false) + throw new UnknownError(e.getMessage()); + } catch (InvocationTargetException e) { + // assert(e.getTargetException() instanceof SecurityException) + throw new UnknownError(e.getMessage()); + } + } + + static Class loadClass (ClassLoader classLoader, String className) + { + try { + if (classLoader == null) + return Class.forName(className); + else + return classLoader.loadClass(className); + } catch (Exception e) { + return null; + } + } + + static private void loadClasses () + { + ClassLoader loader = getClassLoader (); + + nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter"); + validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer"); + wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter"); + xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter"); + loaded = true; + } + + + /** + * Binds the standard SAX2 handlers from the specified consumer + * pipeline to the specified producer. These handlers include the core + * {@link ContentHandler} and {@link DTDHandler}, plus the extension + * {@link DeclHandler} and {@link LexicalHandler}. Any additional + * application-specific handlers need to be bound separately. + * The {@link ErrorHandler} is handled differently: the producer's + * error handler is passed through to the consumer pipeline. + * The producer is told to include namespace prefix information if it + * can, since many pipeline stages need that Infoset information to + * work well. + * + *

    At the head of the pipeline, certain standard event filters are + * recognized and handled specially. This facilitates construction + * of processing pipelines that work regardless of the capabilities + * of the XMLReader implementation in use; for example, it permits + * validating output of a {@link gnu.xml.util.DomParser}.

    + * + *

    Other than that, this method works with any kind of event consumer, + * not just event filters. Note that in all cases, the standard handlers + * are assigned; any previous handler assignments for the handler will + * be overridden. + * + * @param producer will deliver events to the specified consumer + * @param consumer pipeline supplying event handlers to be associated + * with the producer (may not be null) + */ + public static void bind (XMLReader producer, EventConsumer consumer) + { + Class klass = null; + boolean prefixes; + + if (!loaded) + loadClasses (); + + // DOM building, printing, layered validation, and other + // things don't work well when prefix info is discarded. + // Include it by default, whenever possible. + try { + producer.setFeature (FEATURE_URI + "namespace-prefixes", + true); + prefixes = true; + } catch (SAXException e) { + prefixes = false; + } + + // NOTE: This loop doesn't use "instanceof", since that + // would prevent compiling/linking without those classes + // being present. + while (consumer != null) { + klass = consumer.getClass (); + + // we might have already changed this problematic SAX2 default. + if (nsClass != null && nsClass.isAssignableFrom (klass)) { + if (!prefixes) + break; + consumer = ((EventFilter)consumer).getNext (); + + // the parser _might_ do DTD validation by default ... + // if not, maybe we can change this setting. + } else if (validClass != null + && validClass.isAssignableFrom (klass)) { + try { + producer.setFeature (FEATURE_URI + "validation", + true); + consumer = ((ValidationConsumer)consumer).getNext (); + } catch (SAXException e) { + break; + } + + // parsers are required not to have such bugs + } else if (wfClass != null && wfClass.isAssignableFrom (klass)) { + consumer = ((WellFormednessFilter)consumer).getNext (); + + // stop on the first pipeline stage we can't remove + } else + break; + + if (consumer == null) + klass = null; + } + + // the actual setting here doesn't matter as much + // as that producer and consumer agree + if (xincClass != null && klass != null + && xincClass.isAssignableFrom (klass)) + ((XIncludeFilter)consumer).setSavingPrefixes (prefixes); + + // Some SAX parsers can't handle null handlers -- bleech + DefaultHandler2 h = new DefaultHandler2 (); + + if (consumer != null && consumer.getContentHandler () != null) + producer.setContentHandler (consumer.getContentHandler ()); + else + producer.setContentHandler (h); + if (consumer != null && consumer.getDTDHandler () != null) + producer.setDTDHandler (consumer.getDTDHandler ()); + else + producer.setDTDHandler (h); + + try { + Object dh; + + if (consumer != null) + dh = consumer.getProperty (DECL_HANDLER); + else + dh = null; + if (dh == null) + dh = h; + producer.setProperty (DECL_HANDLER, dh); + } catch (Exception e) { /* ignore */ } + try { + Object lh; + + if (consumer != null) + lh = consumer.getProperty (LEXICAL_HANDLER); + else + lh = null; + if (lh == null) + lh = h; + producer.setProperty (LEXICAL_HANDLER, lh); + } catch (Exception e) { /* ignore */ } + + // this binding goes the other way around + if (producer.getErrorHandler () == null) + producer.setErrorHandler (h); + if (consumer != null) + consumer.setErrorHandler (producer.getErrorHandler ()); + } + + /** + * Initializes all handlers to null. + */ + // constructor used by PipelineFactory + public EventFilter () { } + + + /** + * Handlers that are not otherwise set will default to those from + * the specified consumer, making it easy to pass events through. + * If the consumer is null, all handlers are initialzed to null. + */ + // constructor used by PipelineFactory + public EventFilter (EventConsumer consumer) + { + if (consumer == null) + return; + + next = consumer; + + // We delegate through the "xxNext" handlers, and + // report the "xxHandler" ones on our input side. + + // Normally a subclass would both override handler + // methods and register itself as the "xxHandler". + + docHandler = docNext = consumer.getContentHandler (); + dtdHandler = dtdNext = consumer.getDTDHandler (); + try { + declHandler = declNext = (DeclHandler) + consumer.getProperty (DECL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + try { + lexHandler = lexNext = (LexicalHandler) + consumer.getProperty (LEXICAL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + } + + /** + * Treats the XMLFilterImpl as a limited functionality event consumer, + * by arranging to deliver events to it; this lets such classes be + * "wrapped" as pipeline stages. + * + *

    Upstream Event Setup: + * If no handlers have been assigned to this EventFilter, then the + * handlers from specified XMLFilterImpl are returned from this + * {@link EventConsumer}: the XMLFilterImpl is just "wrapped". + * Otherwise the specified handlers will be returned. + * + *

    Downstream Event Setup: + * Subclasses may chain event delivery to the specified XMLFilterImpl + * by invoking the appropiate superclass methods, + * as if their constructor passed a "next" EventConsumer to the + * constructor for this class. + * If this EventFilter has an ErrorHandler, it is assigned as + * the error handler for the XMLFilterImpl, just as would be + * done for a next stage implementing {@link EventConsumer}. + * + * @param next the next downstream component of the pipeline. + * @exception IllegalStateException if the "next" consumer has + * already been set through the constructor. + */ + public void chainTo (XMLFilterImpl next) + { + if (this.next != null) + throw new IllegalStateException (); + + docNext = next.getContentHandler (); + if (docHandler == null) + docHandler = docNext; + dtdNext = next.getDTDHandler (); + if (dtdHandler == null) + dtdHandler = dtdNext; + + try { + declNext = (DeclHandler) next.getProperty (DECL_HANDLER); + if (declHandler == null) + declHandler = declNext; + } catch (SAXException e) { /* leave value null */ } + try { + lexNext = (LexicalHandler) next.getProperty (LEXICAL_HANDLER); + if (lexHandler == null) + lexHandler = lexNext; + } catch (SAXException e) { /* leave value null */ } + + if (errHandler != null) + next.setErrorHandler (errHandler); + } + + /** + * Records the error handler that should be used by this stage, and + * passes it "downstream" to any subsequent stage. + */ + final public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + if (next != null) + next.setErrorHandler (handler); + } + + /** + * Returns the error handler assigned this filter stage, or null + * if no such assigment has been made. + */ + final public ErrorHandler getErrorHandler () + { + return errHandler; + } + + + /** + * Returns the next event consumer in sequence; or null if there + * is no such handler. + */ + final public EventConsumer getNext () + { return next; } + + + /** + * Assigns the content handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setContentHandler (ContentHandler h) + { + docHandler = h; + } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + return docHandler; + } + + /** + * Assigns the DTD handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setDTDHandler (DTDHandler h) + { dtdHandler = h; } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + /** + * Stores the property, normally a handler; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous handler settting, which was probably + * pointed to the next consumer by the base class constructor. + */ + final public void setProperty (String id, Object o) + throws SAXNotRecognizedException, SAXNotSupportedException + { + try { + Object value = getProperty (id); + + if (value == o) + return; + if (DECL_HANDLER.equals (id)) { + declHandler = (DeclHandler) o; + return; + } + if (LEXICAL_HANDLER.equals (id)) { + lexHandler = (LexicalHandler) o; + return; + } + throw new SAXNotSupportedException (id); + + } catch (ClassCastException e) { + throw new SAXNotSupportedException (id); + } + } + + /** Retrieves a property of unknown intent (usually a handler) */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (DECL_HANDLER.equals (id)) + return declHandler; + if (LEXICAL_HANDLER.equals (id)) + return lexHandler; + + throw new SAXNotRecognizedException (id); + } + + /** + * Returns any locator provided to the next consumer, if this class + * (or a subclass) is handling {@link ContentHandler } events. + */ + public Locator getDocumentLocator () + { return locator; } + + + // CONTENT HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + if (docNext != null) + docNext.setDocumentLocator (locator); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDocument () throws SAXException + { + if (docNext != null) + docNext.startDocument (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void skippedEntity (String name) throws SAXException + { + if (docNext != null) + docNext.skippedEntity (name); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void processingInstruction (String target, String data) + throws SAXException + { + if (docNext != null) + docNext.processingInstruction (target, data); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void characters (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.characters (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.ignorableWhitespace (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (docNext != null) + docNext.startPrefixMapping (prefix, uri); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (docNext != null) + docNext.startElement (uri, localName, qName, atts); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (docNext != null) + docNext.endElement (uri, localName, qName); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endPrefixMapping (String prefix) throws SAXException + { + if (docNext != null) + docNext.endPrefixMapping (prefix); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDocument () throws SAXException + { + if (docNext != null) + docNext.endDocument (); + locator = null; + } + + + // DTD HANDLER DELEGATIONS + + /** SAX1: passes this callback to the next consumer, if any */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (dtdNext != null) + dtdNext.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + /** SAX1: passes this callback to the next consumer, if any */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (dtdNext != null) + dtdNext.notationDecl (name, publicId, systemId); + } + + + // LEXICAL HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (lexNext != null) + lexNext.startDTD (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDTD () + throws SAXException + { + if (lexNext != null) + lexNext.endDTD (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void comment (char ch [], int start, int length) + throws SAXException + { + if (lexNext != null) + lexNext.comment (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.startCDATA (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.endCDATA (); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void startEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.startEntity (name); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void endEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.endEntity (name); + } + + + // DECLARATION HANDLER DELEGATIONS + + + /** SAX2: passes this callback to the next consumer, if any */ + public void elementDecl (String name, String model) + throws SAXException + { + if (declNext != null) + declNext.elementDecl (name, model); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void attributeDecl (String eName, String aName, + String type, String mode, String value) + throws SAXException + { + if (declNext != null) + declNext.attributeDecl (eName, aName, type, mode, value); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (declNext != null) + declNext.externalEntityDecl (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (declNext != null) + declNext.internalEntityDecl (name, value); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/LinkFilter.java b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java new file mode 100644 index 000000000..e11a5eca6 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java @@ -0,0 +1,242 @@ +/* LinkFilter.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * Pipeline filter to remember XHTML links found in a document, + * so they can later be crawled. Fragments are not counted, and duplicates + * are ignored. Callers are responsible for filtering out URLs they aren't + * interested in. Events are passed through unmodified. + * + *

    Input MUST include a setDocumentLocator() call, as it's used to + * resolve relative links in the absence of a "base" element. Input MUST + * also include namespace identifiers, since it is the XHTML namespace + * identifier which is used to identify the relevant elements. + * + *

    FIXME: handle xml:base attribute ... in association with + * a stack of base URIs. Similarly, recognize/support XLink data. + * + * @author David Brownell + */ +public class LinkFilter extends EventFilter +{ + // for storing URIs + private Vector vector = new Vector (); + + // struct for "full" link record (tbd) + // these for troubleshooting original source: + // original uri + // uri as resolved (base, relative, etc) + // URI of originating doc + // line # + // original element + attrs (img src, desc, etc) + + // XLink model of the link ... for inter-site pairups ? + + private String baseURI; + + private boolean siteRestricted = false; + + // + // XXX leverage blacklist info (like robots.txt) + // + // XXX constructor w/param ... pipeline for sending link data + // probably XHTML --> XLink, providing info as sketched above + // + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration. + */ + // constructor used by PipelineFactory + public LinkFilter () + { + super.setContentHandler (this); + } + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration and passes all events, unmodified, + * to the next consumer. + */ + // constructor used by PipelineFactory + public LinkFilter (EventConsumer next) + { + super (next); + super.setContentHandler (this); + } + + + /** + * Returns an enumeration of the links found since the filter + * was constructed, or since removeAllLinks() was called. + * + * @return enumeration of strings. + */ + public Enumeration getLinks () + { + return vector.elements (); + } + + /** + * Removes records about all links reported to the event + * stream, as if the filter were newly created. + */ + public void removeAllLinks () + { + vector = new Vector (); + } + + + /** + * Collects URIs for (X)HTML content from elements which hold them. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + String link; + + // Recognize XHTML links. + if ("http://www.w3.org/1999/xhtml".equals (uri)) { + + if ("a".equals (localName) || "base".equals (localName) + || "area".equals (localName)) + link = atts.getValue ("href"); + else if ("iframe".equals (localName) || "frame".equals (localName)) + link = atts.getValue ("src"); + else if ("blockquote".equals (localName) || "q".equals (localName) + || "ins".equals (localName) || "del".equals (localName)) + link = atts.getValue ("cite"); + else + link = null; + link = maybeAddLink (link); + + // "base" modifies designated baseURI + if ("base".equals (localName) && link != null) + baseURI = link; + + if ("iframe".equals (localName) || "img".equals (localName)) + maybeAddLink (atts.getValue ("longdesc")); + } + + super.startElement (uri, localName, qName, atts); + } + + private String maybeAddLink (String link) + { + int index; + + // ignore empty links and fragments inside docs + if (link == null) + return null; + if ((index = link.indexOf ("#")) >= 0) + link = link.substring (0, index); + if (link.equals ("")) + return null; + + try { + // get the real URI + URL base = new URL ((baseURI != null) + ? baseURI + : getDocumentLocator ().getSystemId ()); + URL url = new URL (base, link); + + link = url.toString (); + + // ignore duplicates + if (vector.contains (link)) + return link; + + // other than what "base" does, stick to original site: + if (siteRestricted) { + // don't switch protocols + if (!base.getProtocol ().equals (url.getProtocol ())) + return link; + // don't switch servers + if (base.getHost () != null + && !base.getHost ().equals (url.getHost ())) + return link; + } + + vector.addElement (link); + + return link; + + } catch (IOException e) { + // bad URLs we don't want + } + return null; + } + + /** + * Reports an error if no Locator has been made available. + */ + public void startDocument () + throws SAXException + { + if (getDocumentLocator () == null) + throw new SAXException ("no Locator!"); + } + + /** + * Forgets about any base URI information that may be recorded. + * Applications will often want to call removeAllLinks(), likely + * after examining the links which were reported. + */ + public void endDocument () + throws SAXException + { + baseURI = null; + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/NSFilter.java b/libjava/classpath/gnu/xml/pipeline/NSFilter.java new file mode 100644 index 000000000..0fa4621d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/NSFilter.java @@ -0,0 +1,341 @@ +/* NSFilter.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.util.Enumeration; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.NamespaceSupport; + +/** + * This filter ensures that element and attribute names are properly prefixed, + * and that such prefixes are declared. Such data is critical for operations + * like writing XML text, and validating against DTDs: names or their prefixes + * may have been discarded, although they are essential to the exchange of + * information using XML. There are various common ways that such data + * gets discarded:

    + * + *

    This filter uses a heuristic to choose the prefix to assign to any + * particular name which wasn't already corectly prefixed. The associated + * namespace will be correct, and the prefix will be declared. Original + * structures facilitating text editing, such as conventions about use of + * mnemonic prefix names or the scoping of prefixes, can't always be + * reconstructed after they are discarded, as strongly encouraged by the + * current SAX2 defaults. + * + *

    Note that this can't possibly know whether values inside attribute + * value or document content involve prefixed names. If your application + * requires using prefixed names in such locations you'll need to add some + * appropriate logic (perhaps adding additional heuristics in a subclass). + * + * @author David Brownell + */ +public class NSFilter extends EventFilter +{ + private NamespaceSupport nsStack = new NamespaceSupport (); + private Stack elementStack = new Stack (); + + private boolean pushedContext; + private String nsTemp [] = new String [3]; + private AttributesImpl attributes = new AttributesImpl (); + private boolean usedDefault; + + // gensymmed prefixes use this root name + private static final String prefixRoot = "prefix-"; + + + /** + * Passes events through to the specified consumer, after first + * processing them. + * + * @param next the next event consumer to receive events. + */ + // constructor used by PipelineFactory + public NSFilter (EventConsumer next) + { + super (next); + + setContentHandler (this); + } + + private void fatalError (String message) + throws SAXException + { + SAXParseException e; + ErrorHandler handler = getErrorHandler (); + Locator locator = getDocumentLocator (); + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1); + else + e = new SAXParseException (message, locator); + if (handler != null) + handler.fatalError (e); + throw e; + } + + + public void startDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + pushedContext = false; + super.startDocument (); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in the form + * of attributes; this callback just records a declaration that + * will be exposed as an attribute. + */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (pushedContext == false) { + nsStack.pushContext (); + pushedContext = true; + } + + // this check is awkward, but the paranoia prevents big trouble + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */ ) { + String declared = (String) e.nextElement (); + + if (!declared.equals (prefix)) + continue; + if (uri.equals (nsStack.getURI (prefix))) + return; + fatalError ("inconsistent binding for prefix '" + prefix + + "' ... " + uri + " (was " + nsStack.getURI (prefix) + ")"); + } + + if (!nsStack.declarePrefix (prefix, uri)) + fatalError ("illegal prefix declared: " + prefix); + } + + private String fixName (String ns, String l, String name, boolean isAttr) + throws SAXException + { + if ("".equals (name) || name == null) { + name = l; + if ("".equals (name) || name == null) + fatalError ("empty/null name"); + } + + // can we correctly process the name as-is? + // handles "element scope" attribute names here. + if (nsStack.processName (name, nsTemp, isAttr) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + + // nope, gotta modify the name or declare a default mapping + int temp; + + // get rid of any current prefix + if ((temp = name.indexOf (':')) >= 0) { + name = name.substring (temp + 1); + + // ... maybe that's enough (use/prefer default namespace) ... + if (!isAttr && nsStack.processName (name, nsTemp, false) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + } + + // must we define and use the default/undefined prefix? + if ("".equals (ns)) { + if (isAttr) + fatalError ("processName bug"); + if (attributes.getIndex ("xmlns") != -1) + fatalError ("need to undefine default NS, but it's bound: " + + attributes.getValue ("xmlns")); + + nsStack.declarePrefix ("", ""); + attributes.addAttribute ("", "", "xmlns", "CDATA", ""); + return name; + } + + // is there at least one non-null prefix we can use? + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + String uri = nsStack.getURI (prefix); + + if (uri == null || !uri.equals (ns)) + continue; + return prefix + ":" + name; + } + + // no such luck. create a prefix name, declare it, use it. + for (temp = 0; temp >= 0; temp++) { + String prefix = prefixRoot + temp; + + if (nsStack.getURI (prefix) == null) { + nsStack.declarePrefix (prefix, ns); + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", ns); + return prefix + ":" + name; + } + } + fatalError ("too many prefixes genned"); + // NOTREACHED + return null; + } + + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (!pushedContext) + nsStack.pushContext (); + pushedContext = false; + + // make sure we have all NS declarations handy before we start + int length = atts.getLength (); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + + if (!aName.startsWith ("xmlns")) + continue; + + String prefix; + + if ("xmlns".equals (aName)) + prefix = ""; + else if (aName.indexOf (':') == 5) + prefix = aName.substring (6); + else // "xmlnsfoo" etc. + continue; + startPrefixMapping (prefix, atts.getValue (i)); + } + + // put namespace decls at the start of our regenned attlist + attributes.clear (); + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + + attributes.addAttribute ("", "", + ("".equals (prefix) + ? "xmlns" + : "xmlns:" + prefix), + "CDATA", + nsStack.getURI (prefix)); + } + + // name fixups: element, then attributes. + // fixName may declare a new prefix or, for the element, + // redeclare the default (if element name needs it). + qName = fixName (uri, localName, qName, false); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + String aNS = atts.getURI (i); + String aLocal = atts.getLocalName (i); + String aType = atts.getType (i); + String aValue = atts.getValue (i); + + if (aName.startsWith ("xmlns")) + continue; + aName = fixName (aNS, aLocal, aName, true); + attributes.addAttribute (aNS, aLocal, aName, aType, aValue); + } + + elementStack.push (qName); + + // pass event along, with cleaned-up names and decls. + super.startElement (uri, localName, qName, attributes); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + nsStack.popContext (); + qName = (String) elementStack.pop (); + super.endElement (uri, localName, qName); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in their + * attribute form. + */ + public void endPrefixMapping (String prefix) + throws SAXException + { } + + public void endDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java new file mode 100644 index 000000000..c2adab021 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java @@ -0,0 +1,723 @@ +/* PipelineFactory.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; +import java.util.StringTokenizer; + +import org.xml.sax.*; +import org.xml.sax.ext.*; + + +/** + * This provides static factory methods for creating simple event pipelines. + * These pipelines are specified by strings, suitable for passing on + * command lines or embedding in element attributes. For example, one way + * to write a pipeline that restores namespace syntax, validates (stopping + * the pipeline on validity errors) and then writes valid data to standard + * output is this:

    + *      nsfix | validate | write ( stdout )
    + * + *

    In this syntax, the tokens are always separated by whitespace, and each + * stage of the pipeline may optionally have a parameter (which can be a + * pipeline) in parentheses. Interior stages are called filters, and the + * rightmost end of a pipeline is called a terminus. + * + *

    Stages are usually implemented by a single class, which may not be + * able to act as both a filter and a terminus; but any terminus can be + * automatically turned into a filter, through use of a {@link TeeConsumer}. + * The stage identifiers are either class names, or are one of the following + * short identifiers built into this class. (Most of these identifiers are + * no more than aliases for classes.) The built-in identifiers include:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StageParameterTerminusDescription
    domnone yes Applications code can access a DOM Document built + from the input event stream. When used as a filter, this buffers + data up to an endDocument call, and then uses a DOM parser + to report everything that has been recorded (which can easily be + less than what was reported to it).
    nsfixnonenoThis stage ensures that the XML element and attribute + names in its output use namespace prefixes and declarations correctly. + That is, so that they match the "Namespace plus LocalName" naming data + with which each XML element and attribute is already associated.
    nullnoneyesThis stage ignores all input event data.
    serverrequired
    server URL
    noSends its input as XML request to a remote server, + normally a web application server using the HTTP or HTTPS protocols. + The output of this stage is the parsed response from that server.
    teerequired
    first pipeline
    noThis sends its events down two paths; its parameter + is a pipeline descriptor for the first path, and the second path + is the output of this stage.
    validatenoneyesThis checks for validity errors, and reports them + through its error handler. The input must include declaration events + and some lexical events.
    wfnoneyes This class provides some basic "well formedness" + tests on the input event stream, and reports a fatal error if any + of them fail. One example: start/end calls for elements must match. + No SAX parser is permitted to produce malformed output, but other + components can easily do so.
    writerequired
    "stdout", "stderr", or filename
    yes Writes its input to the specified output, as pretty + printed XML text encoded using UTF-8. Input events must be well + formed and "namespace fixed", else the output won't be XML (or possibly + namespace) conformant. The symbolic names represent + System.out and System.err respectively; names must + correspond to files which don't yet exist.
    xhtmlrequired
    "stdout", "stderr", or filename
    yes Like write (above), except that XHTML rules + are followed. The XHTML 1.0 Transitional document type is declared, + and only ASCII characters are written (for interoperability). Other + characters are written as entity or character references; the text is + pretty printed.
    xincludenonenoThis stage handles XInclude processing. + This is like entity inclusion, except that the included content + is declared in-line rather than in the DTD at the beginning of + a document. +
    xsltrequired
    XSLT stylesheet URI
    noThis stage handles XSLT transformation + according to a stylesheet. + The implementation of the transformation may not actually + stream data, although if such an XSLT engine is in use + then that can happen. +
    + + *

    Note that {@link EventFilter#bind} can automatically eliminate + * some filters by setting SAX2 parser features appropriately. This means + * that you can routinely put filters like "nsfix", "validate", or "wf" at the + * front of a pipeline (for components that need inputs conditioned to match + * that level of correctness), and know that it won't actually be used unless + * it's absolutely necessary. + * + * @author David Brownell + */ +public class PipelineFactory +{ + /** + * Creates a simple pipeline according to the description string passed in. + */ + public static EventConsumer createPipeline (String description) + throws IOException + { + return createPipeline (description, null); + } + + /** + * Extends an existing pipeline by prepending the filter pipeline to the + * specified consumer. Some pipelines need more customization than can + * be done through this simplified syntax. When they are set up with + * direct API calls, use this method to merge more complex pipeline + * segments with easily configured ones. + */ + public static EventConsumer createPipeline ( + String description, + EventConsumer next + ) throws IOException + { + // tokens are (for now) what's separated by whitespace; + // very easy to parse, but IDs never have spaces. + + StringTokenizer tokenizer; + String tokens []; + + tokenizer = new StringTokenizer (description); + tokens = new String [tokenizer.countTokens ()]; + for (int i = 0; i < tokens.length; i++) + tokens [i] = tokenizer.nextToken (); + + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private PipelineFactory () { /* NYET */ } + + + /** + * Extends an existing pipeline by prepending a pre-tokenized filter + * pipeline to the specified consumer. Tokens are class names (or the + * predefined aliases) left and right parenthesis, and the vertical bar. + */ + public static EventConsumer createPipeline ( + String tokens [], + EventConsumer next + ) throws IOException + { + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private String tokens []; + private int index; + + private Pipeline parsePipeline (String toks [], EventConsumer next) + { + tokens = toks; + index = 0; + + Pipeline retval = parsePipeline (next); + + if (index != toks.length) + throw new ArrayIndexOutOfBoundsException ( + "extra token: " + tokens [index]); + return retval; + } + + // pipeline ::= stage | stage '|' pipeline + private Pipeline parsePipeline (EventConsumer next) + { + Pipeline retval = new Pipeline (parseStage ()); + + // minimal pipelines: "stage" and "... | id" + if (index > (tokens.length - 2) + || !"|".equals (tokens [index]) + ) { + retval.next = next; + return retval; + } + index++; + retval.rest = parsePipeline (next); + return retval; + } + + // stage ::= id | id '(' pipeline ')' + private Stage parseStage () + { + Stage retval = new Stage (tokens [index++]); + + // minimal stages: "id" and "id ( id )" + if (index > (tokens.length - 2) + || !"(".equals (tokens [index]) /*)*/ + ) + return retval; + + index++; + retval.param = parsePipeline (null); + if (index >= tokens.length) + throw new ArrayIndexOutOfBoundsException ( + "missing right paren"); + if (/*(*/ !")".equals (tokens [index++])) + throw new ArrayIndexOutOfBoundsException ( + "required right paren, not: " + tokens [index - 1]); + return retval; + } + + + // + // these classes obey the conventions for constructors, so they're + // only built in to this table of shortnames + // + // - filter (one or two types of arglist) + // * last constructor is 'next' element + // * optional (first) string parameter + // + // - terminus (one or types of arglist) + // * optional (only) string parameter + // + // terminus stages are transformed into filters if needed, by + // creating a "tee". filter stages aren't turned to terminus + // stages though; either eliminate such stages, or add some + // terminus explicitly. + // + private static final String builtinStages [][] = { + { "dom", "gnu.xml.dom.Consumer" }, + { "nsfix", "gnu.xml.pipeline.NSFilter" }, + { "null", "gnu.xml.pipeline.EventFilter" }, + { "server", "gnu.xml.pipeline.CallFilter" }, + { "tee", "gnu.xml.pipeline.TeeConsumer" }, + { "validate", "gnu.xml.pipeline.ValidationConsumer" }, + { "wf", "gnu.xml.pipeline.WellFormednessFilter" }, + { "xinclude", "gnu.xml.pipeline.XIncludeFilter" }, + { "xslt", "gnu.xml.pipeline.XsltFilter" }, + +// XXX want: option for validate, to preload external part of a DTD + + // xhtml, write ... nyet generic-ready + }; + + private static class Stage + { + String id; + Pipeline param; + + Stage (String name) + { id = name; } + + public String toString () + { + if (param == null) + return id; + return id + " ( " + param + " )"; + } + + private void fail (String message) + throws IOException + { + throw new IOException ("in '" + id + + "' stage of pipeline, " + message); + } + + EventConsumer createStage (EventConsumer next) + throws IOException + { + String name = id; + + // most builtins are just class aliases + for (int i = 0; i < builtinStages.length; i++) { + if (id.equals (builtinStages [i][0])) { + name = builtinStages [i][1]; + break; + } + } + + // Save output as XML or XHTML text + if ("write".equals (name) || "xhtml".equals (name)) { + String filename; + boolean isXhtml = "xhtml".equals (name); + OutputStream out = null; + TextConsumer consumer; + + if (param == null) + fail ("parameter is required"); + + filename = param.toString (); + if ("stdout".equals (filename)) + out = System.out; + else if ("stderr".equals (filename)) + out = System.err; + else { + File f = new File (filename); + +/* + if (!f.isAbsolute ()) + fail ("require absolute file paths"); + */ + if (f.exists ()) + fail ("file already exists: " + f.getName ()); + +// XXX this races against the existence test + out = new FileOutputStream (f); + } + + if (!isXhtml) + consumer = new TextConsumer (out); + else + consumer = new TextConsumer ( + new OutputStreamWriter (out, "8859_1"), + true); + + consumer.setPrettyPrinting (true); + if (next == null) + return consumer; + return new TeeConsumer (consumer, next); + + } else { + // + // Here go all the builtins that are just aliases for + // classes, and all stage IDs that started out as such + // class names. The following logic relies on several + // documented conventions for constructor invocation. + // + String msg = null; + + try { + Class klass = Class.forName (name); + Class argTypes [] = null; + Constructor constructor = null; + boolean filter = false; + Object params [] = null; + Object obj = null; + + // do we need a filter stage? + if (next != null) { + // "next" consumer is always passed, with + // or without the optional string param + if (param == null) { + argTypes = new Class [1]; + argTypes [0] = EventConsumer.class; + + params = new Object [1]; + params [0] = next; + + msg = "no-param filter"; + } else { + argTypes = new Class [2]; + argTypes [0] = String.class; + argTypes [1] = EventConsumer.class; + + params = new Object [2]; + params [0] = param.toString (); + params [1] = next; + + msg = "one-param filter"; + } + + + try { + constructor = klass.getConstructor (argTypes); + } catch (NoSuchMethodException e) { + // try creating a filter from a + // terminus and a tee + filter = true; + msg += " built from "; + } + } + + // build from a terminus stage, with or + // without the optional string param + if (constructor == null) { + String tmp; + + if (param == null) { + argTypes = new Class [0]; + params = new Object [0]; + + tmp = "no-param terminus"; + } else { + argTypes = new Class [1]; + argTypes [0] = String.class; + + params = new Object [1]; + params [0] = param.toString (); + + tmp = "one-param terminus"; + } + if (msg == null) + msg = tmp; + else + msg += tmp; + constructor = klass.getConstructor (argTypes); + // NOT creating terminus by dead-ending + // filters ... users should think about + // that one, something's likely wrong + } + + obj = constructor.newInstance (params); + + // return EventConsumers directly, perhaps after + // turning them into a filter + if (obj instanceof EventConsumer) { + if (filter) + return new TeeConsumer ((EventConsumer) obj, next); + return (EventConsumer) obj; + } + + // if it's not a handler, it's an error + // we can wrap handlers in a filter + EventFilter retval = new EventFilter (); + boolean updated = false; + + if (obj instanceof ContentHandler) { + retval.setContentHandler ((ContentHandler) obj); + updated = true; + } + if (obj instanceof DTDHandler) { + retval.setDTDHandler ((DTDHandler) obj); + updated = true; + } + if (obj instanceof LexicalHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "lexical-handler", + obj); + updated = true; + } + if (obj instanceof DeclHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "declaration-handler", + obj); + updated = true; + } + + if (!updated) + fail ("class is neither Consumer nor Handler"); + + if (filter) + return new TeeConsumer (retval, next); + return retval; + + } catch (IOException e) { + throw e; + + } catch (NoSuchMethodException e) { + fail (name + " constructor missing -- " + msg); + + } catch (ClassNotFoundException e) { + fail (name + " class not found"); + + } catch (Exception e) { + // e.printStackTrace (); + fail ("stage not available: " + e.getMessage ()); + } + } + // NOTREACHED + return null; + } + } + + private static class Pipeline + { + Stage stage; + + // rest may be null + Pipeline rest; + EventConsumer next; + + Pipeline (Stage s) + { stage = s; } + + public String toString () + { + if (rest == null && next == null) + return stage.toString (); + if (rest != null) + return stage + " | " + rest; + throw new IllegalArgumentException ("next"); + } + + EventConsumer createPipeline () + throws IOException + { + if (next == null) { + if (rest == null) + next = stage.createStage (null); + else + next = stage.createStage (rest.createPipeline ()); + } + return next; + } + } + +/* + public static void main (String argv []) + { + try { + // three basic terminus cases + createPipeline ("null"); + createPipeline ("validate"); + createPipeline ("write ( stdout )"); + + // four basic filters + createPipeline ("nsfix | write ( stderr )"); + createPipeline ("wf | null"); + createPipeline ("null | null"); + createPipeline ( +"call ( http://www.example.com/services/xml-1a ) | xhtml ( stdout )"); + + // tee junctions + createPipeline ("tee ( validate ) | write ( stdout )"); + createPipeline ("tee ( nsfix | write ( stdout ) ) | validate"); + + // longer pipeline + createPipeline ("nsfix | tee ( validate ) | write ( stdout )"); + createPipeline ( + "null | wf | nsfix | tee ( validate ) | write ( stdout )"); + + // try some parsing error cases + try { + createPipeline ("null ("); // extra token '(' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("nsfix |"); // extra token '|' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo"); // missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo bar"); // required right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("tee ( nsfix | validate");// missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + // try some construction error cases + + try { + createPipeline ("call"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("call ( foobar )"); // broken param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("nsfix ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("null ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("wf ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("xhtml ( foobar.html )"); + new File ("foobar.html").delete (); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("xhtml"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("write ( stdout ) | null"); // nonterminal + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("validate | null"); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("validate ( foo )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("tee"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + // only builtins so far + createPipeline ("com.example.xml.FilterClass"); + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + } catch (Exception e) { + e.printStackTrace (); + } + } +/**/ + +} diff --git a/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java new file mode 100644 index 000000000..3ac860575 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java @@ -0,0 +1,417 @@ +/* TeeConsumer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +/** + * Fans its events out to two other consumers, a "tee" filter stage in an + * event pipeline. Networks can be assembled with multiple output points. + * + *

    Error handling should be simple if you remember that exceptions + * you throw will cancel later stages in that callback's pipeline, and + * generally the producer will stop if it sees such an exception. You + * may want to protect your pipeline against such backflows, making a + * kind of reverse filter (or valve?) so that certain exceptions thrown by + * your pipeline will caught and handled before the producer sees them. + * Just use a "try/catch" block, rememebering that really important + * cleanup tasks should be in "finally" clauses. + * + *

    That issue isn't unique to "tee" consumers, but tee consumers have + * the additional twist that exceptions thrown by the first consumer + * will cause the second consumer not to see the callback (except for + * the endDocument callback, which signals state cleanup). + * + * @author David Brownell + */ +final public class TeeConsumer + implements EventConsumer, + ContentHandler, DTDHandler, + LexicalHandler,DeclHandler +{ + private EventConsumer first, rest; + + // cached to minimize time overhead + private ContentHandler docFirst, docRest; + private DeclHandler declFirst, declRest; + private LexicalHandler lexFirst, lexRest; + + + /** + * Constructs a consumer which sends all its events to the first + * consumer, and then the second one. If the first consumer throws + * an exception, the second one will not see the event which + * caused that exception to be reported. + * + * @param car The first consumer to get the events + * @param cdr The second consumer to get the events + */ + public TeeConsumer (EventConsumer car, EventConsumer cdr) + { + if (car == null || cdr == null) + throw new NullPointerException (); + first = car; + rest = cdr; + + // + // Cache the handlers. + // + docFirst = first.getContentHandler (); + docRest = rest.getContentHandler (); + // DTD handler isn't cached (rarely needed) + + try { + declFirst = null; + declFirst = (DeclHandler) first.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + try { + declRest = null; + declRest = (DeclHandler) rest.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + + try { + lexFirst = null; + lexFirst = (LexicalHandler) first.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + try { + lexRest = null; + lexRest = (LexicalHandler) rest.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + } + +/* FIXME + /** + * Constructs a pipeline, and is otherwise a shorthand for the + * two-consumer constructor for this class. + * + * @param first Description of the first pipeline to get events, + * which will be passed to {@link PipelineFactory#createPipeline} + * @param rest The second pipeline to get the events + * / + // constructor used by PipelineFactory + public TeeConsumer (String first, EventConsumer rest) + throws IOException + { + this (PipelineFactory.createPipeline (first), rest); + } +*/ + + /** Returns the first pipeline to get event calls. */ + public EventConsumer getFirst () + { return first; } + + /** Returns the second pipeline to get event calls. */ + public EventConsumer getRest () + { return rest; } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + if (docRest == null) + return docFirst; + if (docFirst == null) + return docRest; + return this; + } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + // not cached (hardly used) + if (rest.getDTDHandler () == null) + return first.getDTDHandler (); + if (first.getDTDHandler () == null) + return rest.getDTDHandler (); + return this; + } + + /** Returns the declaration or lexical handler being used. */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + // + // in degenerate cases, we have no work to do. + // + Object firstProp = null, restProp = null; + + try { firstProp = first.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + try { restProp = rest.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + + if (restProp == null) + return firstProp; + if (firstProp == null) + return restProp; + + // + // we've got work to do; handle two builtin cases. + // + if (EventFilter.DECL_HANDLER.equals (id)) + return this; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return this; + + // + // non-degenerate, handled by both consumers, but we don't know + // how to handle this. + // + throw new SAXNotRecognizedException ("can't tee: " + id); + } + + /** + * Provides the error handler to both subsequent nodes of + * this filter stage. + */ + public void setErrorHandler (ErrorHandler handler) + { + first.setErrorHandler (handler); + rest.setErrorHandler (handler); + } + + + // + // ContentHandler + // + public void setDocumentLocator (Locator locator) + { + // this call is not made by all parsers + docFirst.setDocumentLocator (locator); + docRest.setDocumentLocator (locator); + } + + public void startDocument () + throws SAXException + { + docFirst.startDocument (); + docRest.startDocument (); + } + + public void endDocument () + throws SAXException + { + try { + docFirst.endDocument (); + } finally { + docRest.endDocument (); + } + } + + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + docFirst.startPrefixMapping (prefix, uri); + docRest.startPrefixMapping (prefix, uri); + } + + public void endPrefixMapping (String prefix) + throws SAXException + { + docFirst.endPrefixMapping (prefix); + docRest.endPrefixMapping (prefix); + } + + public void skippedEntity (String name) + throws SAXException + { + docFirst.skippedEntity (name); + docRest.skippedEntity (name); + } + + public void startElement (String uri, String localName, + String qName, Attributes atts) + throws SAXException + { + docFirst.startElement (uri, localName, qName, atts); + docRest.startElement (uri, localName, qName, atts); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + docFirst.endElement (uri, localName, qName); + docRest.endElement (uri, localName, qName); + } + + public void processingInstruction (String target, String data) + throws SAXException + { + docFirst.processingInstruction (target, data); + docRest.processingInstruction (target, data); + } + + public void characters (char ch [], int start, int length) + throws SAXException + { + docFirst.characters (ch, start, length); + docRest.characters (ch, start, length); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + docFirst.ignorableWhitespace (ch, start, length); + docRest.ignorableWhitespace (ch, start, length); + } + + + // + // DTDHandler + // + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.notationDecl (name, publicId, systemId); + l2.notationDecl (name, publicId, systemId); + } + + public void unparsedEntityDecl (String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.unparsedEntityDecl (name, publicId, systemId, notationName); + l2.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + // + // DeclHandler + // + public void attributeDecl (String eName, String aName, + String type, + String mode, String value) + throws SAXException + { + declFirst.attributeDecl (eName, aName, type, mode, value); + declRest.attributeDecl (eName, aName, type, mode, value); + } + + public void elementDecl (String name, String model) + throws SAXException + { + declFirst.elementDecl (name, model); + declRest.elementDecl (name, model); + } + + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + declFirst.externalEntityDecl (name, publicId, systemId); + declRest.externalEntityDecl (name, publicId, systemId); + } + + public void internalEntityDecl (String name, String value) + throws SAXException + { + declFirst.internalEntityDecl (name, value); + declRest.internalEntityDecl (name, value); + } + + + // + // LexicalHandler + // + public void comment (char ch [], int start, int length) + throws SAXException + { + lexFirst.comment (ch, start, length); + lexRest.comment (ch, start, length); + } + + public void startCDATA () + throws SAXException + { + lexFirst.startCDATA (); + lexRest.startCDATA (); + } + + public void endCDATA () + throws SAXException + { + lexFirst.endCDATA (); + lexRest.endCDATA (); + } + + public void startEntity (String name) + throws SAXException + { + lexFirst.startEntity (name); + lexRest.startEntity (name); + } + + public void endEntity (String name) + throws SAXException + { + lexFirst.endEntity (name); + lexRest.endEntity (name); + } + + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + lexFirst.startDTD (name, publicId, systemId); + lexRest.startDTD (name, publicId, systemId); + } + + public void endDTD () + throws SAXException + { + lexFirst.endDTD (); + lexRest.endDTD (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/TextConsumer.java b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java new file mode 100644 index 000000000..13dcfa7f6 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java @@ -0,0 +1,117 @@ +/* TextConsumer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.*; + +import org.xml.sax.*; + +import gnu.xml.util.XMLWriter; + + +/** + * Terminates a pipeline, consuming events to print them as well formed + * XML (or XHTML) text. + * + *

    Input must be well formed, and must include XML names (e.g. the + * prefixes and prefix declarations must be present), or the output of + * this class is undefined. + * + * @see NSFilter + * @see WellFormednessFilter + * + * @author David Brownell + */ +public class TextConsumer extends XMLWriter implements EventConsumer +{ + /** + * Constructs an event consumer which echoes its input as text, + * optionally adhering to some basic XHTML formatting options + * which increase interoperability with old (v3) browsers. + * + *

    For the best interoperability, when writing as XHTML only + * ASCII characters are emitted; other characters are turned to + * entity or character references as needed, and no XML declaration + * is provided in the document. + */ + public TextConsumer (Writer w, boolean isXhtml) + throws IOException + { + super (w, isXhtml ? "US-ASCII" : null); + setXhtml (isXhtml); + } + + /** + * Constructs a consumer that writes its input as XML text. + * XHTML rules are not followed. + */ + public TextConsumer (Writer w) + throws IOException + { + this (w, false); + } + + /** + * Constructs a consumer that writes its input as XML text, + * encoded in UTF-8. XHTML rules are not followed. + */ + public TextConsumer (OutputStream out) + throws IOException + { + this (new OutputStreamWriter (out, "UTF8"), false); + } + + /** EventConsumer Returns the document handler being used. */ + public ContentHandler getContentHandler () + { return this; } + + /** EventConsumer Returns the dtd handler being used. */ + public DTDHandler getDTDHandler () + { return this; } + + /** XMLReaderRetrieves a property (lexical and decl handlers) */ + public Object getProperty (String propertyId) + throws SAXNotRecognizedException + { + if (EventFilter.LEXICAL_HANDLER.equals (propertyId)) + return this; + if (EventFilter.DECL_HANDLER.equals (propertyId)) + return this; + throw new SAXNotRecognizedException (propertyId); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java new file mode 100644 index 000000000..0346984d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java @@ -0,0 +1,1928 @@ +/* ValidationConsumer.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * This class checks SAX2 events to report validity errors; it works as + * both a filter and a terminus on an event pipeline. It relies on the + * producer of SAX events to:

      + * + *
    1. Conform to the specification of a non-validating XML parser that + * reads all external entities, reported using SAX2 events.
    2. + * + *
    3. Report ignorable whitespace as such (through the ContentHandler + * interface). This is, strictly speaking, optional for nonvalidating + * XML processors.
    4. + * + *
    5. Make SAX2 DeclHandler callbacks, with default + * attribute values already normalized (and without "<").
    6. + * + *
    7. Make SAX2 LexicalHandler startDTD() and endDTD () + * callbacks.
    8. + * + *
    9. Act as if the (URI)/namespace-prefixes property were + * set to true, by providing XML 1.0 names and all xmlns* + * attributes (rather than omitting either or both).
    10. + * + *
    + * + *

    At this writing, the major SAX2 parsers (such as Ælfred2, + * Crimson, and Xerces) meet these requirements, and this validation + * module is used by the optional Ælfred2 validation support. + *

    + * + *

    Note that because this is a layered validator, it has to duplicate some + * work that the parser is doing; there are also other cost to layering. + * However, because of layering it doesn't need a parser in order + * to work! You can use it with anything that generates SAX events, such + * as an application component that wants to detect invalid content in + * a changed area without validating an entire document, or which wants to + * ensure that it doesn't write invalid data to a communications partner.

    + * + *

    Also, note that because this is a layered validator, the line numbers + * reported for some errors may seem strange. For example, if an element does + * not permit character content, the validator + * will use the locator provided to it. + * That might reflect the last character of a characters event + * callback, rather than the first non-whitespace character.

    + * + *
    + * + * + * + *

    Current limitations of the validation performed are in roughly three + * categories.

    + * + *

    The first category represents constraints which demand violations + * of software layering: exposing lexical details, one of the first things + * that application programming interfaces (APIs) hide. These + * invariably relate to XML entity handling, and to historical oddities + * of the XML validation semantics. Curiously, + * recent (Autumn 1999) conformance testing showed that these constraints are + * among those handled worst by existing XML validating parsers. Arguments + * have been made that each of these VCs should be turned into WFCs (most + * of them) or discarded (popular for the standalone declaration); in short, + * that these are bugs in the XML specification (not all via SGML):

    + * + *

    The second category of limitations on this validation represent + * constraints associated with information that is not guaranteed to be + * available (or in one case, is guaranteed not to be available, + * through the SAX2 API:

    + * + *

    A third category relates to ease of implementation. (Think of this + * as "bugs".) The most notable issue here is character handling. Rather + * than attempting to implement the voluminous character tables in the XML + * specification (Appendix B), Unicode rules are used directly from + * the java.lang.Character class. Recent JVMs have begun to diverge from + * the original specification for that class (Unicode 2.0), meaning that + * different JVMs may handle that aspect of conformance differently. + *

    + * + *

    Note that for some of the validity errors that SAX2 does not + * expose, a nonvalidating parser is permitted (by the XML specification) + * to report validity errors. When used with a parser that does so for + * the validity constraints mentioned above (or any other SAX2 event + * stream producer that does the same thing), overall conformance is + * substantially improved. + * + * @see gnu.xml.aelfred2.SAXDriver + * @see gnu.xml.aelfred2.XmlReader + * + * @author David Brownell + */ +public final class ValidationConsumer extends EventFilter +{ + // report error if we happen to notice a non-deterministic choice? + // we won't report buggy content models; just buggy instances + private static final boolean warnNonDeterministic = false; + + // for tracking active content models + private String rootName; + private Stack contentStack = new Stack (); + + // flags for "saved DTD" processing + private boolean disableDeclarations; + private boolean disableReset; + + // + // most VCs get tested when we see element start tags. the per-element + // info (including attributes) recorded here duplicates that found inside + // many nonvalidating parsers, hence dual lookups etc ... that's why a + // layered validator isn't going to be as fast as a non-layered one. + // + + // key = element name; value = ElementInfo + private Hashtable elements = new Hashtable (); + + // some VCs relate to ID/IDREF/IDREFS attributes + // key = id; value = boolean true (defd) or false (refd) + private Hashtable ids = new Hashtable (); + + // we just record declared notation and unparsed entity names. + // the implementation here is simple/slow; these features + // are seldom used, one hopes they'll wither away soon + private Vector notations = new Vector (5, 5); + private Vector nDeferred = new Vector (5, 5); + private Vector unparsed = new Vector (5, 5); + private Vector uDeferred = new Vector (5, 5); + + // note: DocBk 3.1.7 XML defines over 2 dozen notations, + // used when defining unparsed entities for graphics + // (and maybe in other places) + + + + /** + * Creates a pipeline terminus which consumes all events passed to + * it; this will report validity errors as if they were fatal errors, + * unless an error handler is assigned. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + public ValidationConsumer () + { + this (null); + } + + /** + * Creates a pipeline filter which reports validity errors and then + * passes events on to the next consumer if they were not fatal. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + // (which won't send declaration events) + public ValidationConsumer (EventConsumer next) + { + super (next); + + setContentHandler (this); + setDTDHandler (this); + try { setProperty (DECL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + try { setProperty (LEXICAL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + } + + + private static final String fakeRootName + = ":Nobody:in:their_Right.Mind_would:use:this-name:1x:"; + + /** + * Creates a validation consumer which is preloaded with the DTD provided. + * It does this by constructing a document with that DTD, then parsing + * that document and recording its DTD declarations. Then it arranges + * not to modify that information. + * + *

    The resulting validation consumer will only validate against + * the specified DTD, regardless of whether some other DTD is found + * in a document being parsed. + * + * @param rootName The name of the required root element; if this is + * null, any root element name will be accepted. + * @param publicId If non-null and there is a non-null systemId, this + * identifier provides an alternate access identifier for the DTD's + * external subset. + * @param systemId If non-null, this is a URI (normally URL) that + * may be used to access the DTD's external subset. + * @param internalSubset If non-null, holds literal markup declarations + * comprising the DTD's internal subset. + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param minimalElement If non-null, a minimal valid document. + * + * @exception SAXNotSupportedException If the default SAX parser does + * not support the standard lexical or declaration handlers. + * @exception SAXParseException If the specified DTD has either + * well-formedness or validity errors + * @exception IOException If the specified DTD can't be read for + * some reason + */ + public ValidationConsumer ( + String rootName, + String publicId, + String systemId, + String internalSubset, + EntityResolver resolver, + String minimalDocument + ) throws SAXException, IOException + { + this (null); + + disableReset = true; + if (rootName == null) + rootName = fakeRootName; + + // + // Synthesize document with that DTD; is it possible to do + // better for the declaration of the root element? + // + // NOTE: can't use SAX2 to write internal subsets. + // + StringWriter writer = new StringWriter (); + + writer.write (""); + } + if (internalSubset != null) + writer.write (internalSubset); + writer.write ("\n ]>"); + + if (minimalDocument != null) { + writer.write ("\n"); + writer.write (minimalDocument); + writer.write ("\n"); + } else { + writer.write (" <"); + writer.write (rootName); + writer.write ("/>\n"); + } + minimalDocument = writer.toString (); + + // + // OK, load it + // + XMLReader producer; + + producer = XMLReaderFactory.createXMLReader (); + bind (producer, this); + + if (resolver != null) + producer.setEntityResolver (resolver); + + InputSource in; + + in = new InputSource (new StringReader (minimalDocument)); + producer.parse (in); + + disableDeclarations = true; + if (rootName == fakeRootName) + this.rootName = null; + } + + private void resetState () + { + if (!disableReset) { + rootName = null; + contentStack.removeAllElements (); + elements.clear (); + ids.clear (); + + notations.removeAllElements (); + nDeferred.removeAllElements (); + unparsed.removeAllElements (); + uDeferred.removeAllElements (); + } + } + + + private void warning (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (errHandler == null) + return; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + errHandler.warning (err); + } + + // package private (for ChildrenRecognizer) + private void error (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + if (errHandler != null) + errHandler.error (err); + else // else we always treat it as fatal! + throw err; + } + + private void fatalError (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator != null) + err = new SAXParseException (description, locator); + else + err = new SAXParseException (description, null, null, -1, -1); + if (errHandler != null) + errHandler.fatalError (err); + // we always treat this as fatal, regardless of the handler + throw err; + } + + + private static boolean isExtender (char c) + { + // [88] Extender ::= ... + return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 + || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 + || (c >= 0x3031 && c <= 0x3035) + || (c >= 0x309d && c <= 0x309e) + || (c >= 0x30fc && c <= 0x30fe); + } + + + // use augmented Unicode rules, not full XML rules + private boolean isName (String name, String context, String id) + throws SAXException + { + char buf [] = name.toCharArray (); + boolean pass = true; + + if (!Character.isUnicodeIdentifierStart (buf [0]) + && ":_".indexOf (buf [0]) == -1) + pass = false; + else { + int max = buf.length; + for (int i = 1; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + name + "' is not a name"); + return pass; // true == OK + } + + // use augmented Unicode rules, not full XML rules + private boolean isNmtoken (String nmtoken, String context, String id) + throws SAXException + { + char buf [] = nmtoken.toCharArray (); + boolean pass = true; + int max = buf.length; + + // XXX make this share code with isName + + for (int i = 0; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + nmtoken + "' is not a name token"); + return pass; // true == OK + } + + private void checkEnumeration (String value, String type, String name) + throws SAXException + { + if (!hasMatch (value, type)) + // VC: Enumeration + error ("Value '" + value + + "' for attribute '" + name + + "' is not permitted: " + type); + } + + // used to test enumerated attributes and mixed content models + // package private + static boolean hasMatch (String value, String orList) + { + int len = value.length (); + int max = orList.length () - len; + + for (int start = 0; + (start = orList.indexOf (value, start)) != -1; + start++) { + char c; + + if (start > max) + break; + c = orList.charAt (start - 1); + if (c != '|' && c != '('/*)*/) + continue; + c = orList.charAt (start + len); + if (c != '|' && /*(*/ c != ')') + continue; + return true; + } + return false; + } + + /** + * LexicalHandler Records the declaration of the root + * element, so it can be verified later. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + rootName = name; + super.startDTD (name, publicId, systemId); + } + + /** + * LexicalHandler Verifies that all referenced notations + * and unparsed entities have been declared. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void endDTD () + throws SAXException + { + if (disableDeclarations) + return; + + // this is a convenient hook for end-of-dtd checks, but we + // could also trigger it in the first startElement call. + // locator info is more appropriate here though. + + // VC: Notation Declared (NDATA can refer to them before decls, + // as can NOTATION attribute enumerations and defaults) + int length = nDeferred.size (); + for (int i = 0; i < length; i++) { + String notation = (String) nDeferred.elementAt (i); + if (!notations.contains (notation)) { + error ("A declaration referred to notation '" + notation + + "' which was never declared"); + } + } + nDeferred.removeAllElements (); + + // VC: Entity Name (attribute values can refer to them + // before they're declared); VC Attribute Default Legal + length = uDeferred.size (); + for (int i = 0; i < length; i++) { + String entity = (String) uDeferred.elementAt (i); + if (!unparsed.contains (entity)) { + error ("An attribute default referred to entity '" + entity + + "' which was never declared"); + } + } + uDeferred.removeAllElements (); + super.endDTD (); + } + + + // These are interned, so we can rely on "==" to find the type of + // all attributes except enumerations ... + // "(this|or|that|...)" and "NOTATION (this|or|that|...)" + static final String types [] = { + "CDATA", + "ID", "IDREF", "IDREFS", + "NMTOKEN", "NMTOKENS", + "ENTITY", "ENTITIES" + }; + + + /** + * DecllHandler Records attribute declaration for later use + * in validating document content, and checks validity constraints + * that are applicable to attribute declarations. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (eName); + AttributeInfo ainfo = new AttributeInfo (); + boolean checkOne = false; + boolean interned = false; + + // cheap interning of type names and #FIXED, #REQUIRED + // for faster startElement (we can use "==") + for (int i = 0; i < types.length; i++) { + if (types [i].equals (type)) { + type = types [i]; + interned = true; + break; + } + } + if ("#FIXED".equals (mode)) + mode = "#FIXED"; + else if ("#REQUIRED".equals (mode)) + mode = "#REQUIRED"; + + ainfo.type = type; + ainfo.mode = mode; + ainfo.value = value; + + // we might not have seen the content model yet + if (info == null) { + info = new ElementInfo (eName); + elements.put (eName, info); + } + if ("ID" == type) { + checkOne = true; + if (!("#REQUIRED" == mode || "#IMPLIED".equals (mode))) { + // VC: ID Attribute Default + error ("ID attribute '" + aName + + "' must be #IMPLIED or #REQUIRED"); + } + + } else if (!interned && type.startsWith ("NOTATION ")) { + checkOne = true; + + // VC: Notation Attributes (notations must be declared) + StringTokenizer tokens = new StringTokenizer ( + type.substring (10, type.lastIndexOf (')')), + "|"); + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + if (!notations.contains (token)) + nDeferred.addElement (token); + } + } + if (checkOne) { + for (Enumeration e = info.attributes.keys (); + e.hasMoreElements (); + /* NOP */) { + String name; + AttributeInfo ainfo2; + + name = (String) e.nextElement (); + ainfo2 = (AttributeInfo) info.attributes.get (name); + if (type == ainfo2.type || !interned /* NOTATION */) { + // VC: One ID per Element Type + // VC: One Notation per Element TYpe + error ("Element '" + eName + + "' already has an attribute of type " + + (interned ? "NOTATION" : type) + + " ('" + name + + "') so '" + aName + + "' is a validity error"); + } + } + } + + // VC: Attribute Default Legal + if (value != null) { + + if ("CDATA" == type) { + // event source rejected '<' + + } else if ("NMTOKEN" == type) { + // VC: Name Token (is a nmtoken) + isNmtoken (value, "attribute default", aName); + + } else if ("NMTOKENS" == type) { + // VC: Name Token (is a nmtoken; at least one value) + StringTokenizer tokens = new StringTokenizer (value); + if (!tokens.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name token."); + else do { + String token = tokens.nextToken (); + isNmtoken (token, "attribute default", aName); + } while (tokens.hasMoreTokens ()); + + } else if ("IDREF" == type || "ENTITY" == type) { + // VC: Entity Name (is a name) + // VC: IDREF (is a name) (is declared) + isName (value, "attribute default", aName); + if ("ENTITY" == type && !unparsed.contains (value)) + uDeferred.addElement (value); + + } else if ("IDREFS" == type || "ENTITIES" == type) { + // VC: Entity Name (is a name; at least one value) + // VC: IDREF (is a name; at least one value) + StringTokenizer names = new StringTokenizer (value); + if (!names.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name."); + else do { + String name = names.nextToken (); + isName (name, "attribute default", aName); + if ("ENTITIES" == type && !unparsed.contains (name)) + uDeferred.addElement (value); + } while (names.hasMoreTokens ()); + + } else if (type.charAt (0) == '(' /*)*/ ) { + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if (!interned && checkOne) { /* NOTATION */ + // VC: Notation attributes (must be names) + isName (value, "attribute default", aName); + + // VC: Notation attributes (must be declared) + if (!notations.contains (value)) + nDeferred.addElement (value); + + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if ("ID" != type) + throw new RuntimeException ("illegal attribute type: " + type); + } + + if (info.attributes.get (aName) == null) + info.attributes.put (aName, ainfo); + /* + else + warning ("Element '" + eName + + "' already has an attribute named '" + aName + "'"); + */ + + if ("xml:space".equals (aName)) { + if (!("(default|preserve)".equals (type) + || "(preserve|default)".equals (type) + // these next two are arguable; XHTML's DTD doesn't + // deserve errors. After all, it's not like any + // illegal _value_ could pass ... + || "(preserve)".equals (type) + || "(default)".equals (type) + )) + error ( + "xml:space attribute type must be like '(default|preserve)'" + + " not '" + type + "'" + ); + + } + super.attributeDecl (eName, aName, type, mode, value); + } + + /** + * DecllHandler Records the element declaration for later use + * when checking document content, and checks validity constraints that + * apply to element declarations. Passed to the next consumer, unless + * this one was preloaded with a particular DTD. + */ + public void elementDecl (String name, String model) + throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (name); + + // we might have seen an attribute decl already + if (info == null) { + info = new ElementInfo (name); + elements.put (name, info); + } + if (info.model != null) { + // NOTE: not all parsers can report such duplicates. + // VC: Unique Element Type Declaration + error ("Element type '" + name + + "' was already declared."); + } else { + info.model = model; + + // VC: No Duplicate Types (in mixed content models) + if (model.charAt (1) == '#') // (#PCDATA... + info.getRecognizer (this); + } + super.elementDecl (name, model); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (!disableDeclarations) + super.internalEntityDecl (name, value); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (!disableDeclarations) + super.externalEntityDecl (name, publicId, systemId); + } + + + /** + * DTDHandler Records the notation name, for checking + * NOTATIONS attribute values and declararations of unparsed + * entities. Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + notations.addElement (name); + super.notationDecl (name, publicId, systemId); + } + + /** + * DTDHandler Records the entity name, for checking + * ENTITY and ENTITIES attribute values; records the notation + * name if it hasn't yet been declared. Passed to the next consumer, + * unless this one was preloaded with a particular DTD. + */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (disableDeclarations) + return; + + unparsed.addElement (name); + if (!notations.contains (notationName)) + nDeferred.addElement (notationName); + super.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + /** + * ContentHandler Ensures that state from any previous parse + * has been deleted. + * Passed to the next consumer. + */ + public void startDocument () + throws SAXException + { + resetState (); + super.startDocument (); + } + + + private static boolean isAsciiLetter (char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + + /** + * ContentHandler Reports a fatal exception. Validating + * XML processors may not skip any entities. + */ + public void skippedEntity (String name) + throws SAXException + { + fatalError ("may not skip entities"); + } + + /* + * SAX2 doesn't expand non-PE refs in attribute defaults... + */ + private String expandDefaultRefs (String s) + throws SAXException + { + if (s.indexOf ('&') < 0) + return s; + +// FIXME: handle &#nn; &#xnn; &name; + String message = "Can't expand refs in attribute default: " + s; + warning (message); + + return s; + } + + /** + * ContentHandler Performs validity checks against element + * (and document) content models, and attribute values. + * Passed to the next consumer. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // + // First check content model for the enclosing scope. + // + if (contentStack.isEmpty ()) { + // VC: Root Element Type + if (!qName.equals (rootName)) { + if (rootName == null) + warning ("This document has no DTD, can't be valid"); + else + error ("Root element type '" + qName + + "' was declared to be '" + rootName + "'"); + } + } else { + Recognizer state = (Recognizer) contentStack.peek (); + + if (state != null) { + Recognizer newstate = state.acceptElement (qName); + + if (newstate == null) + error ("Element type '" + qName + + "' in element '" + state.type.name + + "' violates content model " + state.type.model + ); + if (newstate != state) { + contentStack.pop (); + contentStack.push (newstate); + } + } + } + + // + // Then check that this element was declared, and push the + // object used to validate its content model onto our stack. + // + // This is where the recognizer gets created, if needed; if + // it's a "children" (elements) content model, an NDFA is + // created. (One recognizer is used per content type, no + // matter how complex that recognizer is.) + // + ElementInfo info; + + info = (ElementInfo) elements.get (qName); + if (info == null || info.model == null) { + // VC: Element Valid (base clause) + error ("Element type '" + qName + "' was not declared"); + contentStack.push (null); + + // for less diagnostic noise, fake a declaration. + elementDecl (qName, "ANY"); + } else + contentStack.push (info.getRecognizer (this)); + + // + // Then check each attribute present + // + int len; + String aname; + AttributeInfo ainfo; + + if (atts != null) + len = atts.getLength (); + else + len = 0; + + for (int i = 0; i < len; i++) { + aname = atts.getQName (i); + + if (info == null + || (ainfo = (AttributeInfo) info.attributes.get (aname)) + == null) { + // VC: Attribute Value Type + error ("Attribute '" + aname + + "' was not declared for element type " + qName); + continue; + } + + String value = atts.getValue (i); + + // note that "==" for type names and "#FIXED" is correct + // (and fast) since we've interned those literals. + + if ("#FIXED" == ainfo.mode) { + String expanded = expandDefaultRefs (ainfo.value); + + // VC: Fixed Attribute Default + if (!value.equals (expanded)) { + error ("Attribute '" + aname + + "' must match " + expanded + ); + continue; + } + } + + if ("CDATA" == ainfo.type) + continue; + + // + // For all other attribute types, there are various + // rules to follow. + // + + if ("ID" == ainfo.type) { + // VC: ID (must be a name) + if (isName (value, "ID attribute", aname)) { + if (Boolean.TRUE == ids.get (value)) + // VC: ID (appears once) + error ("ID attribute " + aname + + " uses an ID value '" + value + + "' which was already declared."); + else + // any forward refs are no longer problems + ids.put (value, Boolean.TRUE); + } + continue; + } + + if ("IDREF" == ainfo.type) { + // VC: IDREF (value must be a name) + if (isName (value, "IDREF attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (value) == null) + // new -- assume it's a forward ref + ids.put (value, Boolean.FALSE); + } + continue; + } + + if ("IDREFS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: IDREF (one or more values) + error ("IDREFS attribute " + aname + + " must have at least one ID ref"); + } else do { + String id = tokens.nextToken (); + + // VC: IDREF (value must be a name) + if (isName (id, "IDREFS attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (id) == null) + // new -- assume it's a forward ref + ids.put (id, Boolean.FALSE); + } + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("NMTOKEN" == ainfo.type) { + // VC: Name Token (is a name token) + isNmtoken (value, "NMTOKEN attribute", aname); + continue; + } + + if ("NMTOKENS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Name Token (one or more values) + error ("NMTOKENS attribute " + aname + + " must have at least one name token"); + } else do { + String token = tokens.nextToken (); + + // VC: Name Token (is a name token) + isNmtoken (token, "NMTOKENS attribute", aname); + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("ENTITY" == ainfo.type) { + if (!unparsed.contains (value)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + value + + "' which was not declared."); + continue; + } + + if ("ENTITIES" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Entity Name (one or more values) + error ("ENTITIES attribute " + aname + + " must have at least one name token"); + } else do { + String entity = tokens.nextToken (); + + if (!unparsed.contains (entity)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + entity + + "' which was not declared."); + } while (tokens.hasMoreTokens ()); + continue; + } + + // + // check for enumerations last; more expensive + // + if (ainfo.type.charAt (0) == '(' /*)*/ + || ainfo.type.startsWith ("NOTATION ") + ) { + // VC: Enumeration (value must be defined) + checkEnumeration (value, ainfo.type, aname); + continue; + } + } + + // + // Last, check that all #REQUIRED attributes were provided + // + if (info != null) { + Hashtable table = info.attributes; + + if (table.size () != 0) { + Enumeration e = table.keys (); + + // XXX table.keys uses the heap, bleech -- slows things + + while (e.hasMoreElements ()) { + aname = (String) e.nextElement (); + ainfo = (AttributeInfo) table.get (aname); + + // "#REQUIRED" mode was interned in attributeDecl + if ("#REQUIRED" == ainfo.mode + && atts.getValue (aname) == null) { + // VC: Required Attribute + error ("Attribute '" + aname + "' must be specified " + + "for element type " + qName); + } + } + } + } + super.startElement (uri, localName, qName, atts); + } + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit character data. + * Passed to the next consumer. + */ + public void characters (char ch [], int start, int length) + throws SAXException + { + Recognizer state; + + if (contentStack.empty ()) + state = null; + else + state = (Recognizer) contentStack.peek (); + + // NOTE: if this ever supports with SAX parsers that don't + // report ignorable whitespace as such (only XP?), this class + // needs to morph it into ignorableWhitespace() as needed ... + + if (state != null && !state.acceptCharacters ()) + // VC: Element Valid (clauses three, four -- see recognizer) + error ("Character content not allowed in element " + + state.type.name); + + super.characters (ch, start, length); + } + + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit end-of-element yet, or a well formedness error + * if there was no matching startElement call. + * Passed to the next consumer. + */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + try { + Recognizer state = (Recognizer) contentStack.pop (); + + if (state != null && !state.completed ()) + // VC: Element valid (clauses two, three, four; see Recognizer) + error ("Premature end for element '" + + state.type.name + + "', content model " + + state.type.model); + + // could insist on match of start element, but that's + // something the input stream must to guarantee. + + } catch (EmptyStackException e) { + fatalError ("endElement without startElement: " + qName + + ((uri == null) + ? "" + : ( " { '" + uri + "', " + localName + " }"))); + } + super.endElement (uri, localName, qName); + } + + /** + * ContentHandler Checks whether all ID values that were + * referenced have been declared, and releases all resources. + * Passed to the next consumer. + * + * @see #setDocumentLocator + */ + public void endDocument () + throws SAXException + { + for (Enumeration idNames = ids.keys (); + idNames.hasMoreElements (); + /* NOP */) { + String id = (String) idNames.nextElement (); + + if (Boolean.FALSE == ids.get (id)) { + // VC: IDREF (must match ID) + error ("Undeclared ID value '" + id + + "' was referred to by an IDREF/IDREFS attribute"); + } + } + + resetState (); + super.endDocument (); + } + + + /** Holds per-element declarations */ + static private final class ElementInfo + { + String name; + String model; + + // key = attribute name; value = AttributeInfo + Hashtable attributes = new Hashtable (11); + + ElementInfo (String n) { name = n; } + + private Recognizer recognizer; + + // for validating content models: one per type, shared, + // and constructed only on demand ... so unused elements do + // not need to consume resources. + Recognizer getRecognizer (ValidationConsumer consumer) + throws SAXException + { + if (recognizer == null) { + if ("ANY".equals (model)) + recognizer = ANY; + else if ("EMPTY".equals (model)) + recognizer = new EmptyRecognizer (this); + else if ('#' == model.charAt (1)) + // n.b. this constructor does a validity check + recognizer = new MixedRecognizer (this, consumer); + else + recognizer = new ChildrenRecognizer (this, consumer); + } + return recognizer; + } + } + + /** Holds per-attribute declarations */ + static private final class AttributeInfo + { + String type; + String mode; // #REQUIRED, etc (or null) + String value; // or null + } + + + // + // Content model validation + // + + static private final Recognizer ANY = new Recognizer (null); + + + // Base class defines the calls used to validate content, + // and supports the "ANY" content model + static private class Recognizer + { + final ElementInfo type; + + Recognizer (ElementInfo t) { type = t; } + + // return true iff character data is legal here + boolean acceptCharacters () + throws SAXException + // VC: Element Valid (third and fourth clauses) + { return true; } + + // null return = failure + // otherwise, next state (like an FSM) + // prerequisite: tested that name was declared + Recognizer acceptElement (String name) + throws SAXException + // VC: Element Valid (fourth clause) + { return this; } + + // return true iff model is completed, can finish + boolean completed () + throws SAXException + // VC: Element Valid (fourth clause) + { return true; } + + public String toString () + // n.b. "children" is the interesting case! + { return (type == null) ? "ANY" : type.model; } + } + + // "EMPTY" content model -- no characters or elements + private static final class EmptyRecognizer extends Recognizer + { + public EmptyRecognizer (ElementInfo type) + { super (type); } + + // VC: Element Valid (first clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (first clause) + Recognizer acceptElement (String name) + { return null; } + } + + // "Mixed" content model -- ANY, but restricts elements + private static final class MixedRecognizer extends Recognizer + { + private String permitted []; + + // N.B. constructor tests for duplicated element names (VC) + public MixedRecognizer (ElementInfo t, ValidationConsumer v) + throws SAXException + { + super (t); + + // (#PCDATA...)* or (#PCDATA) ==> ... or empty + // with the "..." being "|elname|..." + StringTokenizer tokens = new StringTokenizer ( + t.model.substring (8, t.model.lastIndexOf (')')), + "|"); + Vector vec = new Vector (); + + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + + if (vec.contains (token)) + v.error ("element " + token + + " is repeated in mixed content model: " + + t.model); + else + vec.addElement (token.intern ()); + } + permitted = new String [vec.size ()]; + for (int i = 0; i < permitted.length; i++) + permitted [i] = (String) vec.elementAt (i); + + // in one large machine-derived DTD sample, most of about + // 250 mixed content models were empty, and 25 had ten or + // more entries. 2 had over a hundred elements. Linear + // search isn't obviously wrong. + } + + // VC: Element Valid (third clause) + Recognizer acceptElement (String name) + { + int length = permitted.length; + + // first pass -- optimistic w.r.t. event source interning + // (and document validity) + for (int i = 0; i < length; i++) + if (permitted [i] == name) + return this; + // second pass -- pessimistic w.r.t. event source interning + for (int i = 0; i < length; i++) + if (permitted [i].equals (name)) + return this; + return null; + } + } + + + // recognizer loop flags, see later + private static final int F_LOOPHEAD = 0x01; + private static final int F_LOOPNEXT = 0x02; + + // for debugging -- used to label/count nodes in toString() + private static int nodeCount; + + /** + * "Children" content model -- these are nodes in NDFA state graphs. + * They work in fixed space. Note that these graphs commonly have + * cycles, handling features such as zero-or-more and one-or-more. + * + *

    It's readonly, so only one copy is ever needed. The content model + * stack may have any number of pointers into each graph, when a model + * happens to be needed more than once due to element nesting. Since + * traversing the graph just moves to another node, and never changes + * it, traversals never interfere with each other. + * + *

    There is an option to report non-deterministic models. These are + * always XML errors, but ones which are not often reported despite the + * fact that they can lead to different validating parsers giving + * different results for the same input. (The XML spec doesn't require + * them to be reported.) + * + *

    FIXME There's currently at least one known bug here, in that + * it's not actually detecting the non-determinism it tries to detect. + * (Of the "optional.xml" test, the once-or-twice-2* tests are all non-D; + * maybe some others.) This may relate to the issue flagged below as + * "should not" happen (but it was), which showed up when patching the + * graph to have one exit node (or more EMPTY nodes). + */ + private static final class ChildrenRecognizer extends Recognizer + implements Cloneable + { + // for reporting non-deterministic content models + // ... a waste of space if we're not reporting those! + // ... along with the 'model' member (in base class) + private ValidationConsumer consumer; + + // for CHOICE nodes -- each component is an arc that + // accepts a different NAME (or is EMPTY indicating + // NDFA termination). + private Recognizer components []; + + // for NAME/SEQUENCE nodes -- accepts that NAME and + // then goes to the next node (CHOICE, NAME, EMPTY). + private String name; + private Recognizer next; + + // loops always point back to a CHOICE node. we mark such choice + // nodes (F_LOOPHEAD) for diagnostics and faster deep cloning. + // We also mark nodes before back pointers (F_LOOPNEXT), to ensure + // termination when we patch sequences and loops. + private int flags; + + + // prevent a needless indirection between 'this' and 'node' + private void copyIn (ChildrenRecognizer node) + { + // model & consumer are already set + components = node.components; + name = node.name; + next = node.next; + flags = node.flags; + } + + // used to construct top level "children" content models, + public ChildrenRecognizer (ElementInfo type, ValidationConsumer vc) + { + this (vc, type); + populate (type.model.toCharArray (), 0); + patchNext (new EmptyRecognizer (type), null); + } + + // used internally; populating is separate + private ChildrenRecognizer (ValidationConsumer vc, ElementInfo type) + { + super (type); + consumer = vc; + } + + + // + // When rewriting some graph nodes we need deep clones in one case; + // mostly shallow clones (what the JVM handles for us) are fine. + // + private ChildrenRecognizer shallowClone () + { + try { + return (ChildrenRecognizer) clone (); + } catch (CloneNotSupportedException e) { + throw new Error ("clone"); + } + } + + private ChildrenRecognizer deepClone () + { + return deepClone (new Hashtable (37)); + } + + private ChildrenRecognizer deepClone (Hashtable table) + { + ChildrenRecognizer retval; + + if ((flags & F_LOOPHEAD) != 0) { + retval = (ChildrenRecognizer) table.get (this); + if (retval != null) + return this; + + retval = shallowClone (); + table.put (this, retval); + } else + retval = shallowClone (); + + if (next != null) { + if (next instanceof ChildrenRecognizer) + retval.next = ((ChildrenRecognizer)next) + .deepClone (table); + else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + + if (components != null) { + retval.components = new Recognizer [components.length]; + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i]; + + if (temp == null) + retval.components [i] = null; + else if (temp instanceof ChildrenRecognizer) + retval.components [i] = ((ChildrenRecognizer)temp) + .deepClone (table); + else if (!(temp instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + } + + return retval; + } + + // connect subgraphs, first to next (sequencing) + private void patchNext (Recognizer theNext, Hashtable table) + { + // backpointers must not be repatched or followed + if ((flags & F_LOOPNEXT) != 0) + return; + + // XXX this table "shouldn't" be needed, right? + // but some choice nodes looped if it isn't there. + if (table != null && table.get (this) != null) + return; + if (table == null) + table = new Hashtable (); + + // NAME/SEQUENCE + if (name != null) { + if (next == null) + next = theNext; + else if (next instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)next).patchNext (theNext, table); + } else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + return; + } + + // CHOICE + for (int i = 0; i < components.length; i++) { + if (components [i] == null) + components [i] = theNext; + else if (components [i] instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)components [i]) + .patchNext (theNext, table); + } else if (!(components [i] instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + } + + if (table != null && (flags & F_LOOPHEAD) != 0) + table.put (this, this); + } + + /** + * Parses a 'children' spec (or recursively 'cp') and makes this + * become a regular graph node. + * + * @return index after this particle + */ + private int populate (char parseBuf [], int startPos) + { + int nextPos = startPos + 1; + char c; + + if (nextPos < 0 || nextPos >= parseBuf.length) + throw new IndexOutOfBoundsException (); + + // Grammar of the string is from the XML spec, but + // with whitespace removed by the SAX parser. + + // children ::= (choice | seq) ('?' | '*' | '+')? + // cp ::= (Name | choice | seq) ('?' | '*' | '+')? + // choice ::= '(' cp ('|' choice)* ')' + // seq ::= '(' cp (',' choice)* ')' + + // interior nodes only + // cp ::= name ... + if (parseBuf [startPos] != '('/*)*/) { + boolean done = false; + do { + switch (c = parseBuf [nextPos]) { + case '?': case '*': case '+': + case '|': case ',': + case /*(*/ ')': + done = true; + continue; + default: + nextPos++; + continue; + } + } while (!done); + name = new String (parseBuf, startPos, nextPos - startPos); + + // interior OR toplevel nodes + // cp ::= choice .. + // cp ::= seq .. + } else { + // collect everything as a separate list, and merge it + // into "this" later if we can (SEQUENCE or singleton) + ChildrenRecognizer first; + + first = new ChildrenRecognizer (consumer, type); + nextPos = first.populate (parseBuf, nextPos); + c = parseBuf [nextPos++]; + + if (c == ',' || c == '|') { + ChildrenRecognizer current = first; + char separator = c; + Vector v = null; + + if (separator == '|') { + v = new Vector (); + v.addElement (first); + } + + do { + ChildrenRecognizer link; + + link = new ChildrenRecognizer (consumer, type); + nextPos = link.populate (parseBuf, nextPos); + + if (separator == ',') { + current.patchNext (link, null); + current = link; + } else + v.addElement (link); + + c = parseBuf [nextPos++]; + } while (c == separator); + + // choice ... collect everything into one array. + if (separator == '|') { + // assert v.size() > 1 + components = new Recognizer [v.size ()]; + for (int i = 0; i < components.length; i++) { + components [i] = (Recognizer) + v.elementAt (i); + } + // assert flags == 0 + + // sequence ... merge into "this" to be smaller. + } else + copyIn (first); + + // treat singletons like one-node sequences. + } else + copyIn (first); + + if (c != /*(*/ ')') + throw new RuntimeException ("corrupt content model"); + } + + // + // Arity is optional, and the root of all fun. We keep the + // FSM state graph simple by only having NAME/SEQUENCE and + // CHOICE nodes (or EMPTY to terminate a model), easily + // evaluated. So we rewrite each node that has arity, using + // those primitives. We create loops here, if needed. + // + if (nextPos < parseBuf.length) { + c = parseBuf [nextPos]; + if (c == '?' || c == '*' || c == '+') { + nextPos++; + + // Rewrite 'zero-or-one' "?" arity to a CHOICE: + // - SEQUENCE (clone, what's next) + // - or, what's next + // Size cost: N --> N + 1 + if (c == '?') { + Recognizer once = shallowClone (); + + components = new Recognizer [2]; + components [0] = once; + // components [1] initted to null + name = null; + next = null; + flags = 0; + + + // Rewrite 'zero-or-more' "*" arity to a CHOICE. + // - LOOP (clone, back to this CHOICE) + // - or, what's next + // Size cost: N --> N + 1 + } else if (c == '*') { + ChildrenRecognizer loop = shallowClone (); + + loop.patchNext (this, null); + loop.flags |= F_LOOPNEXT; + flags = F_LOOPHEAD; + + components = new Recognizer [2]; + components [0] = loop; + // components [1] initted to null + name = null; + next = null; + + + // Rewrite 'one-or-more' "+" arity to a SEQUENCE. + // Basically (a)+ --> ((a),(a)*). + // - this + // - CHOICE + // * LOOP (clone, back to the CHOICE) + // * or, whatever's next + // Size cost: N --> 2N + 1 + } else if (c == '+') { + ChildrenRecognizer loop = deepClone (); + ChildrenRecognizer choice; + + choice = new ChildrenRecognizer (consumer, type); + loop.patchNext (choice, null); + loop.flags |= F_LOOPNEXT; + choice.flags = F_LOOPHEAD; + + choice.components = new Recognizer [2]; + choice.components [0] = loop; + // choice.components [1] initted to null + // choice.name, choice.next initted to null + + patchNext (choice, null); + } + } + } + + return nextPos; + } + + // VC: Element Valid (second clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (second clause) + Recognizer acceptElement (String type) + throws SAXException + { + // NAME/SEQUENCE + if (name != null) { + if (name.equals (type)) + return next; + return null; + } + + // CHOICE ... optionally reporting nondeterminism we + // run across. we won't check out every transition + // for nondeterminism; only the ones we follow. + Recognizer retval = null; + + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i].acceptElement (type); + + if (temp == null) + continue; + else if (!warnNonDeterministic) + return temp; + else if (retval == null) + retval = temp; + else if (retval != temp) + consumer.error ("Content model " + this.type.model + + " is non-deterministic for " + type); + } + return retval; + } + + // VC: Element Valid (second clause) + boolean completed () + throws SAXException + { + // expecting a specific element + if (name != null) + return false; + + // choice, some sequences + for (int i = 0; i < components.length; i++) { + if (components [i].completed ()) + return true; + } + + return false; + } + +/** / + // FOR DEBUGGING ... flattens the graph for printing. + + public String toString () + { + StringBuffer buf = new StringBuffer (); + + // only one set of loop labels can be generated + // at a time... + synchronized (ANY) { + nodeCount = 0; + + toString (buf, new Hashtable ()); + return buf.toString (); + } + } + + private void toString (StringBuffer buf, Hashtable table) + { + // When we visit a node, label and count it. + // Nodes are never visited/counted more than once. + // For small models labels waste space, but if arity + // mappings were used the savings are substantial. + // (Plus, the output can be more readily understood.) + String temp = (String) table.get (this); + + if (temp != null) { + buf.append ('{'); + buf.append (temp); + buf.append ('}'); + return; + } else { + StringBuffer scratch = new StringBuffer (15); + + if ((flags & F_LOOPHEAD) != 0) + scratch.append ("loop"); + else + scratch.append ("node"); + scratch.append ('-'); + scratch.append (++nodeCount); + temp = scratch.toString (); + + table.put (this, temp); + buf.append ('['); + buf.append (temp); + buf.append (']'); + buf.append (':'); + } + + // NAME/SEQUENCE + if (name != null) { + // n.b. some output encodings turn some name chars into '?' + // e.g. with Japanese names and ASCII output + buf.append (name); + if (components != null) // bug! + buf.append ('$'); + if (next == null) + buf.append (",*"); + else if (next instanceof EmptyRecognizer) // patch-to-next + buf.append (",{}"); + else if (next instanceof ChildrenRecognizer) { + buf.append (','); + ((ChildrenRecognizer)next).toString (buf, table); + } else // bug! + buf.append (",+"); + return; + } + + // CHOICE + buf.append ("<"); + for (int i = 0; i < components.length; i++) { + if (i != 0) + buf.append ("|"); + if (components [i] instanceof EmptyRecognizer) { + buf.append ("{}"); + } else if (components [i] == null) { // patch-to-next + buf.append ('*'); + } else { + ChildrenRecognizer r; + + r = (ChildrenRecognizer) components [i]; + r.toString (buf, table); + } + } + buf.append (">"); + } +/**/ + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java new file mode 100644 index 000000000..7a3db6593 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java @@ -0,0 +1,363 @@ +/* WellFormednessFilter.java -- + Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.util.EmptyStackException; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * This filter reports fatal exceptions in the case of event streams that + * are not well formed. The rules currently tested include:

    + * + *

    Other checks for event stream correctness may be provided in + * the future. For example, insisting that + * entity boundaries nest correctly, + * namespace scopes nest correctly, + * namespace values never contain relative URIs, + * attributes don't have "<" characters; + * and more. + * + * @author David Brownell + */ +public final class WellFormednessFilter extends EventFilter +{ + private boolean startedDoc; + private Stack elementStack = new Stack (); + private boolean startedCDATA; + private String dtdState = "before"; + + + /** + * Swallows all events after performing well formedness checks. + */ + // constructor used by PipelineFactory + public WellFormednessFilter () + { this (null); } + + + /** + * Passes events through to the specified consumer, after first + * processing them. + */ + // constructor used by PipelineFactory + public WellFormednessFilter (EventConsumer consumer) + { + super (consumer); + + setContentHandler (this); + setDTDHandler (this); + + try { + setProperty (LEXICAL_HANDLER, this); + } catch (SAXException e) { /* can't happen */ } + } + + /** + * Resets state as if any preceding event stream was well formed. + * Particularly useful if it ended through some sort of error, + * and the endDocument call wasn't made. + */ + public void reset () + { + startedDoc = false; + startedCDATA = false; + elementStack.removeAllElements (); + } + + + private SAXParseException getException (String message) + { + SAXParseException e; + Locator locator = getDocumentLocator (); + + if (locator == null) + return new SAXParseException (message, null, null, -1, -1); + else + return new SAXParseException (message, locator); + } + + private void fatalError (String message) + throws SAXException + { + SAXParseException e = getException (message); + ErrorHandler handler = getErrorHandler (); + + if (handler != null) + handler.fatalError (e); + throw e; + } + + /** + * Throws an exception when called after startDocument. + * + * @param locator the locator, to be used in error reporting or relative + * URI resolution. + * + * @exception IllegalStateException when called after the document + * has already been started + */ + public void setDocumentLocator (Locator locator) + { + if (startedDoc) + throw new IllegalStateException ( + "setDocumentLocator called after startDocument"); + super.setDocumentLocator (locator); + } + + public void startDocument () throws SAXException + { + if (startedDoc) + fatalError ("startDocument called more than once"); + startedDoc = true; + startedCDATA = false; + elementStack.removeAllElements (); + super.startDocument (); + } + + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("inside".equals (dtdState)) + fatalError ("element inside DTD?"); + else + dtdState = "after"; + if (startedCDATA) + fatalError ("element inside CDATA section"); + if (qName == null || "".equals (qName)) + fatalError ("startElement name missing"); + elementStack.push (qName); + super.startElement (uri, localName, qName, atts); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("element inside CDATA section"); + if (qName == null || "".equals (qName)) + fatalError ("endElement name missing"); + + try { + String top = (String) elementStack.pop (); + + if (!qName.equals (top)) + fatalError ("<" + top + " ...>..."); + // XXX could record/test namespace info + } catch (EmptyStackException e) { + fatalError ("endElement without startElement: "); + } + super.endElement (uri, localName, qName); + } + + public void endDocument () throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + dtdState = "before"; + startedDoc = false; + super.endDocument (); + } + + + public void startDTD (String root, String publicId, String systemId) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("before" != dtdState) + fatalError ("two DTDs?"); + if (!elementStack.empty ()) + fatalError ("DTD must precede root element"); + dtdState = "inside"; + super.startDTD (root, publicId, systemId); + } + + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { +// FIXME: not all parsers will report startDTD() ... +// we'd rather insist we're "inside". + if ("after" == dtdState) + fatalError ("not inside DTD"); + super.notationDecl (name, publicId, systemId); + } + + public void unparsedEntityDecl (String name, + String publicId, String systemId, String notationName) + throws SAXException + { +// FIXME: not all parsers will report startDTD() ... +// we'd rather insist we're "inside". + if ("after" == dtdState) + fatalError ("not inside DTD"); + super.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + // FIXME: add the four DeclHandler calls too + + public void endDTD () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("inside" != dtdState) + fatalError ("DTD ends without start?"); + dtdState = "after"; + super.endDTD (); + } + + public void characters (char ch [], int start, int length) + throws SAXException + { + int here = start, end = start + length; + if (elementStack.empty ()) + fatalError ("characters must be in an element"); + while (here < end) { + if (ch [here++] != ']') + continue; + if (here == end) // potential problem ... + continue; + if (ch [here++] != ']') + continue; + if (here == end) // potential problem ... + continue; + if (ch [here++] == '>') + fatalError ("character data can't contain \"]]>\""); + } + super.characters (ch, start, length); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + int here = start, end = start + length; + if (elementStack.empty ()) + fatalError ("characters must be in an element"); + while (here < end) { + if (ch [here++] == '\r') + fatalError ("whitespace can't contain CR"); + } + super.ignorableWhitespace (ch, start, length); + } + + public void processingInstruction (String target, String data) + throws SAXException + { + if (data.indexOf ('\r') > 0) + fatalError ("PIs can't contain CR"); + if (data.indexOf ("?>") > 0) + fatalError ("PIs can't contain \"?>\""); + } + + public void comment (char ch [], int start, int length) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("comments can't nest in CDATA"); + int here = start, end = start + length; + while (here < end) { + if (ch [here] == '\r') + fatalError ("comments can't contain CR"); + if (ch [here++] != '-') + continue; + if (here == end) + fatalError ("comments can't end with \"--->\""); + if (ch [here++] == '-') + fatalError ("comments can't contain \"--\""); + } + super.comment (ch, start, length); + } + + public void startCDATA () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("CDATA starts can't nest"); + startedCDATA = true; + super.startCDATA (); + } + + public void endCDATA () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (!startedCDATA) + fatalError ("CDATA end without start?"); + startedCDATA = false; + super.endCDATA (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java new file mode 100644 index 000000000..a1445fa0c --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java @@ -0,0 +1,579 @@ +/* XIncludeFilter.java -- + Copyright (C) 2001,2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Hashtable; +import java.util.Stack; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import gnu.xml.util.Resolver; + + + +/** + * Filter to process an XPointer-free subset of + * XInclude, supporting its + * use as a kind of replacement for parsed general entities. + * XInclude works much like the #include of C/C++ but + * works for XML documents as well as unparsed text files. + * Restrictions from the 17-Sept-2002 CR draft of XInclude are as follows: + * + *

    + * + *

    XML documents that are included will normally be processed using + * the default SAX namespace rules, meaning that prefix information may + * be discarded. This may be changed with {@link #setSavingPrefixes + * setSavingPrefixes()}. You are strongly advised to do this. + * + *

    Note that XInclude allows highly incompatible implementations, which + * are specialized to handle application-specific infoset extensions. Some + * such implementations can be implemented by subclassing this one, but + * they may only be substituted in applications at "user option". + * + *

    TBD: "IURI" handling. + * + * @author David Brownell + */ +public class XIncludeFilter extends EventFilter implements Locator +{ + private Hashtable extEntities = new Hashtable (5, 5); + private int ignoreCount; + private Stack uris = new Stack (); + private Locator locator; + private Vector inclusions = new Vector (5, 5); + private boolean savingPrefixes; + + /** + */ + public XIncludeFilter (EventConsumer next) + throws SAXException + { + super (next); + setContentHandler (this); + // DTDHandler callbacks pass straight through + setProperty (DECL_HANDLER, this); + setProperty (LEXICAL_HANDLER, this); + } + + private void fatal (SAXParseException e) throws SAXException + { + ErrorHandler eh; + + eh = getErrorHandler (); + if (eh != null) + eh.fatalError (e); + throw e; + } + + /** + * Passes "this" down the filter chain as a proxy locator. + */ + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + super.setDocumentLocator (this); + } + + /** Used for proxy locator; do not call directly. */ + public String getSystemId () + { return (locator == null) ? null : locator.getSystemId (); } + /** Used for proxy locator; do not call directly. */ + public String getPublicId () + { return (locator == null) ? null : locator.getPublicId (); } + /** Used for proxy locator; do not call directly. */ + public int getLineNumber () + { return (locator == null) ? -1 : locator.getLineNumber (); } + /** Used for proxy locator; do not call directly. */ + public int getColumnNumber () + { return (locator == null) ? -1 : locator.getColumnNumber (); } + + /** + * Assigns the flag controlling the setting of the SAX2 + * namespace-prefixes flag. + */ + public void setSavingPrefixes (boolean flag) + { savingPrefixes = flag; } + + /** + * Returns the flag controlling the setting of the SAX2 + * namespace-prefixes flag when parsing included documents. + * The default value is the SAX2 default (false), which discards + * information that can be useful. + */ + public boolean isSavingPrefixes () + { return savingPrefixes; } + + // + // Two mechanisms are interacting here. + // + // - XML Base implies a stack of base URIs, updated both by + // "real entity" boundaries and element boundaries. + // + // - Active "Real Entities" (for document and general entities, + // and by xincluded files) are tracked to prevent circular + // inclusions. + // + private String addMarker (String uri) + throws SAXException + { + if (locator != null && locator.getSystemId () != null) + uri = locator.getSystemId (); + + // guard against InputSource objects without system IDs + if (uri == null) + fatal (new SAXParseException ("Entity URI is unknown", locator)); + + try { + URL url = new URL (uri); + + uri = url.toString (); + if (inclusions.contains (uri)) + fatal (new SAXParseException ( + "XInclude, circular inclusion", locator)); + inclusions.addElement (uri); + uris.push (url); + } catch (IOException e) { + // guard against illegal relative URIs (Xerces) + fatal (new SAXParseException ("parser bug: relative URI", + locator, e)); + } + return uri; + } + + private void pop (String uri) + { + inclusions.removeElement (uri); + uris.pop (); + } + + // + // Document entity boundaries get both treatments. + // + public void startDocument () throws SAXException + { + ignoreCount = 0; + addMarker (null); + super.startDocument (); + } + + public void endDocument () throws SAXException + { + inclusions.setSize (0); + extEntities.clear (); + uris.setSize (0); + super.endDocument (); + } + + // + // External general entity boundaries get both treatments. + // + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (name.charAt (0) == '%') + return; + try { + URL url = new URL (locator.getSystemId ()); + systemId = new URL (url, systemId).toString (); + } catch (IOException e) { + // what could we do? + } + extEntities.put (name, systemId); + } + + public void startEntity (String name) + throws SAXException + { + if (ignoreCount != 0) { + ignoreCount++; + return; + } + + String uri = (String) extEntities.get (name); + if (uri != null) + addMarker (uri); + super.startEntity (name); + } + + public void endEntity (String name) + throws SAXException + { + if (ignoreCount != 0) { + if (--ignoreCount != 0) + return; + } + + String uri = (String) extEntities.get (name); + + if (uri != null) + pop (uri); + super.endEntity (name); + } + + // + // element boundaries only affect the base URI stack, + // unless they're XInclude elements. + // + public void + startElement (String uri, String localName, String qName, Attributes atts) + throws SAXException + { + if (ignoreCount != 0) { + ignoreCount++; + return; + } + + URL baseURI = (URL) uris.peek (); + String base; + + base = atts.getValue ("http://www.w3.org/XML/1998/namespace", "base"); + if (base == null) + uris.push (baseURI); + else { + URL url; + + if (base.indexOf ('#') != -1) + fatal (new SAXParseException ( + "xml:base with fragment: " + base, + locator)); + + try { + baseURI = new URL (baseURI, base); + uris.push (baseURI); + } catch (Exception e) { + fatal (new SAXParseException ( + "xml:base with illegal uri: " + base, + locator, e)); + } + } + + if (!"http://www.w3.org/2001/XInclude".equals (uri)) { + super.startElement (uri, localName, qName, atts); + return; + } + + if ("include".equals (localName)) { + String href = atts.getValue ("href"); + String parse = atts.getValue ("parse"); + String encoding = atts.getValue ("encoding"); + URL url = (URL) uris.peek (); + SAXParseException x = null; + + if (href == null) + fatal (new SAXParseException ( + "XInclude missing href", + locator)); + if (href.indexOf ('#') != -1) + fatal (new SAXParseException ( + "XInclude with fragment: " + href, + locator)); + + if (parse == null || "xml".equals (parse)) + x = xinclude (url, href); + else if ("text".equals (parse)) + x = readText (url, href, encoding); + else + fatal (new SAXParseException ( + "unknown XInclude parsing mode: " + parse, + locator)); + if (x == null) { + // strip out all child content + ignoreCount++; + return; + } + + // FIXME the 17-Sept-2002 CR of XInclude says we "must" + // use xi:fallback elements to handle resource errors, + // if they exist. + fatal (x); + + } else if ("fallback".equals (localName)) { + fatal (new SAXParseException ( + "illegal top level XInclude 'fallback' element", + locator)); + } else { + ErrorHandler eh = getErrorHandler (); + + // CR doesn't say this is an error + if (eh != null) + eh.warning (new SAXParseException ( + "unrecognized toplevel XInclude element: " + localName, + locator)); + super.startElement (uri, localName, qName, atts); + } + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (ignoreCount != 0) { + if (--ignoreCount != 0) + return; + } + + uris.pop (); + if (!("http://www.w3.org/2001/XInclude".equals (uri) + && "include".equals (localName))) + super.endElement (uri, localName, qName); + } + + // + // ignore all content within non-empty xi:include elements + // + public void characters (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.characters (ch, start, length); + } + + public void processingInstruction (String target, String value) + throws SAXException + { + if (ignoreCount == 0) + super.processingInstruction (target, value); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.ignorableWhitespace (ch, start, length); + } + + public void comment (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.comment (ch, start, length); + } + + public void startCDATA () throws SAXException + { + if (ignoreCount == 0) + super.startCDATA (); + } + + public void endCDATA () throws SAXException + { + if (ignoreCount == 0) + super.endCDATA (); + } + + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (ignoreCount == 0) + super.startPrefixMapping (prefix, uri); + } + + public void endPrefixMapping (String prefix) throws SAXException + { + if (ignoreCount == 0) + super.endPrefixMapping (prefix); + } + + public void skippedEntity (String name) throws SAXException + { + if (ignoreCount == 0) + super.skippedEntity (name); + } + + // JDK 1.1 seems to need it to be done this way, sigh + void setLocator (Locator l) { locator = l; } + Locator getLocator () { return locator; } + + + // + // for XIncluded entities, manage the current locator and + // filter out events that would be incorrect to report + // + private class Scrubber extends EventFilter + { + Scrubber (EventFilter f) + throws SAXException + { + // delegation passes to next in chain + super (f); + + // process all content events + super.setContentHandler (this); + super.setProperty (LEXICAL_HANDLER, this); + + // drop all DTD events + super.setDTDHandler (null); + super.setProperty (DECL_HANDLER, null); + } + + // maintain proxy locator + // only one startDocument()/endDocument() pair per event stream + public void setDocumentLocator (Locator l) + { setLocator (l); } + public void startDocument () + { } + public void endDocument () + { } + + private void reject (String message) throws SAXException + { fatal (new SAXParseException (message, getLocator ())); } + + // only the DTD from the "base document" gets reported + public void startDTD (String root, String publicId, String systemId) + throws SAXException + { reject ("XIncluded DTD: " + systemId); } + public void endDTD () + throws SAXException + { reject ("XIncluded DTD"); } + // ... so this should never happen + public void skippedEntity (String name) throws SAXException + { reject ("XInclude skipped entity: " + name); } + + // since we rejected DTDs, only builtin entities can be reported + } + + // + // relative to the base URI passed + private SAXParseException xinclude (URL url, String href) + throws SAXException + { + XMLReader helper; + Scrubber scrubber; + Locator savedLocator = locator; + + // start with a parser acting just like our input + // modulo DTD-ish stuff (validation flag, entity resolver) + helper = XMLReaderFactory.createXMLReader (); + helper.setErrorHandler (getErrorHandler ()); + helper.setFeature (FEATURE_URI + "namespace-prefixes", true); + + // Set up the proxy locator and event filter. + scrubber = new Scrubber (this); + locator = null; + bind (helper, scrubber); + + // Merge the included document, except its DTD + try { + url = new URL (url, href); + href = url.toString (); + + if (inclusions.contains (href)) + fatal (new SAXParseException ( + "XInclude, circular inclusion", locator)); + + inclusions.addElement (href); + uris.push (url); + helper.parse (new InputSource (href)); + return null; + } catch (java.io.IOException e) { + return new SAXParseException (href, locator, e); + } finally { + pop (href); + locator = savedLocator; + } + } + + // + // relative to the base URI passed + private SAXParseException readText (URL url, String href, String encoding) + throws SAXException + { + InputStream in = null; + + try { + URLConnection conn; + InputStreamReader reader; + char buf [] = new char [4096]; + int count; + + url = new URL (url, href); + conn = url.openConnection (); + in = conn.getInputStream (); + if (encoding == null) + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding == null) { + ErrorHandler eh = getErrorHandler (); + if (eh != null) + eh.warning (new SAXParseException ( + "guessing text encoding for URL: " + url, + locator)); + reader = new InputStreamReader (in); + } else + reader = new InputStreamReader (in, encoding); + + while ((count = reader.read (buf, 0, buf.length)) != -1) + super.characters (buf, 0, count); + in.close (); + return null; + } catch (IOException e) { + return new SAXParseException ( + "can't XInclude text", + locator, e); + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/XsltFilter.java b/libjava/classpath/gnu/xml/pipeline/XsltFilter.java new file mode 100644 index 000000000..86b6190c5 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/XsltFilter.java @@ -0,0 +1,130 @@ +/* XsltFilter.java -- + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.pipeline; + +import java.io.IOException; + +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.*; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + + +/** + * Packages an XSLT transform as a pipeline component. + * Note that all DTD events (callbacks to DeclHandler and DTDHandler + * interfaces) are discarded, although XSLT transforms may be set up to + * use the LexicalHandler to write DTDs with only an external subset. + * Not every XSLT engine will necessarily be usable with this filter, + * but current versions of + * SAXON and + * Xalan should work well. + * + * @see TransformerFactory + * + * @author David Brownell + */ +final public class XsltFilter extends EventFilter +{ + /** + * Creates a filter that performs the specified transform. + * Uses the JAXP 1.1 interfaces to access the default XSLT + * engine configured for in the current execution context, + * and parses the stylesheet without custom EntityResolver + * or ErrorHandler support. + * + * @param stylesheet URI for the stylesheet specifying the + * XSLT transform + * @param next provides the ContentHandler and LexicalHandler + * to receive XSLT output. + * @exception SAXException if the stylesheet can't be parsed + * @exception IOException if there are difficulties + * bootstrapping the XSLT engine, such as it not supporting + * SAX well enough to use this way. + */ + public XsltFilter (String stylesheet, EventConsumer next) + throws SAXException, IOException + { + // First, get a transformer with the stylesheet preloaded + TransformerFactory tf = null; + TransformerHandler th; + + try { + SAXTransformerFactory stf; + + tf = TransformerFactory.newInstance (); + if (!tf.getFeature (SAXTransformerFactory.FEATURE) // sax inputs + || !tf.getFeature (SAXResult.FEATURE) // sax outputs + || !tf.getFeature (StreamSource.FEATURE) // stylesheet + ) + throw new IOException ("XSLT factory (" + + tf.getClass ().getName () + + ") does not support SAX"); + stf = (SAXTransformerFactory) tf; + th = stf.newTransformerHandler (new StreamSource (stylesheet)); + } catch (TransformerConfigurationException e) { + throw new IOException ("XSLT factory (" + + (tf == null + ? "none available" + : tf.getClass ().getName ()) + + ") configuration error, " + + e.getMessage () + ); + } + + // Hook its outputs up to the pipeline ... + SAXResult out = new SAXResult (); + + out.setHandler (next.getContentHandler ()); + try { + LexicalHandler lh; + lh = (LexicalHandler) next.getProperty (LEXICAL_HANDLER); + out.setLexicalHandler (lh); + } catch (Exception e) { + // ignore + } + th.setResult (out); + + // ... and make sure its inputs look like ours. + setContentHandler (th); + setProperty (LEXICAL_HANDLER, th); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/package.html b/libjava/classpath/gnu/xml/pipeline/package.html new file mode 100644 index 000000000..352f4c87c --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/package.html @@ -0,0 +1,255 @@ + +blah +<!-- +/* + * Copyright (C) 1999-2001 The Free Software Foundation, Inc. + */ +--> + + +

    This package exposes a kind of XML processing pipeline, based on sending +SAX events, which can be used as components of application architectures. +Pipelines are used to convey streams of processing events from a producer +to one or more consumers, and to let each consumer control the data seen by +later consumers. + +

    There is a PipelineFactory class which +accepts a syntax describing how to construct some simple pipelines. Strings +describing such pipelines can be used in command line tools (see the +DoParse class) +and in other places that it is +useful to let processing be easily reconfigured. Pipelines can of course +be constructed programmatically, providing access to options that the +factory won't. + +

    Web applications are supported by making it easy for servlets (or +non-Java web application components) to be part of a pipeline. They can +originate XML (or XHTML) data through an InputSource or in +response to XML messages sent from clients using CallFilter +pipeline stages. Such facilities are available using the simple syntax +for pipeline construction. + + +

    Programming Models

    + +

    Pipelines should be simple to understand. + +

    + + +

    Producers: XMLReader or Custom

    + +

    Many producers will be SAX2 XMLReader objects, and +will read (pull) data which is then written (pushed) as events. +Typically these will parse XML text (acquired from +org.xml.sax.helpers.XMLReaderFactory) or a DOM tree +(using a DomParser) +These may be bound to event consumer using a convenience routine, +EventFilter.bind(). +Once bound, these producers may be given additional documents to +sent through its pipeline. + +

    In other cases, you will write producers yourself. For example, some +data structures might know how to write themselves out using one or +more XML models, expressed as sequences of SAX2 event callbacks. +An application module might +itself be a producer, issuing startDocument and endDocument events +and then asking those data structures to write themselves out to a +given EventConsumer, or walking data structures (such as JDBC query +results) and applying its own conversion rules. WAP format XML +(WBMXL) can be directly converted to producer output. + +

    SAX2 introduced an "XMLFilter" interface, which is a kind of XMLReader. +It is most useful in conjunction with its XMLFilterImpl helper class; +see the EventFilter javadoc +for information contrasting that XMLFilterImpl approach with the +relevant parts of this pipeline framework. Briefly, such XMLFilterImpl +children can be either producers or consumers, and are more limited in +configuration flexibility. In this framework, the focus of filters is +on the EventConsumer side; see the section on +pipe fitting below. + + +

    Consume to Standard or Custom Data Representations

    + +

    Many consumers will be used to create standard representations of XML +data. The TextConsumer takes its events +and writes them as text for a single XML document, +using an internal XMLWriter. +The DomConsumer takes its events and uses +them to create and populate a DOM Document. + +

    In other cases, you will write consumers yourself. For example, +you might use a particular unmarshaling filter to produce objects +that fit your application's requirements, instead of using DOM. +Such consumers work at the level of XML data models, rather than with +specific representations such as XML text or a DOM tree. You could +convert your output directly to WAP format data (WBXML). + + +

    Pipe Fitting

    + +

    Pipelines are composite event consumers, with each stage having +the opportunity to transform the data before delivering it to any +subsequent stages. + +

    The PipelineFactory class +provides access to much of this functionality through a simple syntax. +See the table in that class's javadoc describing a number of standard +components. Direct API calls are still needed for many of the most +interesting pipeline configurations, including ones leveraging actual +or logical concurrency. + +

    Four basic types of pipe fitting are directly supported. These may +be used to construct complex pipeline networks.

    + +

    Note that filters can be as complex as +XSLT transforms +available) on input data, or as simple as removing simple syntax data +such as ignorable whitespace, comments, and CDATA delimiters. +Some simple "built-in" filters are part of this package. + + +

    Coding Conventions: Filter and Terminus Stages

    + +

    If you follow these coding conventions, your classes may be used +directly (give the full class name) in pipeline descriptions as understood +by the PipelineFactory. There are four constructors the factory may +try to use; in order of decreasing numbers of parameters, these are:

    + +

    Of course, classes may support more than one such usage convention; +if they do, they can automatically be used in multiple modes. If you +try to use a terminus class as a filter, and that terminus has a constructor +with the appropriate number of arguments, it is automatically wrapped in +a "tee" filter. + + +

    Debugging Tip: "Tee" Joints can Snapshot Data

    + +

    It can sometimes be hard to see what's happening, when something +goes wrong. Easily fixed: just snapshot the data. Then you can find +out where things start to go wrong. + +

    If you're using pipeline descriptors so that they're easily +administered, just stick a write ( filename ) +filter into the pipeline at an appropriate point. + +

    Inside your programs, you can do the same thing directly: perhaps +by saving a Writer (perhaps a StringWriter) in a variable, using that +to create a TextConsumer, and making that the first part of a tee -- +splicing that into your pipeline at a convenient location. + +

    You can also use a DomConsumer to buffer the data, but remember +that DOM doesn't save all the information that XML provides, so that DOM +snapshots are relatively low fidelity. They also are substantially more +expensive in terms of memory than a StringWriter holding similar data. + +

    Debugging Tip: Non-XML Producers

    + +

    Producers in pipelines don't need to start from XML +data structures, such as text in XML syntax (likely coming +from some XMLReader that parses XML) or a +DOM representation (perhaps with a +DomParser). + +

    One common type of event producer will instead make +direct calls to SAX event handlers returned from an +EventConsumer. +For example, making ContentHandler.startElement +calls and matching ContentHandler.endElement calls. + +

    Applications making such calls can catch certain +common "syntax errors" by using a +WellFormednessFilter. +That filter will detect (and report) erroneous input data +such as mismatched document, element, or CDATA start/end calls. +Use such a filter near the head of the pipeline that your +producer feeds, at least while debugging, to help ensure that +you're providing legal XML Infoset data. + +

    You can also arrange to validate data on the fly. +For DTD validation, you can configure a +ValidationConsumer +to work as a filter, using any DTD you choose. +Other validation schemes can be handled with other +validation filters. + + diff --git a/libjava/classpath/gnu/xml/stream/AttributeImpl.java b/libjava/classpath/gnu/xml/stream/AttributeImpl.java new file mode 100644 index 000000000..58a0dbe21 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/AttributeImpl.java @@ -0,0 +1,123 @@ +/* AttributeImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +/** + * An attribute event. + * + * @author Chris Burdess + */ +public class AttributeImpl + extends XMLEventImpl + implements Attribute +{ + + protected final QName name; + protected final String value; + protected final String type; + protected final boolean specified; + + protected AttributeImpl(Location location, + QName name, String value, String type, + boolean specified) + { + super(location); + this.name = name; + this.value = value; + this.type = type; + this.specified = specified; + } + + public int getEventType() + { + return ATTRIBUTE; + } + + public QName getName() + { + return name; + } + + public String getValue() + { + return value; + } + + public String getDTDType() + { + return type; + } + + public boolean isSpecified() + { + return specified; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + String prefix = name.getPrefix(); + if (prefix != null && !"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + writer.write('='); + writer.write('"'); + writer.write(encode(value, true)); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/BufferedReader.java b/libjava/classpath/gnu/xml/stream/BufferedReader.java new file mode 100644 index 000000000..dc69fb34b --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/BufferedReader.java @@ -0,0 +1,198 @@ +/* BufferedReader.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Reader; + +/** + * A mark-capable buffered reader. + * + * @author Chris Burdess + */ +class BufferedReader + extends Reader +{ + + static final int DEFAULT_BUFFER_SIZE = 4096; + + final Reader in; + char[] buf; + int pos, count, markpos, marklimit, bufferSize; + + BufferedReader(Reader in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + BufferedReader(Reader in, int bufferSize) + { + if (bufferSize < 1) + throw new IllegalArgumentException(); + this.in = in; + this.bufferSize = bufferSize; + buf = new char[bufferSize]; + pos = count = bufferSize; + } + + public void close() + throws IOException + { + buf = null; + pos = count = 0; + markpos = -1; + in.close(); + } + + public void mark(int readlimit) + throws IOException + { + marklimit = readlimit; + markpos = pos; + } + + public boolean markSupported() + { + return true; + } + + public int read() + throws IOException + { + if (pos >= count && !refill()) + return -1; + return (int) buf[pos++]; + } + + public int read(char[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(char[] b, int off, int len) + throws IOException + { + if (off < 0 || len < 0 || b.length - off < len) + throw new IndexOutOfBoundsException(); + + if (len == 0) + return 0; + + if (pos >= count && !refill()) + return -1; + + int ret = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, ret); + pos += ret; + off += ret; + len -= ret; + + while (len > 0 && refill()) + { + int remain = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + ret += remain; + } + + return ret; + } + + public void reset() + throws IOException + { + if (markpos == -1) + throw new IOException(buf == null ? "Stream closed." : "Invalid mark."); + pos = markpos; + } + + public long skip(long n) + throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + final long origN = n; + while (n > 0L) + { + if (pos >= count && !refill()) + break; + int numread = (int) Math.min((long) (count - pos), n); + pos += numread; + n -= numread; + } + return origN - n; + } + + private boolean refill() + throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + int markcount = count - markpos; + if (markpos == -1 || markcount >= marklimit) + { + markpos = -1; + pos = count = 0; + } + else + { + char[] newbuf = buf; + if (markpos < bufferSize) + { + newbuf = new char[count - markpos + bufferSize]; + } + System.arraycopy(buf, markpos, newbuf, 0, markcount); + buf = newbuf; + count = markcount; + pos -= markpos; + markpos = 0; + } + + int numread = in.read(buf, count, bufferSize); + if (numread <= 0) + return false; + + count += numread; + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CRLFReader.java b/libjava/classpath/gnu/xml/stream/CRLFReader.java new file mode 100644 index 000000000..7f3cf4d74 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CRLFReader.java @@ -0,0 +1,180 @@ +/* CRLFReader.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +/** + * Filtered reader that normalizes CRLF pairs into LFs. + * + * @author Chris Burdess + */ +class CRLFReader + extends Reader +{ + + /** + * The CR octet. + */ + public static final int CR = 13; + + /** + * The LF octet. + */ + public static final int LF = 10; + + private boolean doReset; + + protected Reader in; + + /** + * Constructor. + */ + protected CRLFReader(Reader in) + { + if (!in.markSupported()) + in = new BufferedReader(in); + this.in = in; + } + + public int read() + throws IOException + { + int c = in.read(); + if (c == 13) // CR + { + in.mark(1); + int d = in.read(); + if (d == 10) // LF + c = d; + else + in.reset(); + } + return c; + } + + public int read(char[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(char[] b, int off, int len) + throws IOException + { + in.mark(len + 1); + int l = in.read(b, off, len); + if (l > 0) + { + int i = indexOfCRLF(b, off, l); + if (doReset) + { + in.reset(); + if (i != -1) + { + l = in.read(b, off, (i + 1) - off); // read to CR + in.read(); // skip LF + b[i] = '\n'; // fix CR as LF + } + else + l = in.read(b, off, len); // CR(s) but no LF + } + } + return l; + } + + public boolean markSupported() + { + return in.markSupported(); + } + + public void mark(int limit) + throws IOException + { + in.mark(limit); + } + + public void reset() + throws IOException + { + in.reset(); + } + + public long skip(long n) + throws IOException + { + return in.skip(n); + } + + public void close() + throws IOException + { + in.close(); + } + + private int indexOfCRLF(char[] b, int off, int len) + throws IOException + { + doReset = false; + int end = off + len; + int em1 = end - 1; + for (int i = off; i < end; i++) + { + if (b[i] == '\r') // CR + { + int d; + if (i == em1) + { + d = in.read(); + doReset = true; + } + else + d = b[i + 1]; + if (d == '\n') // LF + { + doReset = true; + return i; + } + } + } + return -1; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CharactersImpl.java b/libjava/classpath/gnu/xml/stream/CharactersImpl.java new file mode 100644 index 000000000..2107a5a6d --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CharactersImpl.java @@ -0,0 +1,119 @@ +/* CharactersImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; + +/** + * A character data (text) event. + * + * @author Chris Burdess + */ +public class CharactersImpl + extends XMLEventImpl + implements Characters +{ + + protected final String data; + protected final boolean whitespace; + protected final boolean cdata; + protected final boolean ignorableWhitespace; + + protected CharactersImpl(Location location, + String data, boolean whitespace, boolean cdata, + boolean ignorableWhitespace) + { + super(location); + this.data = data; + this.whitespace = whitespace; + this.cdata = cdata; + this.ignorableWhitespace = ignorableWhitespace; + } + + public int getEventType() + { + return cdata ? CDATA : whitespace ? SPACE : CHARACTERS; + } + + public String getData() + { + return data; + } + + public boolean isWhiteSpace() + { + return whitespace; + } + + public boolean isCData() + { + return cdata; + } + + public boolean isIgnorableWhiteSpace() + { + return ignorableWhitespace; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + if (cdata) + { + writer.write(""); + } + else + writer.write(encode(data, false)); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CommentImpl.java b/libjava/classpath/gnu/xml/stream/CommentImpl.java new file mode 100644 index 000000000..118ac7a57 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CommentImpl.java @@ -0,0 +1,91 @@ +/* CommentImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Comment; + +/** + * A comment event. + * + * @author Chris Burdess + */ +public class CommentImpl + extends XMLEventImpl + implements Comment +{ + + protected final String text; + + protected CommentImpl(Location location, String text) + { + super(location); + this.text = text; + } + + public int getEventType() + { + return COMMENT; + } + + public String getText() + { + return text; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/DTDImpl.java b/libjava/classpath/gnu/xml/stream/DTDImpl.java new file mode 100644 index 000000000..cf049d362 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/DTDImpl.java @@ -0,0 +1,114 @@ +/* DTDImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.DTD; + +/** + * A DOCTYPE declaration event. + * + * @author Chris Burdess + */ +public class DTDImpl + extends XMLEventImpl + implements DTD +{ + + protected final String body; + protected final Object impl; + protected final List notations; + protected final List entities; + + protected DTDImpl(Location location, + String body, Object impl, List notations, List entities) + { + super(location); + this.body = body; + this.impl = impl; + this.notations = notations; + this.entities = entities; + } + + public int getEventType() + { + return DTD; + } + + public String getDocumentTypeDeclaration() + { + return body; + } + + public Object getProcessedDTD() + { + return impl; + } + + public List getNotations() + { + return notations; + } + + public List getEntities() + { + return entities; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java b/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java new file mode 100644 index 000000000..13877c5c9 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java @@ -0,0 +1,70 @@ +/* EndDocumentImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndDocument; + +/** + * An end-document event. + * + * @author Chris Burdess + */ +public class EndDocumentImpl + extends XMLEventImpl + implements EndDocument +{ + + protected EndDocumentImpl(Location location) + { + super(location); + } + + public int getEventType() + { + return END_DOCUMENT; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EndElementImpl.java b/libjava/classpath/gnu/xml/stream/EndElementImpl.java new file mode 100644 index 000000000..71f6aa0bc --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EndElementImpl.java @@ -0,0 +1,107 @@ +/* EndElementImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; + +/** + * An end-element event. + * + * @author Chris Burdess + */ +public class EndElementImpl + extends XMLEventImpl + implements EndElement +{ + + protected final QName name; + protected final List namespaces; + + protected EndElementImpl(Location location, QName name, List namespaces) + { + super(location); + this.name = name; + this.namespaces = namespaces; + } + + public int getEventType() + { + return END_ELEMENT; + } + + public QName getName() + { + return name; + } + + public Iterator getNamespaces() + { + return namespaces.iterator(); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java b/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java new file mode 100644 index 000000000..b6e33e8d2 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java @@ -0,0 +1,163 @@ +/* EntityDeclarationImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; + +/** + * An entity declaration event. + * + * @author Chris Burdess + */ +public class EntityDeclarationImpl + extends XMLEventImpl + implements EntityDeclaration +{ + + protected final String publicId; + protected final String systemId; + protected final String name; + protected final String notationName; + protected final String replacementText; + protected final String baseUri; + + protected EntityDeclarationImpl(Location location, + String publicId, String systemId, + String name, String notationName, + String replacementText, String baseUri) + { + super(location); + this.publicId = publicId; + this.systemId = systemId; + this.name = name; + this.notationName = notationName; + this.replacementText = replacementText; + this.baseUri = baseUri; + } + + public int getEventType() + { + return ENTITY_DECLARATION; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + public String getName() + { + return name; + } + + public String getNotationName() + { + return notationName; + } + + public String getReplacementText() + { + return replacementText; + } + + public String getBaseURI() + { + return baseUri; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java b/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java new file mode 100644 index 000000000..6f8a11c80 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java @@ -0,0 +1,101 @@ +/* EntityReferenceImpl.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; + +/** + * An entity reference event. + * + * @author Chris Burdess + */ +public class EntityReferenceImpl + extends XMLEventImpl + implements EntityReference +{ + + protected final EntityDeclaration decl; + protected final String name; + + protected EntityReferenceImpl(Location location, + EntityDeclaration decl, + String name) + { + super(location); + this.decl = decl; + this.name = name; + } + + public int getEventType() + { + return ENTITY_REFERENCE; + } + + public EntityDeclaration getDeclaration() + { + return decl; + } + + public String getName() + { + return name; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write('&'); + writer.write(name); + writer.write(';'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/FilteredEventReader.java b/libjava/classpath/gnu/xml/stream/FilteredEventReader.java new file mode 100644 index 000000000..1ddb469df --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/FilteredEventReader.java @@ -0,0 +1,114 @@ +/* FilteredEventReader.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import javax.xml.stream.EventFilter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.EventReaderDelegate; + +class FilteredEventReader + extends EventReaderDelegate +{ + + final EventFilter filter; + + FilteredEventReader(XMLEventReader reader, EventFilter filter) + { + super(reader); + this.filter = filter; + } + + public boolean hasNext() + { + // XXX ??? + return super.hasNext(); + } + + public XMLEvent nextEvent() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.nextEvent(); + } + while (!filter.accept(ret)); + return ret; + } + + public Object next() + { + try + { + return nextEvent(); + } + catch (XMLStreamException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + + public XMLEvent peek() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.peek(); + } + while (!filter.accept(ret)); + return ret; + } + + public XMLEvent nextTag() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.nextTag(); + } + while (!filter.accept(ret)); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java b/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java new file mode 100644 index 000000000..62d96488e --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java @@ -0,0 +1,90 @@ +/* FilteredStreamReader.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import javax.xml.stream.StreamFilter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; + +class FilteredStreamReader + extends StreamReaderDelegate +{ + + final XMLStreamReader reader; + final StreamFilter filter; + + FilteredStreamReader(XMLStreamReader reader, StreamFilter filter) + { + super(reader); + this.reader = reader; + this.filter = filter; + } + + public boolean hasNext() + throws XMLStreamException + { + // XXX ??? + return super.hasNext(); + } + + public int next() + throws XMLStreamException + { + int ret; + do + { + ret = super.next(); + } + while (!filter.accept(reader)); + return ret; + } + + public int nextTag() + throws XMLStreamException + { + int ret; + do + { + ret = super.nextTag(); + } + while (!filter.accept(reader)); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/NamespaceImpl.java b/libjava/classpath/gnu/xml/stream/NamespaceImpl.java new file mode 100644 index 000000000..241f980b6 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/NamespaceImpl.java @@ -0,0 +1,137 @@ +/* NamespaceImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Namespace; + +/** + * A namespace declaration event. + * + * @author Chris Burdess + */ +public class NamespaceImpl + extends XMLEventImpl + implements Namespace +{ + + protected final String prefix; + protected final String uri; + protected final boolean specified; + + protected NamespaceImpl(Location location, String prefix, String uri, + boolean specified) + { + super(location); + this.prefix = prefix; + this.uri = uri; + this.specified = specified; + } + + public int getEventType() + { + return NAMESPACE; + } + + public String getPrefix() + { + return prefix; + } + + public String getNamespaceURI() + { + return uri; + } + + public boolean isSpecified() + { + return specified; + } + + public QName getName() + { + if (isDefaultNamespaceDeclaration()) + return new QName("", "xmlns", null); + else + return new QName("", prefix, "xmlns"); + } + + public String getDTDType() + { + return "CDATA"; + } + + public String getValue() + { + return uri; + } + + public boolean isDefaultNamespaceDeclaration() + { + return (prefix == null || "".equals(prefix)); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write("xmlns"); + if (prefix != null && !"".equals(prefix)) + { + writer.write(':'); + writer.write(prefix); + } + writer.write('='); + writer.write('"'); + writer.write(encode(uri, true)); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java b/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java new file mode 100644 index 000000000..a338237ee --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java @@ -0,0 +1,125 @@ +/* NotationDeclarationImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.NotationDeclaration; + +/** + * A notation declaration event. + * + * @author Chris Burdess + */ +public class NotationDeclarationImpl + extends XMLEventImpl + implements NotationDeclaration +{ + + protected final String name; + protected final String publicId; + protected final String systemId; + + protected NotationDeclarationImpl(Location location, + String name, String publicId, + String systemId) + { + super(location); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public int getEventType() + { + return NOTATION_DECLARATION; + } + + public String getName() + { + return name; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write("'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java b/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java new file mode 100644 index 000000000..4ce0badc8 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java @@ -0,0 +1,104 @@ +/* ProcessingInstructionImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.ProcessingInstruction; + +/** + * A processing instruction event. + * + * @author Chris Burdess + */ +public class ProcessingInstructionImpl + extends XMLEventImpl + implements ProcessingInstruction +{ + + protected final String target; + protected final String data; + + protected ProcessingInstructionImpl(Location location, + String target, String data) + { + super(location); + this.target = target; + this.data = data; + } + + public int getEventType() + { + return PROCESSING_INSTRUCTION; + } + + public String getTarget() + { + return target; + } + + public String getData() + { + return data; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/SAXParser.java b/libjava/classpath/gnu/xml/stream/SAXParser.java new file mode 100644 index 000000000..b71d98ed3 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/SAXParser.java @@ -0,0 +1,1041 @@ +/* SAXParser.java -- + Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.util.Iterator; +import java.util.Map; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.ext.Locator2; + +/** + * JAXP SAX parser using an underlying StAX parser. + * This parser supports the following additional SAX features and + * properties: + * + * + * + * + * + * + * + * + * + * + * + * + *
    Features
    http://gnu.org/sax/features/xml-baseread/writeIndicates or sets whether XML Base processing is enabled
    Properties
    http://gnu.org/sax/properties/base-uriread-onlyStringReturns the base URI of the current event
    http://gnu.org/sax/properties/document-xml-encodingread-onlyStringReturns the encoding specified in the XML declaration
    + * + * @author Chris Burdess + */ +public class SAXParser + extends javax.xml.parsers.SAXParser + implements XMLReader, Attributes2, Locator2, XMLReporter, XMLResolver +{ + + ContentHandler contentHandler; + DeclHandler declHandler; + DTDHandler dtdHandler; + EntityResolver entityResolver; + ErrorHandler errorHandler; + LexicalHandler lexicalHandler; + + boolean validating = false; + boolean namespaceAware = true; + boolean xIncludeAware = false; + boolean stringInterning = true; + boolean coalescing = true; + boolean replaceERefs = true; + boolean externalEntities = true; + boolean supportDTD = true; + boolean baseAware = true; + + XMLParser parser; + XMLStreamReader reader; + String encoding; + String xmlVersion; + boolean xmlStandalone; + String xmlEncoding; + String baseURI; + + public SAXParser() + { + } + + SAXParser(boolean validating, boolean namespaceAware, boolean xIncludeAware) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.xIncludeAware = xIncludeAware; + } + + // -- SAXParser -- + + public Parser getParser() + throws SAXException + { + return null; + } + + public XMLReader getXMLReader() + throws SAXException + { + return this; + } + + public boolean isNamespaceAware() + { + return namespaceAware; + } + + public boolean isValidating() + { + return validating; + } + + public void setProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parser != null) + throw new IllegalStateException("parsing in progress"); + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_FEATURES = "http://gnu.org/sax/features/"; + if ((FEATURES + "namespaces").equals(name)) + namespaceAware = Boolean.TRUE.equals(value); + else if ((FEATURES + "namespace-prefixes").equals(name)) + { + // NOOP + } + else if ((FEATURES + "string-interning").equals(name)) + stringInterning = Boolean.TRUE.equals(value); + else if ((FEATURES + "use-attributes2").equals(name)) + { + // NOOP + } + else if ((FEATURES + "validation").equals(name)) + validating = Boolean.TRUE.equals(value); + else if ((FEATURES + "external-general-entities").equals(name)) + externalEntities = Boolean.TRUE.equals(value); + else if ((FEATURES + "external-parameter-entities").equals(name)) + externalEntities = Boolean.TRUE.equals(value); + else if ((PROPERTIES + "declaration-handler").equals(name)) + declHandler = (DeclHandler) value; + else if ((PROPERTIES + "lexical-handler").equals(name)) + lexicalHandler = (LexicalHandler) value; + else if ((GNU_FEATURES + "xml-base").equals(name)) + baseAware = Boolean.TRUE.equals(value); + else if ((GNU_FEATURES + "coalescing").equals(name)) + coalescing = Boolean.TRUE.equals(value); + else + throw new SAXNotSupportedException(name); + } + + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_FEATURES = "http://gnu.org/sax/features/"; + final String GNU_PROPERTIES = "http://gnu.org/sax/properties/"; + if ((GNU_FEATURES + "base-uri").equals(name)) + return baseURI; + if ((FEATURES + "is-standalone").equals(name)) + return xmlStandalone ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "namespaces").equals(name)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "namespace-prefixes").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "string-interning").equals(name)) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "use-attributes2").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "use-locator2").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "use-entity-resolver2").equals(name)) + return Boolean.FALSE; + if ((FEATURES + "validation").equals(name)) + return validating ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "external-general-entities").equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "external-parameter-entities").equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "xml-1.1").equals(name)) + return Boolean.TRUE; + if ((PROPERTIES + "declaration-handler").equals(name)) + return declHandler; + if ((PROPERTIES + "document-xml-version").equals(name)) + return xmlVersion; + if ((PROPERTIES + "lexical-handler").equals(name)) + return lexicalHandler; + if ((GNU_FEATURES + "xml-base").equals(name)) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if ((GNU_PROPERTIES + "document-xml-encoding").equals(name)) + return xmlEncoding; + throw new SAXNotRecognizedException(name); + } + + public boolean isXIncludeAware() + { + return xIncludeAware; + } + + public void reset() + { + parser = null; + encoding = null; + xmlVersion = null; + xmlStandalone = false; + } + + // -- XMLReader -- + + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + Object ret = getProperty(name); + if (ret instanceof Boolean) + return ((Boolean) ret).booleanValue(); + throw new SAXNotSupportedException(name); + } + + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + setProperty(name, value ? Boolean.TRUE : Boolean.FALSE); + } + + public void setEntityResolver(EntityResolver resolver) + { + entityResolver = resolver; + } + + public EntityResolver getEntityResolver() + { + return entityResolver; + } + + public void setDTDHandler(DTDHandler handler) + { + dtdHandler = handler; + } + + public DTDHandler getDTDHandler() + { + return dtdHandler; + } + + public void setContentHandler(ContentHandler handler) + { + contentHandler = handler; + } + + public ContentHandler getContentHandler() + { + return contentHandler; + } + + public void setErrorHandler(ErrorHandler handler) + { + errorHandler = handler; + } + + public ErrorHandler getErrorHandler() + { + return errorHandler; + } + + public synchronized void parse(InputSource input) + throws IOException, SAXException + { + reset(); + String systemId = input.getSystemId(); + InputStream in = input.getByteStream(); + boolean opened = false; + if (in != null) + parser = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + else + { + Reader r = input.getCharacterStream(); + if (r != null) + parser = new XMLParser(r, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + } + if (parser == null) + { + if (systemId == null) + throw new SAXException("No stream or system ID specified"); + systemId = XMLParser.absolutize(null, systemId); + in = new URL(systemId).openStream(); + opened = true; + parser = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + } + reader = parser; + baseURI = systemId; + + if (xIncludeAware) + reader = new XIncludeFilter(parser, systemId, namespaceAware, + validating, true); + + if (contentHandler != null) + contentHandler.setDocumentLocator(this); + boolean startDocumentDone = false; + try + { + while (parser.hasNext()) + { + int event = parser.next(); + if (baseAware) + baseURI = parser.getXMLBase(); + switch (event) + { + case XMLStreamConstants.CHARACTERS: + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + contentHandler.characters(b, 0, b.length); + } + break; + case XMLStreamConstants.SPACE: + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + if (isIgnorableWhitespace(parser, b, false)) + contentHandler.ignorableWhitespace(b, 0, b.length); + else + contentHandler.characters(b, 0, b.length); + } + break; + case XMLStreamConstants.CDATA: + if (lexicalHandler != null) + lexicalHandler.startCDATA(); + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + if (isIgnorableWhitespace(parser, b, true)) + contentHandler.ignorableWhitespace(b, 0, b.length); + else + contentHandler.characters(b, 0, b.length); + } + if (lexicalHandler != null) + lexicalHandler.endCDATA(); + break; + case XMLStreamConstants.START_ELEMENT: + if (contentHandler != null) + { + QName name = reader.getName(); + String uri = name.getNamespaceURI(); + String localName = name.getLocalPart(); + String prefix = name.getPrefix(); + String qName = localName; + if (!"".equals(prefix)) + qName = prefix + ":" + localName; + if (!namespaceAware) + { + uri = ""; + localName = ""; + } + else + { + int nc = reader.getNamespaceCount(); + for (int i = 0; i < nc; i++) + { + String nsuri = reader.getNamespaceURI(i); + String nsprefix = reader.getNamespacePrefix(i); + if ("xml".equals(nsprefix)) + continue; + contentHandler.startPrefixMapping(nsprefix, nsuri); + } + } + contentHandler.startElement(uri, localName, qName, this); + } + break; + case XMLStreamConstants.END_ELEMENT: + if (contentHandler != null) + { + QName name = reader.getName(); + String uri = name.getNamespaceURI(); + String localName = name.getLocalPart(); + String prefix = name.getPrefix(); + String qName = localName; + if (!"".equals(prefix)) + qName = prefix + ":" + localName; + if (!namespaceAware) + { + uri = ""; + localName = ""; + } + contentHandler.endElement(uri, localName, qName); + if (namespaceAware) + { + int nc = reader.getNamespaceCount(); + for (int i = 0; i < nc; i++) + { + String nsprefix = reader.getNamespacePrefix(i); + if ("xml".equals(nsprefix)) + continue; + contentHandler.endPrefixMapping(nsprefix); + } + } + } + break; + case XMLStreamConstants.COMMENT: + if (lexicalHandler != null) + { + char[] b = reader.getTextCharacters(); + lexicalHandler.comment(b, 0, b.length); + } + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + if (contentHandler != null) + { + String target = reader.getPITarget(); + String data = reader.getPIData(); + if (data == null) + data = ""; + contentHandler.processingInstruction(target, data); + } + break; + case XMLParser.START_ENTITY: + if (lexicalHandler != null) + { + String name = reader.getText(); + lexicalHandler.startEntity(name); + } + break; + case XMLParser.END_ENTITY: + if (lexicalHandler != null) + { + String name = reader.getText(); + lexicalHandler.endEntity(name); + } + break; + case XMLStreamConstants.START_DOCUMENT: + encoding = reader.getEncoding(); + xmlVersion = reader.getVersion(); + xmlStandalone = reader.isStandalone(); + xmlEncoding = reader.getCharacterEncodingScheme(); + if (contentHandler != null) + contentHandler.startDocument(); + startDocumentDone = true; + break; + case XMLStreamConstants.END_DOCUMENT: + if (contentHandler != null) + contentHandler.endDocument(); + break; + case XMLStreamConstants.DTD: + XMLParser.Doctype doctype = parser.doctype; + if (lexicalHandler != null) + { + String rootName = doctype.rootName; + String publicId = doctype.publicId; + String systemId2 = doctype.systemId; + lexicalHandler.startDTD(rootName, publicId, systemId2); + } + for (Iterator i = doctype.entryIterator(); i.hasNext(); ) + { + String entry = (String) i.next(); + char c = entry.charAt(0); + String name = entry.substring(1); + if ('E' == c) + { + // Element decl + if (declHandler != null) + { + XMLParser.ContentModel model = + doctype.getElementModel(name); + declHandler.elementDecl(name, model.text); + } + } + else if ('A' == c) + { + // Attlist decl + if (declHandler != null) + { + for (Iterator j = doctype.attlistIterator(name); + j.hasNext(); ) + { + Map.Entry att = (Map.Entry) j.next(); + String aname = (String) att.getKey(); + XMLParser.AttributeDecl decl = + (XMLParser.AttributeDecl) att.getValue(); + String type = decl.type; + String value = decl.value; + String mode = null; + switch (decl.valueType) + { + case XMLParser.ATTRIBUTE_DEFAULT_FIXED: + mode = "#FIXED"; + break; + case XMLParser.ATTRIBUTE_DEFAULT_REQUIRED: + mode = "#REQUIRED"; + break; + case XMLParser.ATTRIBUTE_DEFAULT_IMPLIED: + mode = "#IMPLIED"; + break; + } + declHandler.attributeDecl(name, aname, + type, mode, value); + } + } + } + else if ('e' == c) + { + // Entity decl + Object entity = doctype.getEntity(name); + if (entity instanceof String) + { + if (declHandler != null) + declHandler.internalEntityDecl(name, + (String) entity); + } + else + { + XMLParser.ExternalIds ids = + (XMLParser.ExternalIds) entity; + if (ids.notationName != null) + { + if (dtdHandler != null) + { + String pub = ids.publicId; + String url = ids.systemId; + String not = ids.notationName; + dtdHandler.unparsedEntityDecl(name, + pub, + url, + not); + } + } + else + { + if (declHandler != null) + { + String pub = ids.publicId; + String url = ids.systemId; + declHandler.externalEntityDecl(name, + pub, + url); + } + } + } + } + else if ('n' == c) + { + // Notation decl + if (dtdHandler != null) + { + XMLParser.ExternalIds ids = + doctype.getNotation(name); + String pub = ids.publicId; + String url = ids.systemId; + dtdHandler.notationDecl(name, pub, url); + } + } + else if ('c' == c) + { + // Comment + if (lexicalHandler != null) + { + String comment = doctype.getComment(name); + char[] b = comment.toCharArray(); + lexicalHandler.comment(b, 0, b.length); + } + } + else if ('p' == c) + { + // Processing instruction + if (contentHandler != null) + { + String[] pi = doctype.getPI(name); + String target = pi[0]; + String data = pi[1]; + if (data == null) + data = ""; + contentHandler.processingInstruction(target, data); + } + } + } + if (lexicalHandler != null) + lexicalHandler.endDTD(); + } + } + reset(); + if (opened) + in.close(); + } + catch (Exception e) + { + SAXParseException e2 = new SAXParseException(e.getMessage(), this); + e2.initCause(e); + try + { + if (!startDocumentDone && contentHandler != null) + contentHandler.startDocument(); + if (errorHandler != null) + errorHandler.fatalError(e2); + if (contentHandler != null) + contentHandler.endDocument(); + } + catch (SAXException sex) + { + // Ignored, we will rethrow the original exception. + } + reset(); + if (opened) + in.close(); + if (e instanceof SAXException) + throw (SAXException) e; + if (e instanceof IOException) + throw (IOException) e; + else + throw e2; + } + } + + /** + * Indicates whether the specified characters are ignorable whitespace. + */ + private boolean isIgnorableWhitespace(XMLParser reader, char[] b, + boolean testCharacters) + throws XMLStreamException + { + XMLParser.Doctype doctype = reader.doctype; + if (doctype == null) + return false; + String currentElement = reader.getCurrentElement(); + // check for xml:space + int ac = reader.getAttributeCount(); + for (int i = 0; i < ac; i++) + { + QName aname = reader.getAttributeName(i); + if ("space".equals(aname.getLocalPart()) && + XMLConstants.XML_NS_URI.equals(aname.getNamespaceURI())) + { + if ("preserve".equals(reader.getAttributeValue(i))) + return false; + } + } + XMLParser.ContentModel model = doctype.getElementModel(currentElement); + if (model == null || model.type != XMLParser.ContentModel.ELEMENT) + return false; + if (model.external && xmlStandalone) + return false; + boolean white = true; + if (testCharacters) + { + for (int i = 0; i < b.length; i++) + { + if (b[i] != ' ' && b[i] != '\t' && b[i] != '\n' && b[i] != '\r') + { + white = false; + break; + } + } + } + return white; + } + + public void parse(String systemId) + throws IOException, SAXException + { + parse(new InputSource(systemId)); + } + + // -- Attributes2 -- + + public int getIndex(String qName) + { + int len = reader.getAttributeCount(); + for (int i = 0; i < len; i++) + { + QName q = reader.getAttributeName(i); + String localName = q.getLocalPart(); + String prefix = q.getPrefix(); + String qn = ("".equals(prefix)) ? localName : prefix + ":" + localName; + if (qName.equals(qn)) + return i; + } + return -1; + } + + public int getIndex(String uri, String localName) + { + int len = reader.getAttributeCount(); + for (int i = 0; i < len; i++) + { + QName q = reader.getAttributeName(i); + String ln = q.getLocalPart(); + String u = q.getNamespaceURI(); + if (u == null && uri != null) + continue; + if (u != null && !u.equals(uri)) + continue; + if (ln.equals(localName)) + return i; + } + return -1; + } + + public int getLength() + { + return reader.getAttributeCount(); + } + + public String getLocalName(int index) + { + return reader.getAttributeLocalName(index); + } + + public String getQName(int index) + { + QName q = reader.getAttributeName(index); + String localName = q.getLocalPart(); + String prefix = q.getPrefix(); + return ("".equals(prefix)) ? localName : prefix + ":" + localName; + } + + public String getType(int index) + { + String ret = reader.getAttributeType(index); + // SAX doesn't permit ENUMERATION? + return ("ENUMERATION".equals(ret)) ? "NMTOKEN" : ret; + } + + public String getType(String qName) + { + int index = getIndex(qName); + return (index == -1) ? null : getType(index); + } + + public String getType(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? null : getType(index); + } + + public String getURI(int index) + { + String ret = reader.getAttributeNamespace(index); + return (ret == null) ? "" : ret; + } + + public String getValue(int index) + { + return reader.getAttributeValue(index); + } + + public String getValue(String qName) + { + int index = getIndex(qName); + return (index == -1) ? null : getValue(index); + } + + public String getValue(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? null : getValue(index); + } + + public boolean isDeclared(int index) + { + return parser.isAttributeDeclared(index); + } + + public boolean isDeclared(String qName) + { + int index = getIndex(qName); + return (index == -1) ? false : isDeclared(index); + } + + public boolean isDeclared(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? false : isDeclared(index); + } + + public boolean isSpecified(int index) + { + return reader.isAttributeSpecified(index); + } + + public boolean isSpecified(String qName) + { + int index = getIndex(qName); + return (index == -1) ? false : isSpecified(index); + } + + public boolean isSpecified(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? false : isSpecified(index); + } + + // -- Locator2 -- + + public int getColumnNumber() + { + Location l = reader.getLocation(); + return l.getColumnNumber(); + } + + public int getLineNumber() + { + Location l = reader.getLocation(); + return l.getLineNumber(); + } + + public String getPublicId() + { + Location l = reader.getLocation(); + return l.getPublicId(); + } + + public String getSystemId() + { + Location l = reader.getLocation(); + return l.getSystemId(); + } + + public String getEncoding() + { + return encoding; + } + + public String getXMLVersion() + { + return xmlVersion; + } + + // -- XMLResolver -- + + public Object resolveEntity(String publicId, String systemId, + String baseURI, String namespace) + throws XMLStreamException + { + if (entityResolver != null) + { + try + { + InputSource input = + entityResolver.resolveEntity(publicId, systemId); + if (input != null) + { + InputStream in = input.getByteStream(); + if (in == null) + { + String newSystemId = input.getSystemId(); + if (newSystemId != null && !newSystemId.equals(systemId)) + in = XMLParser.resolve(newSystemId); + } + return in; + } + } + catch (SAXException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + return null; + } + + public XMLEventReader resolveAsXMLEventReader(String uri) + throws XMLStreamException + { + // unused + return null; + } + + public XMLStreamReader resolveAsXMLStreamReader(String uri) + throws XMLStreamException + { + // unused + return null; + } + + // -- XMLReporter -- + + public void report(String message, String errorType, + Object relatedInformation, Location location) + throws XMLStreamException + { + if (errorHandler != null) + { + try + { + errorHandler.warning(new SAXParseException(message, this)); + } + catch (SAXException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + } + + public static void main(String[] args) + throws Exception + { + boolean validating = false; + boolean namespaceAware = false; + boolean xIncludeAware = false; + boolean expectCallbackClass = false; + String callbackClass = null; + int pos = 0; + while (pos < args.length && (args[pos].startsWith("-") || expectCallbackClass)) + { + if ("-x".equals(args[pos])) + xIncludeAware = true; + else if ("-v".equals(args[pos])) + validating = true; + else if ("-n".equals(args[pos])) + namespaceAware = true; + else if ("-c".equals(args[pos])) + expectCallbackClass = true; + else if (expectCallbackClass) + { + callbackClass = args[pos]; + expectCallbackClass = false; + } + pos++; + } + if (pos >= args.length || expectCallbackClass) + { + System.out.println("Syntax: SAXParser [-n] [-v] [-x] [-c ] [ [...]]"); + System.out.println("\t-n: use namespace aware mode"); + System.out.println("\t-v: use validating parser"); + System.out.println("\t-x: use XInclude aware mode"); + System.out.println("\t-c : use specified class as callback handler (must have a no-arg public constructor)"); + System.exit(2); + } + while (pos < args.length) + { + ContentHandler handler = null; + if (callbackClass != null) + { + Class t = Class.forName(callbackClass); + handler = (ContentHandler) t.newInstance(); + } + else + handler = new org.xml.sax.helpers.DefaultHandler(); + SAXParser parser = new SAXParser(validating, namespaceAware, + xIncludeAware); + InputSource input = new InputSource(args[pos]); + java.io.FileReader fr = new java.io.FileReader(args[pos]); + input.setCharacterStream(fr); + try + { + XMLReader reader = parser.getXMLReader(); + reader.setContentHandler(handler); + reader.parse(input); + } + finally + { + fr.close(); + } + pos++; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/SAXParserFactory.java b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java new file mode 100644 index 000000000..ebaeb3cb2 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java @@ -0,0 +1,104 @@ +/* SAXParserFactory.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * SAX parser factory providing a SAX compatibility layer on top of StAX. + * + * @author Chris Burdess + */ +public class SAXParserFactory + extends javax.xml.parsers.SAXParserFactory +{ + + static final Set FEATURE_NAMES = new HashSet(); + static + { + FEATURE_NAMES.add("http://xml.org/sax/features/namespaces"); + FEATURE_NAMES.add("http://xml.org/sax/features/string-interning"); + FEATURE_NAMES.add("http://xml.org/sax/features/validation"); + } + + Map features = new HashMap(); + + public javax.xml.parsers.SAXParser newSAXParser() + throws ParserConfigurationException, SAXException + { + boolean validating = isValidating(); + boolean namespaceAware = isNamespaceAware(); + boolean xIncludeAware = isXIncludeAware(); + SAXParser ret = new SAXParser(validating, namespaceAware, xIncludeAware); + for (Iterator i = features.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String name = (String) entry.getKey(); + Boolean value = (Boolean) entry.getValue(); + ret.setFeature(name, value.booleanValue()); + } + return ret; + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + if (!FEATURE_NAMES.contains(name)) + throw new SAXNotSupportedException(name); + features.put(name, value ? Boolean.TRUE : Boolean.FALSE); + } + + public boolean getFeature(String name) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + if (!FEATURE_NAMES.contains(name)) + throw new SAXNotSupportedException(name); + Boolean value = (Boolean) features.get(name); + return (value == null) ? false : value.booleanValue(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java b/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java new file mode 100644 index 000000000..d2e590cfc --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java @@ -0,0 +1,143 @@ +/* StartDocumentImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartDocument; + +/** + * A start-document event. + * + * @author Chris Burdess + */ +public class StartDocumentImpl + extends XMLEventImpl + implements StartDocument +{ + + protected final String systemId; + protected final String encoding; + protected final String xmlVersion; + protected final boolean xmlStandalone; + protected final boolean standaloneDeclared; + protected final boolean encodingDeclared; + + protected StartDocumentImpl(Location location, + String systemId, String encoding, + String xmlVersion, boolean xmlStandalone, + boolean standaloneDeclared, + boolean encodingDeclared) + { + super(location); + this.systemId = systemId; + this.encoding = encoding; + this.xmlVersion = xmlVersion; + this.xmlStandalone = xmlStandalone; + this.standaloneDeclared = standaloneDeclared; + this.encodingDeclared = encodingDeclared; + } + + public int getEventType() + { + return START_DOCUMENT; + } + + public String getSystemId() + { + return systemId; + } + + public String getCharacterEncodingScheme() + { + return encoding; + } + + public boolean encodingSet() + { + return encodingDeclared; + } + + public boolean isStandalone() + { + return xmlStandalone; + } + + public boolean standaloneSet() + { + return standaloneDeclared; + } + + public String getVersion() + { + return xmlVersion; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/StartElementImpl.java b/libjava/classpath/gnu/xml/stream/StartElementImpl.java new file mode 100644 index 000000000..66e68d560 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/StartElementImpl.java @@ -0,0 +1,152 @@ +/* StartElementImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.StartElement; + +/** + * A start-element event. + * + * @author Chris Burdess + */ +public class StartElementImpl + extends XMLEventImpl + implements StartElement +{ + + protected final QName name; + protected final List attributes; + protected final List namespaces; + protected final NamespaceContext namespaceContext; + + protected StartElementImpl(Location location, + QName name, List attributes, List namespaces, + NamespaceContext namespaceContext) + { + super(location); + this.name = name; + this.attributes = attributes; + this.namespaces = namespaces; + this.namespaceContext = namespaceContext; + } + + public int getEventType() + { + return START_ELEMENT; + } + + public QName getName() + { + return name; + } + + public Iterator getAttributes() + { + return attributes.iterator(); + } + + public Iterator getNamespaces() + { + return namespaces.iterator(); + } + + public Attribute getAttributeByName(QName name) + { + for (Iterator i = attributes.iterator(); i.hasNext(); ) + { + Attribute attr = (Attribute) i.next(); + if (name.equals(attr.getName())) + return attr; + } + return null; + } + + public NamespaceContext getNamespaceContext() + { + return namespaceContext; + } + + public String getNamespaceURI(String prefix) + { + return namespaceContext.getNamespaceURI(prefix); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write('<'); + String prefix = name.getPrefix(); + if (prefix != null && !"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + writer.write(' '); + ((Namespace) i.next()).writeAsEncodedUnicode(writer); + } + for (Iterator i = attributes.iterator(); i.hasNext(); ) + { + writer.write(' '); + ((Attribute) i.next()).writeAsEncodedUnicode(writer); + } + writer.write('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/UnicodeReader.java b/libjava/classpath/gnu/xml/stream/UnicodeReader.java new file mode 100644 index 000000000..aa2a95422 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/UnicodeReader.java @@ -0,0 +1,205 @@ +/* UnicodeReader.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Reader; + +/** + * A reader that converts UTF-16 characters to Unicode code points. + * + * @author Chris Burdess + */ +public class UnicodeReader +{ + + final Reader in; + + UnicodeReader(Reader in) + { + this.in = in; + } + + public void mark(int limit) + throws IOException + { + in.mark(limit * 2); + } + + public void reset() + throws IOException + { + in.reset(); + } + + public int read() + throws IOException + { + int ret = in.read(); + if (ret == -1) + return ret; + if (ret >= 0xd800 && ret < 0xdc00) + { + // Unicode surrogate? + int low = in.read(); + if (low >= 0xdc00 && low < 0xe000) + ret = Character.toCodePoint((char) ret, (char) low); + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(ret)); + } + else if (ret >= 0xdc00 && ret < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(ret)); + return ret; + } + + public int read(int[] buf, int off, int len) + throws IOException + { + if (len == 0) + return 0; + char[] b2 = new char[len]; + int ret = in.read(b2, 0, len); + if (ret <= 0) + return ret; + int l = ret - 1; + int i = 0, j = off; + for (; i < l; i++) + { + char c = b2[i]; + if (c >= 0xd800 && c < 0xdc00) + { + // Unicode surrogate? + char d = b2[i + 1]; + if (d >= 0xdc00 && d < 0xe000) + { + buf[j++] = Character.toCodePoint(c, d); + i++; + continue; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + if (i == l) + { + // last char + char c = b2[l]; + if (c >= 0xd800 && c < 0xdc00) + { + int low = in.read(); + if (low >= 0xdc00 && low < 0xe000) + { + buf[j++] = Character.toCodePoint(c, (char) low); + return j; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + return j; + } + + public void close() + throws IOException + { + in.close(); + } + + /** + * Returns the specified UTF-16 char array as an array of Unicode code + * points. + */ + public static int[] toCodePointArray(String text) + throws IOException + { + char[] b2 = text.toCharArray(); + int[] buf = new int[b2.length]; + if (b2.length > 0) + { + int l = b2.length - 1; + int i = 0, j = 0; + for (; i < l; i++) + { + char c = b2[i]; + if (c >= 0xd800 && c < 0xdc00) + { + // Unicode surrogate? + char d = b2[i + 1]; + if (d >= 0xdc00 && d < 0xe000) + { + buf[j++] = Character.toCodePoint(c, d); + i++; + continue; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + if (i == l) + { + // last char + buf[j++] = (int) b2[l]; + if (j < buf.length) + { + int[] buf2 = new int[j]; + System.arraycopy(buf, 0, buf2, 0, j); + buf = buf2; + } + } + } + return buf; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XIncludeFilter.java b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java new file mode 100644 index 000000000..6d955c492 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java @@ -0,0 +1,931 @@ +/* XIncludeFilter.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathNSResolver; +import org.w3c.dom.xpath.XPathResult; +import org.xml.sax.SAXException; + +/** + * StAX filter for performing XInclude processing. + * + * @see http://www.w3.org/TR/xinclude/ + * @see http://www.w3.org/TR/xptr-framework/ + * @see http://www.w3.org/TR/xptr-element/ + * + * @author Chris Burdess + */ +class XIncludeFilter + extends StreamReaderDelegate +{ + + static final String XINCLUDE_NS_URI = "http://www.w3.org/2001/XInclude"; + static final int SHOW_FLAGS = + NodeFilter.SHOW_CDATA_SECTION | + NodeFilter.SHOW_COMMENT | + NodeFilter.SHOW_ELEMENT | + NodeFilter.SHOW_ENTITY_REFERENCE | + NodeFilter.SHOW_PROCESSING_INSTRUCTION | + NodeFilter.SHOW_TEXT; + + final String systemId; + final boolean namespaceAware; + final boolean validating; + final boolean expandERefs; + String href; + int event; + boolean included; + XPathResult result; + int snapshotIndex; + Node current; + TreeWalker walker; + HashSet seen = new HashSet(); + boolean backtracking; + boolean lookahead; + + Reader includedText; + char[] buf; + int len = -1; + boolean inInclude, inFallback, seenFallback; + + DocumentBuilder builder; + + XIncludeFilter(XMLStreamReader reader, String systemId, + boolean namespaceAware, boolean validating, + boolean expandERefs) + { + super(reader); + this.systemId = XMLParser.absolutize(null, systemId); + this.namespaceAware = namespaceAware; + this.validating = validating; + this.expandERefs = expandERefs; + } + + public int getAttributeCount() + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + return (attrs == null) ? 0 : attrs.getLength(); + } + return super.getAttributeCount(); + } + + public String getAttributeLocalName(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getLocalName(); + } + return super.getAttributeLocalName(index); + } + + public String getAttributeNamespace(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getNamespaceURI(); + } + return super.getAttributeNamespace(index); + } + + public String getAttributePrefix(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getPrefix(); + } + return super.getAttributePrefix(index); + } + + public QName getAttributeName(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + String localName = attr.getLocalName(); + String uri = attr.getNamespaceURI(); + String prefix = attr.getPrefix(); + return new QName(uri, localName, prefix); + } + return super.getAttributeName(index); + } + + public String getAttributeType(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Attr attr = (Attr) attrs.item(index); + TypeInfo ti = attr.getSchemaTypeInfo(); + return (ti == null) ? "CDATA" : ti.getTypeName(); + } + return super.getAttributeType(index); + } + + public boolean isAttributeSpecified(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return false; + Attr attr = (Attr) attrs.item(index); + return attr.getSpecified(); + } + return super.isAttributeSpecified(index); + } + + public String getAttributeValue(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getNodeValue(); + } + return super.getAttributeValue(index); + } + + public String getAttributeValue(String uri, String localName) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.getNamedItemNS(uri, localName); + return (attr == null) ? null : attr.getNodeValue(); + } + return super.getAttributeValue(uri, localName); + } + + public String getElementText() + throws XMLStreamException + { + if (current != null) + return current.getTextContent(); + return super.getElementText(); + } + + public int getEventType() + { + return event; + } + + public String getLocalName() + { + if (current != null) + return current.getLocalName(); + return super.getLocalName(); + } + + public QName getName() + { + if (current != null) + { + String localName = current.getLocalName(); + String uri = current.getNamespaceURI(); + String prefix = current.getPrefix(); + return new QName(uri, localName, prefix); + } + return super.getName(); + } + + public String getNamespaceURI() + { + if (current != null) + return current.getNamespaceURI(); + return super.getNamespaceURI(); + } + + // TODO namespaces + + public String getPIData() + { + if (current != null) + return ((ProcessingInstruction) current).getData(); + return super.getPIData(); + } + + public String getPITarget() + { + if (current != null) + return ((ProcessingInstruction) current).getTarget(); + return super.getPITarget(); + } + + public String getPrefix() + { + if (current != null) + return current.getPrefix(); + return super.getPrefix(); + } + + public String getText() + { + if (current != null) + return current.getNodeValue(); + if (walker != null) + { + Node n = walker.getCurrentNode(); + if (n != null) + return n.getTextContent(); + } + if (buf != null) + return new String(buf, 0, len); + return super.getText(); + } + + public char[] getTextCharacters() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return buf; + return super.getTextCharacters(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) + throws XMLStreamException + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + { + int max = Math.min(len - sourceStart, length); + if (max > 0) + System.arraycopy(buf, sourceStart, target, targetStart, max); + return max; + } + return super.getTextCharacters(sourceStart, target, targetStart, length); + } + + public int getTextLength() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return len; + return super.getTextLength(); + } + + public int getTextStart() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return 0; + return super.getTextStart(); + } + + public boolean hasNext() + throws XMLStreamException + { + if (!lookahead) + { + try + { + next(); + } + catch (NoSuchElementException e) + { + event = -1; + } + lookahead = true; + } + return (event != -1); + } + + public int next() + throws XMLStreamException + { + if (lookahead) + { + lookahead = false; + return event; + } + buf = null; + len = 0; + if (walker != null) + { + Node c = walker.getCurrentNode(); + Node n = null; + if (c.getNodeType() == Node.ELEMENT_NODE) + { + boolean isStartElement = !seen.contains(c); + if (isStartElement) + { + seen.add(c); + current = c; + event = XMLStreamConstants.START_ELEMENT; + return event; + } + else if (backtracking) + { + n = walker.nextSibling(); + if (n != null) + backtracking = false; + } + else + { + n = walker.firstChild(); + if (n == null) + n = walker.nextSibling(); + } + } + else + { + n = walker.firstChild(); + if (n == null) + n = walker.nextSibling(); + } + if (n == null) + { + current = walker.parentNode(); + if (current != null && current.getNodeType() == Node.ELEMENT_NODE) + { + // end-element + backtracking = true; + event = XMLStreamConstants.END_ELEMENT; + return event; + } + else + { + walker = null; + current = null; + } + } + else + { + current = n; + switch (n.getNodeType()) + { + case Node.ELEMENT_NODE: + return next(); + case Node.TEXT_NODE: + String text = n.getNodeValue(); + buf = text.toCharArray(); + len = buf.length; + event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS; + return event; + case Node.CDATA_SECTION_NODE: + event = XMLStreamConstants.CDATA; + return event; + case Node.COMMENT_NODE: + event = XMLStreamConstants.COMMENT; + return event; + case Node.PROCESSING_INSTRUCTION_NODE: + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + return event; + case Node.ENTITY_REFERENCE_NODE: + event = XMLStreamConstants.ENTITY_REFERENCE; + return event; + default: + throw new IllegalStateException(); + } + } + } + if (result != null) + { + switch (result.getResultType()) + { + case XPathResult.BOOLEAN_TYPE: + boolean bval = result.getBooleanValue(); + String btext = bval ? "true" : "false"; + buf = btext.toCharArray(); + len = buf.length; + result = null; + event = XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.NUMBER_TYPE: + double nval = result.getNumberValue(); + String ntext = Double.toString(nval); + buf = ntext.toCharArray(); + len = buf.length; + result = null; + event = XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.STRING_TYPE: + String stext = result.getStringValue(); + buf = stext.toCharArray(); + len = buf.length; + result = null; + event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.ANY_UNORDERED_NODE_TYPE: + case XPathResult.FIRST_ORDERED_NODE_TYPE: + Node n1 = result.getSingleNodeValue(); + Document d1 = getDocument(n1); + walker = getDocumentTraversal(d1) + .createTreeWalker(n1, SHOW_FLAGS, null, expandERefs); + result = null; + return next(); + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + Node n2 = result.iterateNext(); + if (n2 == null) + { + result = null; + return next(); + } + Document d2 = getDocument(n2); + walker = getDocumentTraversal(d2) + .createTreeWalker(n2, SHOW_FLAGS, null, expandERefs); + return next(); + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Node n3 = result.snapshotItem(snapshotIndex++); + if (n3 == null) + { + result = null; + return next(); + } + Document d3 = getDocument(n3); + walker = getDocumentTraversal(d3) + .createTreeWalker(n3, SHOW_FLAGS, null, expandERefs); + return next(); + default: + throw new IllegalStateException(); + } + } + if (includedText != null) + { + // fill buffer + if (buf == null) + buf = new char[2048]; + try + { + len = includedText.read(buf, 0, buf.length); + if (len == -1) + { + includedText = null; + buf = null; + return next(); + } + // chars or space? + return (event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + event = super.next(); + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + String uri = getNamespaceURI(); + if (XINCLUDE_NS_URI.equals(uri)) + { + String localName = getLocalName(); + if ("include".equals(localName)) + { + href = getAttributeValue(null, "href"); + String parse = getAttributeValue(null, "parse"); + String xpointer = getAttributeValue(null, "xpointer"); + String encoding = getAttributeValue(null, "encoding"); + String accept = getAttributeValue(null, "accept"); + String acceptLanguage = getAttributeValue(null, + "accept-language"); + if (includeResource(href, parse, xpointer, encoding, + accept, acceptLanguage)) + { + // Skip to xi:include end-element event + int depth = 0; + while (depth >= 0) + { + event = super.next(); + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + depth++; + break; + case XMLStreamConstants.END_ELEMENT: + depth--; + } + } + } + else + inInclude = true; + } + else if (inInclude && "fallback".equals(localName)) + { + if (!seenFallback) + inFallback = seenFallback = true; + else + throw new XMLStreamException("duplicate xi:fallback element"); + } + else if (inInclude) + { + throw new XMLStreamException("illegal xi element '" + + localName + "'"); + } + return next(); + } + break; + case XMLStreamConstants.END_ELEMENT: + String uri2 = getNamespaceURI(); + if (XINCLUDE_NS_URI.equals(uri2)) + { + String localName = getLocalName(); + if ("include".equals(localName)) + { + if (!seenFallback && included) + { + String msg = "Unable to read " + href + + " and no xi:fallback element present"; + throw new XMLStreamException(msg); + } + included = false; + href = null; + inInclude = inFallback = seenFallback = false; + } + else if ("fallback".equals(localName)) + inFallback = false; + return next(); + } + break; + } + if (inInclude && !inFallback) + return next(); + return event; + } + + boolean isSpace(char[] text, int len) + { + boolean space = true; + for (int i = 0; i < len; i++) + { + char c = text[i]; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') + { + space = false; + break; + } + } + return space; + } + + String getBaseURI() + { + String base = (String) getParent().getProperty("gnu.xml.stream.baseURI"); + return (base == null) ? systemId : base; + } + + boolean includeResource(String href, String parse, String xpointer, + String encoding, String accept, + String acceptLanguage) + { + included = false; + try + { + if (xpointer != null) + throw new XMLStreamException("xpointer attribute not yet supported"); + String base = getBaseURI(); + if (href == null || "".equals(href)) + href = base; + else + href = XMLParser.absolutize(base, href); + if (parse == null || "xml".equals(parse)) + { + seen.clear(); + result = null; + snapshotIndex = 0; + walker = null; + current = null; + backtracking = false; + + URLConnection connection = getURLConnection(href, accept, + acceptLanguage); + InputStream in = connection.getInputStream(); + Document doc = getDocumentBuilder().parse(in, href); + DocumentTraversal dt = getDocumentTraversal(doc); + if (xpointer == null) + { + result = null; + Node item = doc.getDocumentElement(); + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + } + else + { + result = null; + snapshotIndex = 0; + walker = null; + // shorthand or scheme-based? + int lpi = xpointer.indexOf('('); + int rpi = xpointer.indexOf(')', lpi); + if (lpi != -1 && rpi != -1) + { + String scheme = xpointer.substring(0, lpi); + if ("element".equals(scheme)) + { + // element() scheme + String elementSchemeData = + xpointer.substring(lpi + 1, rpi); + Node item = doc; + int si = elementSchemeData.indexOf('/'); + if (si == -1) + { + if (elementSchemeData.length() > 0) + item = doc.getElementById(elementSchemeData); + } + else + { + if (si > 0) + { + String context = + elementSchemeData.substring(0, si); + item = doc.getElementById(context); + elementSchemeData = + elementSchemeData.substring(si + 1); + } + StringTokenizer st = + new StringTokenizer(elementSchemeData, "/"); + while (st.hasMoreTokens() && item != null) + { + int n = Integer.parseInt(st.nextToken()); + Node ctx = item.getFirstChild(); + int count = 1; + while (ctx != null && count++ < n) + ctx = ctx.getNextSibling(); + item = ctx; + } + } + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + included = true; + } + else if ("xpointer".equals(scheme)) + { + xpointer = xpointer.substring(lpi + 1, rpi); + XPathEvaluator eval = getXPathEvaluator(doc); + XPathNSResolver resolver = eval.createNSResolver(doc); + result = + (XPathResult) eval.evaluate(xpointer, doc, + resolver, + XPathResult.ANY_TYPE, + null); + // TODO xpointer() scheme functions + included = true; + } + else + { + String msg = "Unknown XPointer scheme: " + scheme; + throw new XMLStreamException(msg); + } + } + else + { + Node item = doc.getElementById(xpointer); + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + included = true; + } + } + } + else if ("text".equals(parse)) + { + URLConnection connection = getURLConnection(href, accept, + acceptLanguage); + InputStream in = connection.getInputStream(); + if (encoding == null) + { + encoding = connection.getContentEncoding(); + if (encoding == null) + { + String contentType = connection.getContentType(); + if (contentType != null) + encoding = getParameter(contentType, "charset"); + } + } + if (encoding == null) + includedText = new InputStreamReader(in, "UTF-8"); + else + includedText = new InputStreamReader(in, encoding); + included = true; + } + else + throw new XMLStreamException("value of 'parse' attribute must be "+ + "'xml' or 'text'"); + return true; + } + catch (IOException e) + { + return false; + } + catch (XMLStreamException e) + { + return false; + } + catch (SAXException e) + { + return false; + } + } + + URLConnection getURLConnection(String href, String accept, + String acceptLanguage) + throws IOException + { + URL url = new URL(href); + URLConnection connection = url.openConnection(); + if (connection instanceof HttpURLConnection) + { + HttpURLConnection http = (HttpURLConnection) connection; + http.setInstanceFollowRedirects(true); + if (accept != null) + http.setRequestProperty("Accept", accept); + if (acceptLanguage != null) + http.setRequestProperty("Accept-Language", acceptLanguage); + } + return connection; + } + + Document getDocument(Node node) + { + if (node.getNodeType() == Node.DOCUMENT_NODE) + return (Document) node; + return node.getOwnerDocument(); + } + + DocumentBuilder getDocumentBuilder() + throws XMLStreamException + { + if (builder == null) + { + try + { + DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); + f.setXIncludeAware(true); + f.setNamespaceAware(namespaceAware); + f.setValidating(validating); + builder = f.newDocumentBuilder(); + } + catch (ParserConfigurationException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + builder.reset(); + return builder; + } + + DocumentTraversal getDocumentTraversal(Document doc) + throws XMLStreamException + { + DOMImplementation dom = doc.getImplementation(); + if (!dom.hasFeature("Traversal", "2.0")) + throw new XMLStreamException("Traversal not supported"); + return (DocumentTraversal) doc; + } + + XPathEvaluator getXPathEvaluator(Document doc) + throws XMLStreamException + { + DOMImplementation dom = doc.getImplementation(); + if (!dom.hasFeature("XPath", "3.0")) + throw new XMLStreamException("XPath not supported"); + return (XPathEvaluator) doc; + } + + static String getParameter(String contentType, String name) + { + StringTokenizer st = new StringTokenizer(contentType, " ;"); + if (st.hasMoreTokens()) + st.nextToken(); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + int ei = token.indexOf('='); + if (ei != -1) + { + String key = token.substring(0, ei); + if (key.equals(name)) + { + String value = token.substring(ei + 1); + int len = value.length(); + if (len > 1 && + value.charAt(0) == '"' && + value.charAt(len - 1) == '"') + value = value.substring(1, len - 1); + else if (len > 1 && + value.charAt(0) == '\'' && + value.charAt(len - 1) == '\'') + value = value.substring(1, len - 1); + return value; + } + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java new file mode 100644 index 000000000..a1824bfc5 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java @@ -0,0 +1,204 @@ +/* XMLEventAllocatorImpl.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.XMLEventAllocator; +import javax.xml.stream.util.XMLEventConsumer; + +/** + * Allocator for creating XML events based on a reader state. + * + * @author Chris Burdess + */ +public class XMLEventAllocatorImpl + implements XMLEventAllocator +{ + + protected Map entityDeclarations; + + protected XMLEventAllocatorImpl() + { + entityDeclarations = new HashMap(); + } + + public XMLEvent allocate(XMLStreamReader reader) + throws XMLStreamException + { + String text; + boolean whitespace; + boolean ignorableWhitespace; + int len; + List namespaces; + int eventType = reader.getEventType(); + Location location = reader.getLocation(); + switch (eventType) + { + case XMLStreamConstants.CDATA: + text = reader.getText(); + whitespace = isWhitespace(text); + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, true, ignorableWhitespace); + case XMLStreamConstants.CHARACTERS: + text = reader.getText(); + whitespace = false; + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, false, ignorableWhitespace); + case XMLStreamConstants.COMMENT: + text = reader.getText(); + return new CommentImpl(location, text); + case XMLStreamConstants.DTD: + text = reader.getText(); + List notations = new LinkedList(); + List entities = new LinkedList(); + // TODO readDTDBody(notations, entities); + return new DTDImpl(location, text, null, notations, entities); + case XMLStreamConstants.END_DOCUMENT: + return new EndDocumentImpl(location); + case XMLStreamConstants.END_ELEMENT: + len = reader.getNamespaceCount(); + namespaces = new LinkedList(); + for (int i = 0; i < len; i++) + namespaces.add(new NamespaceImpl(location, + reader.getNamespacePrefix(i), + reader.getNamespaceURI(i), + false)); + return new EndElementImpl(location, + reader.getName(), + namespaces); + case XMLStreamConstants.ENTITY_REFERENCE: + String name = reader.getLocalName(); + EntityDeclaration decl = + (EntityDeclaration) entityDeclarations.get(name); + return new EntityReferenceImpl(location, decl, name); + case XMLStreamConstants.PROCESSING_INSTRUCTION: + return new ProcessingInstructionImpl(location, + reader.getPITarget(), + reader.getPIData()); + case XMLStreamConstants.SPACE: + text = reader.getText(); + whitespace = true; + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, false, ignorableWhitespace); + case XMLStreamConstants.START_DOCUMENT: + String systemId = location.getSystemId(); + String encoding = reader.getCharacterEncodingScheme(); + boolean encodingDeclared = encoding != null; + if (encoding == null) + { + encoding = reader.getEncoding(); + if (encoding == null) + encoding = "UTF-8"; + } + String xmlVersion = reader.getVersion(); + if (xmlVersion == null) + xmlVersion = "1.0"; + boolean xmlStandalone = reader.isStandalone(); + boolean standaloneDeclared = reader.standaloneSet(); + return new StartDocumentImpl(location, + systemId, + encoding, + xmlVersion, + xmlStandalone, + standaloneDeclared, + encodingDeclared); + case XMLStreamConstants.START_ELEMENT: + len = reader.getNamespaceCount(); + namespaces = new LinkedList(); + for (int i = 0; i < len; i++) + namespaces.add(new NamespaceImpl(location, + reader.getNamespacePrefix(i), + reader.getNamespaceURI(i), + false)); + len = reader.getAttributeCount(); + List attributes = new LinkedList(); + for (int i = 0; i < len; i++) + attributes.add(new AttributeImpl(location, + reader.getAttributeName(i), + reader.getAttributeValue(i), + reader.getAttributeType(i), + reader.isAttributeSpecified(i))); + return new StartElementImpl(location, + reader.getName(), + attributes, namespaces, + reader.getNamespaceContext()); + default: + throw new XMLStreamException("Unknown event type: " + eventType); + } + } + + public void allocate(XMLStreamReader reader, XMLEventConsumer consumer) + throws XMLStreamException + { + consumer.add(allocate(reader)); + } + + public XMLEventAllocator newInstance() + { + return new XMLEventAllocatorImpl(); + } + + protected boolean isWhitespace(String text) + { + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d) + return false; + } + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java new file mode 100644 index 000000000..12f7f2c79 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java @@ -0,0 +1,269 @@ +/* XMLEventFactoryImpl.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; + +/** + * Factory for XML events. + * + * @author Chris Burdess + */ +public class XMLEventFactoryImpl + extends XMLEventFactory +{ + + protected Location location; + + public void setLocation(Location location) + { + this.location = location; + } + + public Attribute createAttribute(String prefix, String namespaceURI, + String localName, String value) + { + return new AttributeImpl(location, + new QName(namespaceURI, localName, prefix), + value, "CDATA", true); + } + + public Attribute createAttribute(String localName, String value) + { + return new AttributeImpl(location, + new QName(localName), + value, "CDATA", true); + } + + public Attribute createAttribute(QName name, String value) + { + return new AttributeImpl(location, name, value, + "CDATA", true); + } + + public Namespace createNamespace(String namespaceURI) + { + return new NamespaceImpl(location, + XMLConstants.DEFAULT_NS_PREFIX, + namespaceURI, + true); + } + + public Namespace createNamespace(String prefix, String namespaceUri) + { + return new NamespaceImpl(location, prefix, namespaceUri, true); + } + + public StartElement createStartElement(QName name, + Iterator attributes, + Iterator namespaces) + { + return new StartElementImpl(location, name, + createLinkedList(attributes), + createLinkedList(namespaces), + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + Collections.EMPTY_LIST, + Collections.EMPTY_LIST, + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName, + Iterator attributes, + Iterator namespaces) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(attributes), + createLinkedList(namespaces), + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName, + Iterator attributes, + Iterator namespaces, + NamespaceContext context) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(attributes), + createLinkedList(namespaces), + context); + } + + public EndElement createEndElement(QName name, + Iterator namespaces) + { + return new EndElementImpl(location, name, + createLinkedList(namespaces)); + } + + public EndElement createEndElement(String prefix, + String namespaceUri, + String localName) + { + return new EndElementImpl(location, + new QName(namespaceUri, localName, prefix), + Collections.EMPTY_LIST); + } + + public EndElement createEndElement(String prefix, + String namespaceUri, + String localName, + Iterator namespaces) + { + return new EndElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(namespaces)); + } + + public Characters createCharacters(String content) + { + return new CharactersImpl(location, content, false, false, false); + } + + public Characters createCData(String content) + { + return new CharactersImpl(location, content, false, true, false); + } + + public Characters createSpace(String content) + { + return new CharactersImpl(location, content, true, false, false); + } + + public Characters createIgnorableSpace(String content) + { + return new CharactersImpl(location, content, true, false, true); + } + + public StartDocument createStartDocument() + { + return new StartDocumentImpl(location, null, "UTF-8", "1.0", + false, false, false); + } + + public StartDocument createStartDocument(String encoding, + String version, + boolean standalone) + { + return new StartDocumentImpl(location, null, encoding, version, + standalone, true, true); + } + + public StartDocument createStartDocument(String encoding, + String version) + { + return new StartDocumentImpl(location, null, encoding, version, + false, false, true); + } + + public StartDocument createStartDocument(String encoding) + { + return new StartDocumentImpl(location, null, encoding, "1.0", + false, false, true); + } + + public EndDocument createEndDocument() + { + return new EndDocumentImpl(location); + } + + public EntityReference createEntityReference(String name, + EntityDeclaration declaration) + { + return new EntityReferenceImpl(location, declaration, name); + } + + public Comment createComment(String text) + { + return new CommentImpl(location, text); + } + + public ProcessingInstruction createProcessingInstruction(String target, + String data) + { + return new ProcessingInstructionImpl(location, target, data); + } + + public DTD createDTD(String dtd) + { + return new DTDImpl(location, dtd, null, + Collections.EMPTY_LIST, + Collections.EMPTY_LIST); + } + + LinkedList createLinkedList(Iterator i) + { + LinkedList ret = new LinkedList(); + while (i.hasNext()) + ret.add(i.next()); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventImpl.java new file mode 100644 index 000000000..2e650bf74 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventImpl.java @@ -0,0 +1,198 @@ +/* XMLEventImpl.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +/** + * An XML stream event. + * + * @author Chris Burdess + */ +public abstract class XMLEventImpl + implements XMLEvent +{ + + protected final Location location; + + protected XMLEventImpl(Location location) + { + this.location = location; + } + + public abstract int getEventType(); + + public Location getLocation() + { + return location; + } + + public boolean isStartElement() + { + return getEventType() == START_ELEMENT; + } + + public boolean isAttribute() + { + return getEventType() == ATTRIBUTE; + } + + public boolean isNamespace() + { + return getEventType() == NAMESPACE; + } + + public boolean isEndElement() + { + return getEventType() == END_ELEMENT; + } + + public boolean isEntityReference() + { + return getEventType() == ENTITY_REFERENCE; + } + + public boolean isProcessingInstruction() + { + return getEventType() == PROCESSING_INSTRUCTION; + } + + public boolean isCharacters() + { + int et = getEventType(); + return et == CHARACTERS || et == CDATA; + } + + public boolean isStartDocument() + { + return getEventType() == START_DOCUMENT; + } + + public boolean isEndDocument() + { + return getEventType() == END_DOCUMENT; + } + + public StartElement asStartElement() + { + return (StartElement) this; + } + + public EndElement asEndElement() + { + return (EndElement) this; + } + + public Characters asCharacters() + { + return (Characters) this; + } + + public QName getSchemaType() + { + return null; + } + + public abstract void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException; + + protected String encode(String text, boolean inAttr) + { + int len = text.length(); + CPStringBuilder buf = null; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '<') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("<"); + } + else if (c == '>') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append(">"); + } + else if (c == '&') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("&"); + } + else if (c == '\'' && inAttr) + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("'"); + } + else if (c == '"' && inAttr) + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("""); + } + else if (buf != null) + { + buf.append(c); + } + } + return (buf == null) ? text : buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java new file mode 100644 index 000000000..bab6d9378 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java @@ -0,0 +1,157 @@ +/* XMLEventReaderImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.XMLEventAllocator; + +/** + * Parser using XML events. + * + * @author Chris Burdess + */ +public class XMLEventReaderImpl + implements XMLEventReader +{ + + protected final XMLStreamReader reader; + protected final XMLEventAllocator allocator; + protected final String systemId; + protected XMLEvent peekEvent; + + protected XMLEventReaderImpl(XMLStreamReader reader, + XMLEventAllocator allocator, + String systemId) + { + this.reader = reader; + this.allocator = allocator; + this.systemId = systemId; + } + + public XMLEvent nextEvent() + throws XMLStreamException + { + XMLEvent ret = peek(); + peekEvent = null; + return ret; + } + + public Object next() + { + try + { + return nextEvent(); + } + catch (XMLStreamException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + + public boolean hasNext() + { + if (peekEvent != null) + return true; + try + { + return reader.hasNext(); + } + catch (XMLStreamException e) + { + return false; + } + } + + public XMLEvent peek() + throws XMLStreamException + { + if (peekEvent != null) + return peekEvent; + if (!reader.hasNext()) + return null; + reader.next(); + peekEvent = allocator.allocate(reader); + return peekEvent; + } + + public String getElementText() + throws XMLStreamException + { + return reader.getElementText(); + } + + public XMLEvent nextTag() + throws XMLStreamException + { + if (peekEvent != null) + { + int eventType = peekEvent.getEventType(); + if (eventType == XMLStreamConstants.START_ELEMENT || + eventType == XMLStreamConstants.END_ELEMENT) + return peekEvent; + else + peekEvent = null; + } + reader.nextTag(); + return allocator.allocate(reader); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + return reader.getProperty(name); + } + + public void close() + throws XMLStreamException + { + reader.close(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java new file mode 100644 index 000000000..33b1dce31 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java @@ -0,0 +1,190 @@ +/* XMLEventWriterImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +/** + * Writer to write events to an underlying XML stream writer. + * + * @author Chris Burdess + */ +public class XMLEventWriterImpl + implements XMLEventWriter +{ + + protected final XMLStreamWriter writer; + + protected XMLEventWriterImpl(XMLStreamWriter writer) + { + this.writer = writer; + } + + public void flush() + throws XMLStreamException + { + writer.flush(); + } + + public void close() + throws XMLStreamException + { + writer.close(); + } + + public void add(XMLEvent event) + throws XMLStreamException + { + QName name; + String uri; + switch (event.getEventType()) + { + case XMLStreamConstants.START_ELEMENT: + StartElement startElement = event.asStartElement(); + name = startElement.getName(); + uri = name.getNamespaceURI(); + if (uri != null && !"".equals(uri)) + writer.writeStartElement(name.getPrefix(), name.getLocalPart(), uri); + else + writer.writeStartElement(name.getLocalPart()); + break; + case XMLStreamConstants.END_ELEMENT: + writer.writeEndElement(); + break; + case XMLStreamConstants.ATTRIBUTE: + Attribute attribute = (Attribute) event; + name = attribute.getName(); + uri = name.getNamespaceURI(); + if (uri != null && !"".equals(uri)) + writer.writeAttribute(name.getPrefix(), uri, name.getLocalPart(), + attribute.getValue()); + else + writer.writeAttribute(name.getLocalPart(), attribute.getValue()); + break; + case XMLStreamConstants.NAMESPACE: + Namespace namespace = (Namespace) event; + uri = namespace.getNamespaceURI(); + writer.writeNamespace(namespace.getPrefix(), uri); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + ProcessingInstruction pi = (ProcessingInstruction) event; + String data = pi.getData(); + if (data == null) + writer.writeProcessingInstruction(pi.getTarget()); + else + writer.writeProcessingInstruction(pi.getTarget(), data); + break; + case XMLStreamConstants.COMMENT: + Comment comment = (Comment) event; + writer.writeComment(comment.getText()); + break; + case XMLStreamConstants.START_DOCUMENT: + StartDocument startDocument = (StartDocument) event; + writer.writeStartDocument(startDocument.getVersion()); + break; + case XMLStreamConstants.END_DOCUMENT: + writer.writeEndDocument(); + break; + case XMLStreamConstants.DTD: + DTD dtd = (DTD) event; + writer.writeDTD(dtd.getDocumentTypeDeclaration()); + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + Characters characters = event.asCharacters(); + writer.writeCharacters(characters.getData()); + break; + case XMLStreamConstants.CDATA: + Characters cdata = event.asCharacters(); + writer.writeCData(cdata.getData()); + break; + } + } + + public void add(XMLEventReader reader) + throws XMLStreamException + { + while (reader.hasNext()) + add(reader.nextEvent()); + } + + public String getPrefix(String uri) + throws XMLStreamException + { + return writer.getPrefix(uri); + } + + public void setPrefix(String prefix, String uri) + throws XMLStreamException + { + writer.setPrefix(prefix, uri); + } + + public void setDefaultNamespace(String uri) + throws XMLStreamException + { + writer.setDefaultNamespace(uri); + } + + public void setNamespaceContext(NamespaceContext context) + throws XMLStreamException + { + writer.setNamespaceContext(context); + } + + public NamespaceContext getNamespaceContext() + { + return writer.getNamespaceContext(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java new file mode 100644 index 000000000..87aa32107 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java @@ -0,0 +1,397 @@ +/* XMLInputFactoryImpl.java -- + Copyright (C) 2005,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.stream.EventFilter; +import javax.xml.stream.StreamFilter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.util.XMLEventAllocator; + +/** + * Factory for creating parsers from various kinds of XML source. + * + * @author Chris Burdess + */ +public class XMLInputFactoryImpl + extends XMLInputFactory +{ + + protected XMLResolver resolver; + protected XMLReporter reporter; + protected XMLEventAllocator allocator; + + protected boolean validating; + protected boolean namespaceAware = true; + protected boolean coalescing; + protected boolean replacingEntityReferences = true; + protected boolean externalEntities = true; + protected boolean supportDTD = true; + protected boolean xIncludeAware = false; + protected boolean baseAware = true; + protected boolean stringInterning = true; + + public XMLInputFactoryImpl() + { + allocator = new XMLEventAllocatorImpl(); + } + + public XMLStreamReader createXMLStreamReader(Reader reader) + throws XMLStreamException + { + return createXMLStreamReader(null, reader); + } + + public XMLStreamReader createXMLStreamReader(Source source) + throws XMLStreamException + { + String systemId = source.getSystemId(); + InputStream in = getInputStream(source); + XMLParser ret = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, systemId, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLStreamReader createXMLStreamReader(InputStream in) + throws XMLStreamException + { + return createXMLStreamReader(null, in); + } + + public XMLStreamReader createXMLStreamReader(InputStream in, String encoding) + throws XMLStreamException + { + return createXMLStreamReader(in); + } + + public XMLStreamReader createXMLStreamReader(String systemId, InputStream in) + throws XMLStreamException + { + XMLParser ret = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, null, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLStreamReader createXMLStreamReader(String systemId, Reader reader) + throws XMLStreamException + { + XMLParser ret = new XMLParser(reader, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, null, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLEventReader createXMLEventReader(Reader reader) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(reader); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(String systemId, Reader reader) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(systemId, reader); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(XMLStreamReader reader) + throws XMLStreamException + { + return new XMLEventReaderImpl(reader, allocator, null); + } + + public XMLEventReader createXMLEventReader(Source source) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(source); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(InputStream in) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(in); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(InputStream in, String encoding) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(in, encoding); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(String systemId, InputStream in) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(systemId, in); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLStreamReader createFilteredReader(XMLStreamReader reader, + StreamFilter filter) + throws XMLStreamException + { + return new FilteredStreamReader(reader, filter); + } + + public XMLEventReader createFilteredReader(XMLEventReader reader, + EventFilter filter) + throws XMLStreamException + { + return new FilteredEventReader(reader, filter); + } + + public XMLResolver getXMLResolver() + { + return resolver; + } + + public void setXMLResolver(XMLResolver resolver) + { + this.resolver = resolver; + } + + public XMLReporter getXMLReporter() + { + return reporter; + } + + public void setXMLReporter(XMLReporter reporter) + { + this.reporter = reporter; + } + + public void setProperty(String name, Object value) + throws IllegalArgumentException + { + if (name.equals(IS_NAMESPACE_AWARE)) + namespaceAware = ((Boolean) value).booleanValue(); + else if (name.equals(IS_VALIDATING)) + validating = ((Boolean) value).booleanValue(); + else if (name.equals(IS_COALESCING)) + coalescing = ((Boolean) value).booleanValue(); + else if (name.equals(IS_REPLACING_ENTITY_REFERENCES)) + replacingEntityReferences = ((Boolean) value).booleanValue(); + else if (name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES)) + externalEntities = ((Boolean) value).booleanValue(); + else if (name.equals(SUPPORT_DTD)) + supportDTD = ((Boolean) value).booleanValue(); + else if (name.equals(REPORTER)) + reporter = (XMLReporter) value; + else if (name.equals(RESOLVER)) + resolver = (XMLResolver) value; + else if (name.equals(ALLOCATOR)) + allocator = (XMLEventAllocator) value; + else if (name.equals("gnu.xml.stream.stringInterning")) + stringInterning = ((Boolean) value).booleanValue(); + else if (name.equals("gnu.xml.stream.baseAware")) + baseAware = ((Boolean) value).booleanValue(); + else if (name.equals("gnu.xml.stream.xIncludeAware")) + xIncludeAware = ((Boolean) value).booleanValue(); + else + throw new IllegalArgumentException(name); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (name.equals(IS_NAMESPACE_AWARE)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_VALIDATING)) + return validating ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_COALESCING)) + return coalescing ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_REPLACING_ENTITY_REFERENCES)) + return replacingEntityReferences ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(SUPPORT_DTD)) + return supportDTD ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(REPORTER)) + return reporter; + if (name.equals(RESOLVER)) + return resolver; + if (name.equals(ALLOCATOR)) + return allocator; + if (name.equals("gnu.xml.stream.stringInterning")) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if (name.equals("gnu.xml.stream.baseAware")) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if (name.equals("gnu.xml.stream.xIncludeAware")) + return xIncludeAware ? Boolean.TRUE : Boolean.FALSE; + throw new IllegalArgumentException(name); + } + + public boolean isPropertySupported(String name) + { + return name.equals(IS_NAMESPACE_AWARE) || + name.equals(IS_VALIDATING) || + name.equals(IS_COALESCING) || + name.equals(IS_REPLACING_ENTITY_REFERENCES) || + name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES) || + name.equals(SUPPORT_DTD) || + name.equals(REPORTER) || + name.equals(RESOLVER) || + name.equals(ALLOCATOR) || + name.equals("gnu.xml.stream.stringInterning") || + name.equals("gnu.xml.stream.baseAware") || + name.equals("gnu.xml.stream.xIncludeAware"); + } + + public void setEventAllocator(XMLEventAllocator allocator) + { + this.allocator = allocator; + } + + public XMLEventAllocator getEventAllocator() + { + return allocator; + } + + public void setCoalescing(boolean coalescing) + { + this.coalescing = coalescing; + } + + public boolean isCoalescing() + { + return coalescing; + } + + protected InputStream getInputStream(Source source) + throws XMLStreamException + { + InputStream in = null; + if (source instanceof StreamSource) + { + StreamSource streamSource = (StreamSource) source; + in = streamSource.getInputStream(); + } + if (in == null) + { + String systemId = source.getSystemId(); + try + { + URL url = new URL(systemId); + try + { + in = url.openStream(); + } + catch (IOException e2) + { + XMLStreamException e3 = new XMLStreamException(e2); + e3.initCause(e2); + throw e3; + } + } + catch (MalformedURLException e) + { + // Fall back to relative file + if (File.separatorChar != '/') + systemId = systemId.replace('/', File.separatorChar); + try + { + in = new FileInputStream(systemId); + } + catch (FileNotFoundException e2) + { + XMLStreamException e3 = new XMLStreamException(e2); + e3.initCause(e2); + throw e3; + } + } + } + return in; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java new file mode 100644 index 000000000..d849e8ba5 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java @@ -0,0 +1,187 @@ +/* XMLOutputFactoryImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.io.UnsupportedEncodingException; + +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** + * Standard output factory. + * + * @author Chris Burdess + */ +public class XMLOutputFactoryImpl + extends XMLOutputFactory +{ + + protected boolean prefixDefaulting = false; + + public XMLOutputFactoryImpl() + { + } + + public XMLStreamWriter createXMLStreamWriter(Writer stream) + throws XMLStreamException + { + // XXX try to determine character encoding of writer? + return new XMLStreamWriterImpl(stream, null, prefixDefaulting); + } + + public XMLStreamWriter createXMLStreamWriter(OutputStream stream) + throws XMLStreamException + { + return createXMLStreamWriter(stream, "UTF-8"); + } + + public XMLStreamWriter createXMLStreamWriter(OutputStream stream, + String encoding) + throws XMLStreamException + { + if (encoding == null) + encoding = "UTF-8"; + try + { + Writer writer = new OutputStreamWriter(stream, encoding); + return new XMLStreamWriterImpl(writer, encoding, prefixDefaulting); + } + catch (UnsupportedEncodingException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public XMLStreamWriter createXMLStreamWriter(Result result) + throws XMLStreamException + { + if (result instanceof StreamResult) + { + StreamResult sr = (StreamResult) result; + OutputStream out = sr.getOutputStream(); + if (out != null) + return createXMLStreamWriter(out); + Writer writer = sr.getWriter(); + if (writer != null) + return createXMLStreamWriter(writer); + } + throw new UnsupportedOperationException(); + } + + public XMLEventWriter createXMLEventWriter(OutputStream stream) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(OutputStream stream, + String encoding) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream, encoding); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(Writer stream) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(Result result) + throws XMLStreamException + { + if (result instanceof StreamResult) + { + StreamResult sr = (StreamResult) result; + OutputStream out = sr.getOutputStream(); + if (out != null) + return createXMLEventWriter(out); + Writer writer = sr.getWriter(); + if (writer != null) + return createXMLEventWriter(writer); + } + throw new UnsupportedOperationException(); + } + + public void setProperty(String name, Object value) + throws IllegalArgumentException + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + prefixDefaulting = ((Boolean) value).booleanValue(); + else + throw new IllegalArgumentException(name); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + return new Boolean(prefixDefaulting); + throw new IllegalArgumentException(name); + } + + public boolean isPropertySupported(String name) + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + return true; + return false; + } + + public boolean isPrefixDefaulting() + { + return prefixDefaulting; + } + + public void setPrefixDefaulting(boolean value) + { + prefixDefaulting = value; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLParser.java b/libjava/classpath/gnu/xml/stream/XMLParser.java new file mode 100644 index 000000000..71e876569 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLParser.java @@ -0,0 +1,5434 @@ +/* XMLParser.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +Partly derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program 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. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.stream; + +import gnu.java.lang.CPStringBuilder; + +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import gnu.java.net.CRLFInputStream; +import gnu.classpath.debug.TeeInputStream; +import gnu.classpath.debug.TeeReader; + +/** + * An XML parser. + * This parser supports the following additional StAX properties: + * + * + * + * + * + * + * + * + * + * + *
    gnu.xml.stream.stringInterningBooleanIndicates whether markup strings will be interned
    gnu.xml.stream.xmlBaseBooleanIndicates whether XML Base processing will be performed
    gnu.xml.stream.baseURIStringReturns the base URI of the current event
    + * + * @see http://www.w3.org/TR/REC-xml/ + * @see http://www.w3.org/TR/xml11/ + * @see http://www.w3.org/TR/REC-xml-names + * @see http://www.w3.org/TR/xml-names11 + * @see http://www.w3.org/TR/xmlbase/ + * + * @author Chris Burdess + */ +public class XMLParser + implements XMLStreamReader, NamespaceContext +{ + + // -- parser state machine states -- + private static final int INIT = 0; // start state + private static final int PROLOG = 1; // in prolog + private static final int CONTENT = 2; // in content + private static final int EMPTY_ELEMENT = 3; // empty element state + private static final int MISC = 4; // in Misc (after root element) + + // -- parameters for parsing literals -- + private final static int LIT_ENTITY_REF = 2; + private final static int LIT_NORMALIZE = 4; + private final static int LIT_ATTRIBUTE = 8; + private final static int LIT_DISABLE_PE = 16; + private final static int LIT_DISABLE_CREF = 32; + private final static int LIT_DISABLE_EREF = 64; + private final static int LIT_PUBID = 256; + + // -- types of attribute values -- + final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30; + final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31; + final static int ATTRIBUTE_DEFAULT_IMPLIED = 32; + final static int ATTRIBUTE_DEFAULT_REQUIRED = 33; + final static int ATTRIBUTE_DEFAULT_FIXED = 34; + + // -- additional event types -- + final static int START_ENTITY = 50; + final static int END_ENTITY = 51; + + /** + * The current input. + */ + private Input input; + + /** + * Stack of inputs representing XML general entities. + * The input representing the XML input stream or reader is always the + * first element in this stack. + */ + private LinkedList inputStack = new LinkedList(); + + /** + * Stack of start-entity events to be reported. + */ + private LinkedList startEntityStack = new LinkedList(); + + /** + * Stack of end-entity events to be reported. + */ + private LinkedList endEntityStack = new LinkedList(); + + /** + * Current parser state within the main state machine. + */ + private int state = INIT; + + /** + * The (type of the) current event. + */ + private int event; + + /** + * The element name stack. The first element in this stack will be the + * root element. + */ + private LinkedList stack = new LinkedList(); + + /** + * Stack of namespace contexts. These are maps specifying prefix-to-URI + * mappings. The first element in this stack is the most recent namespace + * context (i.e. the other way around from the element name stack). + */ + private LinkedList namespaces = new LinkedList(); + + /** + * The base-URI stack. This holds the base URI context for each element. + * The first element in this stack is the most recent context (i.e. the + * other way around from the element name stack). + */ + private LinkedList bases = new LinkedList(); + + /** + * The list of attributes for the current element, in the order defined in + * the XML stream. + */ + private ArrayList attrs = new ArrayList(); + + /** + * Buffer for text and character data. + */ + private StringBuffer buf = new StringBuffer(); + + /** + * Buffer for NMTOKEN strings (markup). + */ + private StringBuffer nmtokenBuf = new StringBuffer(); + + /** + * Buffer for string literals. (e.g. attribute values) + */ + private StringBuffer literalBuf = new StringBuffer(); + + /** + * Temporary Unicode character buffer used during character data reads. + */ + private int[] tmpBuf = new int[1024]; + + /** + * The element content model for the current element. + */ + private ContentModel currentContentModel; + + /** + * The validation stack. This holds lists of the elements seen for each + * element, in order to determine whether the names and order of these + * elements match the content model for the element. The last entry in + * this stack represents the current element. + */ + private LinkedList validationStack; + + /** + * These sets contain the IDs and the IDREFs seen in the document, to + * ensure that IDs are unique and that each IDREF refers to an ID in the + * document. + */ + private HashSet ids, idrefs; + + /** + * The target and data associated with the current processing instruction + * event. + */ + private String piTarget, piData; + + /** + * The XML version declared in the XML declaration. + */ + private String xmlVersion; + + /** + * The encoding declared in the XML declaration. + */ + private String xmlEncoding; + + /** + * The standalone value declared in the XML declaration. + */ + private Boolean xmlStandalone; + + /** + * The document type definition. + */ + Doctype doctype; + + /** + * State variables for determining parameter-entity expansion. + */ + private boolean expandPE, peIsError; + + /** + * Whether this is a validating parser. + */ + private final boolean validating; + + /** + * Whether strings representing markup will be interned. + */ + private final boolean stringInterning; + + /** + * If true, CDATA sections will be merged with adjacent text nodes into a + * single event. + */ + private final boolean coalescing; + + /** + * Whether to replace general entity references with their replacement + * text automatically during parsing. + * Otherwise entity-reference events will be issued. + */ + private final boolean replaceERefs; + + /** + * Whether to support external entities. + */ + private final boolean externalEntities; + + /** + * Whether to support DTDs. + */ + private final boolean supportDTD; + + /** + * Whether to support XML namespaces. If true, namespace information will + * be available. Otherwise namespaces will simply be reported as ordinary + * attributes. + */ + private final boolean namespaceAware; + + /** + * Whether to support XML Base. If true, URIs specified in xml:base + * attributes will be honoured when resolving external entities. + */ + private final boolean baseAware; + + /** + * Whether to report extended event types (START_ENTITY and END_ENTITY) + * in addition to the standard event types. Used by the SAX parser. + */ + private final boolean extendedEventTypes; + + /** + * The reporter to receive parsing warnings. + */ + final XMLReporter reporter; + + /** + * Callback interface for resolving external entities. + */ + final XMLResolver resolver; + + // -- Constants for testing the next kind of markup event -- + private static final String TEST_START_ELEMENT = "<"; + private static final String TEST_END_ELEMENT = ""; + private static final String TEST_END_COMMENT = "--"; + private static final String TEST_END_PI = "?>"; + private static final String TEST_END_CDATA = "]]>"; + + /** + * The general entities predefined by the XML specification. + */ + private static final LinkedHashMap PREDEFINED_ENTITIES = new LinkedHashMap(); + static + { + PREDEFINED_ENTITIES.put("amp", "&"); + PREDEFINED_ENTITIES.put("lt", "<"); + PREDEFINED_ENTITIES.put("gt", ">"); + PREDEFINED_ENTITIES.put("apos", "'"); + PREDEFINED_ENTITIES.put("quot", "\""); + } + + /** + * Creates a new XML parser for the given input stream. + * This constructor should be used where possible, as it allows the + * encoding of the XML data to be correctly determined from the stream. + * @param in the input stream + * @param systemId the URL from which the input stream was retrieved + * (necessary if there are external entities to be resolved) + * @param validating if the parser is to be a validating parser + * @param namespaceAware if the parser should support XML Namespaces + * @param coalescing if CDATA sections should be merged into adjacent text + * nodes + * @param replaceERefs if entity references should be automatically + * replaced by their replacement text (otherwise they will be reported as + * entity-reference events) + * @param externalEntities if external entities should be loaded + * @param supportDTD if support for the XML DTD should be enabled + * @param baseAware if the parser should support XML Base to resolve + * external entities + * @param stringInterning whether strings will be interned during parsing + * @param reporter the reporter to receive warnings during processing + * @param resolver the callback interface used to resolve external + * entities + */ + public XMLParser(InputStream in, String systemId, + boolean validating, + boolean namespaceAware, + boolean coalescing, + boolean replaceERefs, + boolean externalEntities, + boolean supportDTD, + boolean baseAware, + boolean stringInterning, + boolean extendedEventTypes, + XMLReporter reporter, + XMLResolver resolver) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.coalescing = coalescing; + this.replaceERefs = replaceERefs; + this.externalEntities = externalEntities; + this.supportDTD = supportDTD; + this.baseAware = baseAware; + this.stringInterning = stringInterning; + this.extendedEventTypes = extendedEventTypes; + this.reporter = reporter; + this.resolver = resolver; + if (validating) + { + validationStack = new LinkedList(); + ids = new HashSet(); + idrefs = new HashSet(); + } + String debug = System.getProperty("gnu.xml.debug.input"); + if (debug != null) + { + try + { + File file = File.createTempFile(debug, ".xml"); + in = new TeeInputStream(in, new FileOutputStream(file)); + } + catch (IOException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + systemId = canonicalize(systemId); + pushInput(new Input(in, null, null, systemId, null, null, false, true)); + } + + /** + * Creates a new XML parser for the given character stream. + * This constructor is only available for compatibility with the JAXP + * APIs, which permit XML to be parsed from a character stream. Because + * the encoding specified by the character stream may conflict with that + * specified in the XML declaration, this method should be avoided where + * possible. + * @param in the input stream + * @param systemId the URL from which the input stream was retrieved + * (necessary if there are external entities to be resolved) + * @param validating if the parser is to be a validating parser + * @param namespaceAware if the parser should support XML Namespaces + * @param coalescing if CDATA sections should be merged into adjacent text + * nodes + * @param replaceERefs if entity references should be automatically + * replaced by their replacement text (otherwise they will be reported as + * entity-reference events) + * @param externalEntities if external entities should be loaded + * @param supportDTD if support for the XML DTD should be enabled + * @param baseAware if the parser should support XML Base to resolve + * external entities + * @param stringInterning whether strings will be interned during parsing + * @param reporter the reporter to receive warnings during processing + * @param resolver the callback interface used to resolve external + * entities + */ + public XMLParser(Reader reader, String systemId, + boolean validating, + boolean namespaceAware, + boolean coalescing, + boolean replaceERefs, + boolean externalEntities, + boolean supportDTD, + boolean baseAware, + boolean stringInterning, + boolean extendedEventTypes, + XMLReporter reporter, + XMLResolver resolver) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.coalescing = coalescing; + this.replaceERefs = replaceERefs; + this.externalEntities = externalEntities; + this.supportDTD = supportDTD; + this.baseAware = baseAware; + this.stringInterning = stringInterning; + this.extendedEventTypes = extendedEventTypes; + this.reporter = reporter; + this.resolver = resolver; + if (validating) + { + validationStack = new LinkedList(); + ids = new HashSet(); + idrefs = new HashSet(); + } + String debug = System.getProperty("gnu.xml.debug.input"); + if (debug != null) + { + try + { + File file = File.createTempFile(debug, ".xml"); + reader = new TeeReader(reader, new FileWriter(file)); + } + catch (IOException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + systemId = canonicalize(systemId); + pushInput(new Input(null, reader, null, systemId, null, null, false, true)); + } + + // -- NamespaceContext -- + + public String getNamespaceURI(String prefix) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + return XMLConstants.XML_NS_URI; + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + String namespaceURI = (String) ctx.get(prefix); + if (namespaceURI != null) + return namespaceURI; + } + return null; + } + + public String getPrefix(String namespaceURI) + { + if (XMLConstants.XML_NS_URI.equals(namespaceURI)) + return XMLConstants.XML_NS_PREFIX; + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + return XMLConstants.XMLNS_ATTRIBUTE; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + if (ctx.containsValue(namespaceURI)) + { + for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String uri = (String) entry.getValue(); + if (uri.equals(namespaceURI)) + return (String) entry.getKey(); + } + } + } + return null; + } + + public Iterator getPrefixes(String namespaceURI) + { + if (XMLConstants.XML_NS_URI.equals(namespaceURI)) + return Collections.singleton(XMLConstants.XML_NS_PREFIX).iterator(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE).iterator(); + LinkedList acc = new LinkedList(); + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + if (ctx.containsValue(namespaceURI)) + { + for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String uri = (String) entry.getValue(); + if (uri.equals(namespaceURI)) + acc.add(entry.getKey()); + } + } + } + return acc.iterator(); + } + + // -- XMLStreamReader -- + + public void close() + throws XMLStreamException + { + stack = null; + namespaces = null; + bases = null; + buf = null; + attrs = null; + doctype = null; + + inputStack = null; + validationStack = null; + ids = null; + idrefs = null; + } + + public NamespaceContext getNamespaceContext() + { + return this; + } + + public int getAttributeCount() + { + return attrs.size(); + } + + public String getAttributeLocalName(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.localName; + } + + public String getAttributeNamespace(int index) + { + String prefix = getAttributePrefix(index); + return getNamespaceURI(prefix); + } + + public String getAttributePrefix(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.prefix; + } + + public QName getAttributeName(int index) + { + Attribute a = (Attribute) attrs.get(index); + String namespaceURI = getNamespaceURI(a.prefix); + return new QName(namespaceURI, a.localName, a.prefix); + } + + public String getAttributeType(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.type; + } + + private String getAttributeType(String elementName, String attName) + { + if (doctype != null) + { + AttributeDecl att = doctype.getAttributeDecl(elementName, attName); + if (att != null) + return att.type; + } + return "CDATA"; + } + + public String getAttributeValue(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.value; + } + + public String getAttributeValue(String namespaceURI, String localName) + { + for (Iterator i = attrs.iterator(); i.hasNext(); ) + { + Attribute a = (Attribute) i.next(); + if (a.localName.equals(localName)) + { + String uri = getNamespaceURI(a.prefix); + if ((uri == null && namespaceURI == null) || + (uri != null && uri.equals(namespaceURI))) + return a.value; + } + } + return null; + } + + boolean isAttributeDeclared(int index) + { + if (doctype == null) + return false; + Attribute a = (Attribute) attrs.get(index); + String qn = ("".equals(a.prefix)) ? a.localName : + a.prefix + ":" + a.localName; + String elementName = buf.toString(); + return doctype.isAttributeDeclared(elementName, qn); + } + + public String getCharacterEncodingScheme() + { + return xmlEncoding; + } + + public String getElementText() + throws XMLStreamException + { + if (event != XMLStreamConstants.START_ELEMENT) + throw new XMLStreamException("current event must be START_ELEMENT"); + CPStringBuilder elementText = new CPStringBuilder(); + int depth = stack.size(); + while (event != XMLStreamConstants.END_ELEMENT || stack.size() > depth) + { + switch (next()) + { + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + elementText.append(buf.toString()); + } + } + return elementText.toString(); + } + + public String getEncoding() + { + return (input.inputEncoding == null) ? "UTF-8" : input.inputEncoding; + } + + public int getEventType() + { + return event; + } + + public String getLocalName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String localName = (ci == -1) ? qName : qName.substring(ci + 1); + if (stringInterning) + localName = localName.intern(); + return localName; + default: + return null; + } + } + + public Location getLocation() + { + return input; + } + + public QName getName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String localName = (ci == -1) ? qName : qName.substring(ci + 1); + if (stringInterning) + localName = localName.intern(); + String prefix = (ci == -1) ? + (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) : + qName.substring(0, ci); + if (stringInterning && prefix != null) + prefix = prefix.intern(); + String namespaceURI = getNamespaceURI(prefix); + return new QName(namespaceURI, localName, prefix); + default: + return null; + } + } + + public int getNamespaceCount() + { + if (!namespaceAware || namespaces.isEmpty()) + return 0; + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + return ctx.size(); + default: + return 0; + } + } + + public String getNamespacePrefix(int index) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + int count = 0; + for (Iterator i = ctx.keySet().iterator(); i.hasNext(); ) + { + String prefix = (String) i.next(); + if (count++ == index) + return prefix; + } + return null; + } + + public String getNamespaceURI() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + if (ci == -1) + return null; + String prefix = qName.substring(0, ci); + return getNamespaceURI(prefix); + default: + return null; + } + } + + public String getNamespaceURI(int index) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + int count = 0; + for (Iterator i = ctx.values().iterator(); i.hasNext(); ) + { + String uri = (String) i.next(); + if (count++ == index) + return uri; + } + return null; + } + + public String getPIData() + { + return piData; + } + + public String getPITarget() + { + return piTarget; + } + + public String getPrefix() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String prefix = (ci == -1) ? + (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) : + qName.substring(0, ci); + if (stringInterning && prefix != null) + prefix = prefix.intern(); + return prefix; + default: + return null; + } + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (name == null) + throw new IllegalArgumentException("name is null"); + if (XMLInputFactory.ALLOCATOR.equals(name)) + return null; + if (XMLInputFactory.IS_COALESCING.equals(name)) + return coalescing ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_NAMESPACE_AWARE.equals(name)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES.equals(name)) + return replaceERefs ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES.equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_VALIDATING.equals(name)) + return Boolean.FALSE; + if (XMLInputFactory.REPORTER.equals(name)) + return reporter; + if (XMLInputFactory.RESOLVER.equals(name)) + return resolver; + if (XMLInputFactory.SUPPORT_DTD.equals(name)) + return supportDTD ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.stringInterning".equals(name)) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.xmlBase".equals(name)) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.baseURI".equals(name)) + return getXMLBase(); + return null; + } + + public String getText() + { + return buf.toString(); + } + + public char[] getTextCharacters() + { + return buf.toString().toCharArray(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) + throws XMLStreamException + { + length = Math.min(sourceStart + buf.length(), length); + int sourceEnd = sourceStart + length; + buf.getChars(sourceStart, sourceEnd, target, targetStart); + return length; + } + + public int getTextLength() + { + return buf.length(); + } + + public int getTextStart() + { + return 0; + } + + public String getVersion() + { + return (xmlVersion == null) ? "1.0" : xmlVersion; + } + + public boolean hasName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + return true; + default: + return false; + } + } + + public boolean hasText() + { + switch (event) + { + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + return true; + default: + return false; + } + } + + public boolean isAttributeSpecified(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.specified; + } + + public boolean isCharacters() + { + return (event == XMLStreamConstants.CHARACTERS); + } + + public boolean isEndElement() + { + return (event == XMLStreamConstants.END_ELEMENT); + } + + public boolean isStandalone() + { + return Boolean.TRUE.equals(xmlStandalone); + } + + public boolean isStartElement() + { + return (event == XMLStreamConstants.START_ELEMENT); + } + + public boolean isWhiteSpace() + { + return (event == XMLStreamConstants.SPACE); + } + + public int nextTag() + throws XMLStreamException + { + do + { + switch (next()) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + case XMLStreamConstants.COMMENT: + case XMLStreamConstants.PROCESSING_INSTRUCTION: + break; + default: + throw new XMLStreamException("Unexpected event type: " + event); + } + } + while (event != XMLStreamConstants.START_ELEMENT && + event != XMLStreamConstants.END_ELEMENT); + return event; + } + + public void require(int type, String namespaceURI, String localName) + throws XMLStreamException + { + if (event != type) + throw new XMLStreamException("Current event type is " + event); + if (event == XMLStreamConstants.START_ELEMENT || + event == XMLStreamConstants.END_ELEMENT) + { + String ln = getLocalName(); + if (!ln.equals(localName)) + throw new XMLStreamException("Current local-name is " + ln); + String uri = getNamespaceURI(); + if ((uri == null && namespaceURI != null) || + (uri != null && !uri.equals(namespaceURI))) + throw new XMLStreamException("Current namespace URI is " + uri); + } + } + + public boolean standaloneSet() + { + return (xmlStandalone != null); + } + + public boolean hasNext() + throws XMLStreamException + { + return (event != XMLStreamConstants.END_DOCUMENT && event != -1); + } + + public int next() + throws XMLStreamException + { + if (event == XMLStreamConstants.END_ELEMENT) + { + // Pop namespace context + if (namespaceAware && !namespaces.isEmpty()) + namespaces.removeFirst(); + // Pop base context + if (baseAware && !bases.isEmpty()) + bases.removeFirst(); + } + if (!startEntityStack.isEmpty()) + { + String entityName = (String) startEntityStack.removeFirst(); + buf.setLength(0); + buf.append(entityName); + event = START_ENTITY; + return extendedEventTypes ? event : next(); + } + else if (!endEntityStack.isEmpty()) + { + String entityName = (String) endEntityStack.removeFirst(); + buf.setLength(0); + buf.append(entityName); + event = END_ENTITY; + return extendedEventTypes ? event : next(); + } + try + { + if (!input.initialized) + input.init(); + switch (state) + { + case CONTENT: + if (tryRead(TEST_END_ELEMENT)) + { + readEndElement(); + if (stack.isEmpty()) + state = MISC; + event = XMLStreamConstants.END_ELEMENT; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else if (tryRead(TEST_CDATA)) + { + readCDSect(); + event = XMLStreamConstants.CDATA; + } + else if (tryRead(TEST_START_ELEMENT)) + { + state = readStartElement(); + event = XMLStreamConstants.START_ELEMENT; + } + else + { + // Check for character reference or predefined entity + mark(8); + int c = readCh(); + if (c == 0x26) // '&' + { + c = readCh(); + if (c == 0x23) // '#' + { + reset(); + event = readCharData(null); + } + else + { + // entity reference + reset(); + readCh(); // & + readReference(); + String ref = buf.toString(); + String text = (String) PREDEFINED_ENTITIES.get(ref); + if (text != null) + { + event = readCharData(text); + } + else if (replaceERefs && !isUnparsedEntity(ref)) + { + // this will report a start-entity event + boolean external = false; + if (doctype != null) + { + Object entity = doctype.getEntity(ref); + if (entity instanceof ExternalIds) + external = true; + } + expandEntity(ref, false, external); + event = next(); + } + else + { + event = XMLStreamConstants.ENTITY_REFERENCE; + } + } + } + else + { + reset(); + event = readCharData(null); + if (validating && doctype != null) + validatePCData(buf.toString()); + } + } + break; + case EMPTY_ELEMENT: + String elementName = (String) stack.removeLast(); + buf.setLength(0); + buf.append(elementName); + state = stack.isEmpty() ? MISC : CONTENT; + event = XMLStreamConstants.END_ELEMENT; + if (validating && doctype != null) + endElementValidationHook(); + break; + case INIT: // XMLDecl? + if (tryRead(TEST_XML_DECL)) + readXMLDecl(); + input.finalizeEncoding(); + event = XMLStreamConstants.START_DOCUMENT; + state = PROLOG; + break; + case PROLOG: // Misc* (doctypedecl Misc*)? + skipWhitespace(); + if (doctype == null && tryRead(TEST_DOCTYPE_DECL)) + { + readDoctypeDecl(); + event = XMLStreamConstants.DTD; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else if (tryRead(TEST_START_ELEMENT)) + { + state = readStartElement(); + event = XMLStreamConstants.START_ELEMENT; + } + else + { + int c = readCh(); + error("no root element: U+" + Integer.toHexString(c)); + } + break; + case MISC: // Comment | PI | S + skipWhitespace(); + if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else + { + if (event == XMLStreamConstants.END_DOCUMENT) + throw new NoSuchElementException(); + int c = readCh(); + if (c != -1) + error("Only comments and PIs may appear after " + + "the root element"); + event = XMLStreamConstants.END_DOCUMENT; + } + break; + default: + event = -1; + } + return event; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(); + e2.initCause(e); + throw e2; + } + } + + // package private + + /** + * Returns the current element name. + */ + String getCurrentElement() + { + return (String) stack.getLast(); + } + + // private + + private void mark(int limit) + throws IOException + { + input.mark(limit); + } + + private void reset() + throws IOException + { + input.reset(); + } + + private int read() + throws IOException + { + return input.read(); + } + + private int read(int[] b, int off, int len) + throws IOException + { + return input.read(b, off, len); + } + + /** + * Parsed character read. + */ + private int readCh() + throws IOException, XMLStreamException + { + int c = read(); + if (expandPE && c == 0x25) // '%' + { + if (peIsError) + error("PE reference within decl in internal subset."); + expandPEReference(); + return readCh(); + } + return c; + } + + /** + * Reads the next character, ensuring it is the character specified. + * @param delim the character to match + * @exception XMLStreamException if the next character is not the + * specified one + */ + private void require(char delim) + throws IOException, XMLStreamException + { + mark(1); + int c = readCh(); + if (delim != c) + { + reset(); + error("required character (got U+" + Integer.toHexString(c) + ")", + new Character(delim)); + } + } + + /** + * Reads the next few characters, ensuring they match the string specified. + * @param delim the string to match + * @exception XMLStreamException if the next characters do not match the + * specified string + */ + private void require(String delim) + throws IOException, XMLStreamException + { + char[] chars = delim.toCharArray(); + int len = chars.length; + mark(len); + int off = 0; + do + { + int l2 = read(tmpBuf, off, len - off); + if (l2 == -1) + { + reset(); + error("EOF before required string", delim); + } + off += l2; + } + while (off < len); + for (int i = 0; i < chars.length; i++) + { + if (chars[i] != tmpBuf[i]) + { + reset(); + error("required string", delim); + } + } + } + + /** + * Try to read a single character. On failure, reset the stream. + * @param delim the character to test + * @return true if the character matched delim, false otherwise. + */ + private boolean tryRead(char delim) + throws IOException, XMLStreamException + { + mark(1); + int c = readCh(); + if (delim != c) + { + reset(); + return false; + } + return true; + } + + /** + * Tries to read the specified characters. + * If successful, the stream is positioned after the last character, + * otherwise it is reset. + * @param test the string to test + * @return true if the characters matched the test string, false otherwise. + */ + private boolean tryRead(String test) + throws IOException + { + char[] chars = test.toCharArray(); + int len = chars.length; + mark(len); + int count = 0; + int l2 = read(tmpBuf, 0, len); + if (l2 == -1) + { + reset(); + return false; + } + count += l2; + // check the characters we received first before doing additional reads + for (int i = 0; i < count; i++) + { + if (chars[i] != tmpBuf[i]) + { + reset(); + return false; + } + } + while (count < len) + { + // force read + int c = read(); + if (c == -1) + { + reset(); + return false; + } + tmpBuf[count] = (char) c; + // check each character as it is read + if (chars[count] != tmpBuf[count]) + { + reset(); + return false; + } + count++; + } + return true; + } + + /** + * Reads characters until the specified test string is encountered. + * @param delim the string delimiting the end of the characters + */ + private void readUntil(String delim) + throws IOException, XMLStreamException + { + int startLine = input.line; + try + { + while (!tryRead(delim)) + { + int c = readCh(); + if (c == -1) + throw new EOFException(); + else if (input.xml11) + { + if (!isXML11Char(c) || isXML11RestrictedChar(c)) + error("illegal XML 1.1 character", + "U+" + Integer.toHexString(c)); + } + else if (!isChar(c)) + error("illegal XML character", + "U+" + Integer.toHexString(c)); + buf.append(Character.toChars(c)); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter "+ + "(started on line " + startLine + ')', delim); + } + } + + /** + * Reads any whitespace characters. + * @return true if whitespace characters were read, false otherwise + */ + private boolean tryWhitespace() + throws IOException, XMLStreamException + { + boolean white; + boolean ret = false; + do + { + mark(1); + int c = readCh(); + while (c == -1 && inputStack.size() > 1) + { + popInput(); + c = readCh(); + } + white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d); + if (white) + ret = true; + } + while (white); + reset(); + return ret; + } + + /** + * Skip over any whitespace characters. + */ + private void skipWhitespace() + throws IOException, XMLStreamException + { + boolean white; + do + { + mark(1); + int c = readCh(); + while (c == -1 && inputStack.size() > 1) + { + popInput(); + c = readCh(); + } + white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d); + } + while (white); + reset(); + } + + /** + * Try to read as many whitespace characters as are available. + * @exception XMLStreamException if no whitespace characters were seen + */ + private void requireWhitespace() + throws IOException, XMLStreamException + { + if (!tryWhitespace()) + error("whitespace required"); + } + + /** + * Returns the current base URI for resolving external entities. + */ + String getXMLBase() + { + if (baseAware) + { + for (Iterator i = bases.iterator(); i.hasNext(); ) + { + String base = (String) i.next(); + if (base != null) + return base; + } + } + return input.systemId; + } + + /** + * Push the specified text input source. + */ + private void pushInput(String name, String text, boolean report, + boolean normalize) + throws IOException, XMLStreamException + { + // Check for recursion + if (name != null && !"".equals(name)) + { + for (Iterator i = inputStack.iterator(); i.hasNext(); ) + { + Input ctx = (Input) i.next(); + if (name.equals(ctx.name)) + error("entities may not be self-recursive", name); + } + } + else + report = false; + pushInput(new Input(null, new StringReader(text), input.publicId, + input.systemId, name, input.inputEncoding, report, + normalize)); + } + + /** + * Push the specified external input source. + */ + private void pushInput(String name, ExternalIds ids, boolean report, + boolean normalize) + throws IOException, XMLStreamException + { + if (!externalEntities) + return; + String url = canonicalize(absolutize(input.systemId, ids.systemId)); + // Check for recursion + for (Iterator i = inputStack.iterator(); i.hasNext(); ) + { + Input ctx = (Input) i.next(); + if (url.equals(ctx.systemId)) + error("entities may not be self-recursive", url); + if (name != null && !"".equals(name) && name.equals(ctx.name)) + error("entities may not be self-recursive", name); + } + if (name == null || "".equals(name)) + report = false; + InputStream in = null; + if (resolver != null) + { + Object obj = resolver.resolveEntity(ids.publicId, url, getXMLBase(), + null); + if (obj instanceof InputStream) + in = (InputStream) obj; + } + if (in == null) + in = resolve(url); + if (in == null) + error("unable to resolve external entity", + (ids.systemId != null) ? ids.systemId : ids.publicId); + pushInput(new Input(in, null, ids.publicId, url, name, null, report, + normalize)); + input.init(); + if (tryRead(TEST_XML_DECL)) + readTextDecl(); + input.finalizeEncoding(); + } + + /** + * Push the specified input source (general entity) onto the input stack. + */ + private void pushInput(Input input) + { + if (input.report) + startEntityStack.addFirst(input.name); + inputStack.addLast(input); + if (this.input != null) + input.xml11 = this.input.xml11; + this.input = input; + } + + /** + * Returns a canonicalized version of the specified URL. + * This is largely to work around a problem with the specification of + * file URLs. + */ + static String canonicalize(String url) + { + if (url == null) + return null; + if (url.startsWith("file:") && !url.startsWith("file://")) + url = "file://" + url.substring(5); + return url; + } + + /** + * "Absolutize" a URL. This resolves a relative URL into an absolute one. + * @param base the current base URL + * @param href the (absolute or relative) URL to resolve + */ + public static String absolutize(String base, String href) + { + if (href == null) + return null; + int ci = href.indexOf(':'); + if (ci > 1 && isURLScheme(href.substring(0, ci))) + { + // href is absolute already + return href; + } + if (base == null) + base = ""; + else + { + int i = base.lastIndexOf('/'); + if (i != -1) + base = base.substring(0, i + 1); + else + base = ""; + } + if ("".equals(base)) + { + // assume file URL relative to current directory + base = System.getProperty("user.dir"); + if (base.charAt(0) == '/') + base = base.substring(1); + base = "file:///" + base.replace(File.separatorChar, '/'); + if (!base.endsWith("/")) + base += "/"; + } + // We can't use java.net.URL here to do the parsing, as it searches for + // a protocol handler. A protocol handler may not be registered for the + // URL scheme here. Do it manually. + // + // Set aside scheme and host portion of base URL + String basePrefix = null; + ci = base.indexOf(':'); + if (ci > 1 && isURLScheme(base.substring(0, ci))) + { + if (base.length() > (ci + 3) && + base.charAt(ci + 1) == '/' && + base.charAt(ci + 2) == '/') + { + int si = base.indexOf('/', ci + 3); + if (si == -1) + base = null; + else + { + basePrefix = base.substring(0, si); + base = base.substring(si); + } + } + else + base = null; + } + if (base == null) // unknown or malformed base URL, use href + return href; + if (href.startsWith("/")) // absolute href pathname + return (basePrefix == null) ? href : basePrefix + href; + // relative href pathname + if (!base.endsWith("/")) + { + int lsi = base.lastIndexOf('/'); + if (lsi == -1) + base = "/"; + else + base = base.substring(0, lsi + 1); + } + while (href.startsWith("../") || href.startsWith("./")) + { + if (href.startsWith("../")) + { + // strip last path component from base + int lsi = base.lastIndexOf('/', base.length() - 2); + if (lsi > -1) + base = base.substring(0, lsi + 1); + href = href.substring(3); // strip ../ prefix + } + else + { + href = href.substring(2); // strip ./ prefix + } + } + return (basePrefix == null) ? base + href : basePrefix + base + href; + } + + /** + * Indicates whether the specified characters match the scheme portion of + * a URL. + * @see RFC 1738 section 2.1 + */ + private static boolean isURLScheme(String text) + { + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '+' || c == '.' || c == '-') + continue; + if (c < 65 || (c > 90 && c < 97) || c > 122) + return false; + } + return true; + } + + /** + * Returns an input stream for the given URL. + */ + static InputStream resolve(String url) + throws IOException + { + try + { + return new URL(url).openStream(); + } + catch (MalformedURLException e) + { + return null; + } + catch (IOException e) + { + IOException e2 = new IOException("error resolving " + url); + e2.initCause(e); + throw e2; + } + } + + /** + * Pops the current input source (general entity) off the stack. + */ + private void popInput() + { + Input old = (Input) inputStack.removeLast(); + if (old.report) + endEntityStack.addFirst(old.name); + input = (Input) inputStack.getLast(); + } + + /** + * Parse an entity text declaration. + */ + private void readTextDecl() + throws IOException, XMLStreamException + { + final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + requireWhitespace(); + if (tryRead("version")) + { + readEq(); + String v = readLiteral(flags, false); + if ("1.0".equals(v)) + input.xml11 = false; + else if ("1.1".equals(v)) + { + Input i1 = (Input) inputStack.getFirst(); + if (!i1.xml11) + error("external entity specifies later version number"); + input.xml11 = true; + } + else + throw new XMLStreamException("illegal XML version: " + v); + requireWhitespace(); + } + require("encoding"); + readEq(); + String enc = readLiteral(flags, false); + skipWhitespace(); + require("?>"); + input.setInputEncoding(enc); + } + + /** + * Parse the XML declaration. + */ + private void readXMLDecl() + throws IOException, XMLStreamException + { + final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + requireWhitespace(); + require("version"); + readEq(); + xmlVersion = readLiteral(flags, false); + if ("1.0".equals(xmlVersion)) + input.xml11 = false; + else if ("1.1".equals(xmlVersion)) + input.xml11 = true; + else + throw new XMLStreamException("illegal XML version: " + xmlVersion); + + boolean white = tryWhitespace(); + + if (tryRead("encoding")) + { + if (!white) + error("whitespace required before 'encoding='"); + readEq(); + xmlEncoding = readLiteral(flags, false); + white = tryWhitespace(); + } + + if (tryRead("standalone")) + { + if (!white) + error("whitespace required before 'standalone='"); + readEq(); + String standalone = readLiteral(flags, false); + if ("yes".equals(standalone)) + xmlStandalone = Boolean.TRUE; + else if ("no".equals(standalone)) + xmlStandalone = Boolean.FALSE; + else + error("standalone flag must be 'yes' or 'no'", standalone); + } + + skipWhitespace(); + require("?>"); + if (xmlEncoding != null) + input.setInputEncoding(xmlEncoding); + } + + /** + * Parse the DOCTYPE declaration. + */ + private void readDoctypeDecl() + throws IOException, XMLStreamException + { + if (!supportDTD) + error("parser was configured not to support DTDs"); + requireWhitespace(); + String rootName = readNmtoken(true); + skipWhitespace(); + ExternalIds ids = readExternalIds(false, true); + doctype = + this.new Doctype(rootName, ids.publicId, ids.systemId); + + // Parse internal subset first + skipWhitespace(); + if (tryRead('[')) + { + while (true) + { + expandPE = true; + skipWhitespace(); + expandPE = false; + if (tryRead(']')) + break; + else + readMarkupdecl(false); + } + } + skipWhitespace(); + require('>'); + + // Parse external subset + if (ids.systemId != null && externalEntities) + { + pushInput("", ">", false, false); + pushInput("[dtd]", ids, true, true); + // loop until we get back to ">" + while (true) + { + expandPE = true; + skipWhitespace(); + expandPE = false; + mark(1); + int c = readCh(); + if (c == 0x3e) // '>' + break; + else if (c == -1) + popInput(); + else + { + reset(); + expandPE = true; + readMarkupdecl(true); + expandPE = true; + } + } + if (inputStack.size() != 2) + error("external subset has unmatched '>'"); + popInput(); + } + checkDoctype(); + if (validating) + validateDoctype(); + + // Make rootName available for reading + buf.setLength(0); + buf.append(rootName); + } + + /** + * Checks the well-formedness of the DTD. + */ + private void checkDoctype() + throws XMLStreamException + { + // TODO check entity recursion + } + + /** + * Parse the markupdecl production. + */ + private void readMarkupdecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + mark(1); + require('<'); + reset(); + expandPE = false; + if (tryRead(TEST_ELEMENT_DECL)) + { + expandPE = saved; + readElementDecl(); + } + else if (tryRead(TEST_ATTLIST_DECL)) + { + expandPE = saved; + readAttlistDecl(); + } + else if (tryRead(TEST_ENTITY_DECL)) + { + expandPE = saved; + readEntityDecl(inExternalSubset); + } + else if (tryRead(TEST_NOTATION_DECL)) + { + expandPE = saved; + readNotationDecl(inExternalSubset); + } + else if (tryRead(TEST_PI)) + { + readPI(true); + expandPE = saved; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(true); + expandPE = saved; + } + else if (tryRead("")) + { + readMarkupdecl(inExternalSubset); + skipWhitespace(); + } + } + else if (tryRead("IGNORE")) + { + skipWhitespace(); + require('['); + expandPE = false; + for (int nesting = 1; nesting > 0; ) + { + int c = readCh(); + switch (c) + { + case 0x3c: // '<' + if (tryRead("![")) + nesting++; + break; + case 0x5d: // ']' + if (tryRead("]>")) + nesting--; + break; + case -1: + throw new EOFException(); + } + } + expandPE = saved; + } + else + error("conditional section must begin with INCLUDE or IGNORE"); + } + else + error("expected markup declaration"); + } + + /** + * Parse the elementdecl production. + */ + private void readElementDecl() + throws IOException, XMLStreamException + { + requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); + String name = readNmtoken(true); + expandPE = saved; + requireWhitespace(); + readContentspec(name); + skipWhitespace(); + require('>'); + } + + /** + * Parse the contentspec production. + */ + private void readContentspec(String elementName) + throws IOException, XMLStreamException + { + if (tryRead("EMPTY")) + doctype.addElementDecl(elementName, "EMPTY", new EmptyContentModel()); + else if (tryRead("ANY")) + doctype.addElementDecl(elementName, "ANY", new AnyContentModel()); + else + { + ContentModel model; + CPStringBuilder acc = new CPStringBuilder(); + require('('); + acc.append('('); + skipWhitespace(); + if (tryRead("#PCDATA")) + { + // mixed content + acc.append("#PCDATA"); + MixedContentModel mm = new MixedContentModel(); + model = mm; + skipWhitespace(); + if (tryRead(')')) + { + acc.append(")"); + if (tryRead('*')) + { + mm.min = 0; + mm.max = -1; + } + } + else + { + while (!tryRead(")")) + { + require('|'); + acc.append('|'); + skipWhitespace(); + String name = readNmtoken(true); + acc.append(name); + mm.addName(name); + skipWhitespace(); + } + require('*'); + acc.append(")*"); + mm.min = 0; + mm.max = -1; + } + } + else + model = readElements(acc); + doctype.addElementDecl(elementName, acc.toString(), model); + } + } + + /** + * Parses an element content model. + */ + private ElementContentModel readElements(CPStringBuilder acc) + throws IOException, XMLStreamException + { + int separator; + ElementContentModel model = new ElementContentModel(); + + // Parse first content particle + skipWhitespace(); + model.addContentParticle(readContentParticle(acc)); + // End or separator + skipWhitespace(); + int c = readCh(); + switch (c) + { + case 0x29: // ')' + acc.append(')'); + mark(1); + c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + model.min = 0; + model.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + model.min = 0; + model.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + model.min = 1; + model.max = -1; + break; + default: + reset(); + } + return model; // done + case 0x7c: // '|' + model.or = true; + // fall through + case 0x2c: // ',' + separator = c; + acc.append(Character.toChars(c)); + break; + default: + error("bad separator in content model", + "U+" + Integer.toHexString(c)); + return model; + } + // Parse subsequent content particles + while (true) + { + skipWhitespace(); + model.addContentParticle(readContentParticle(acc)); + skipWhitespace(); + c = readCh(); + if (c == 0x29) // ')' + { + acc.append(')'); + break; + } + else if (c != separator) + { + error("bad separator in content model", + "U+" + Integer.toHexString(c)); + return model; + } + else + acc.append(c); + } + // Check for occurrence indicator + mark(1); + c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + model.min = 0; + model.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + model.min = 0; + model.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + model.min = 1; + model.max = -1; + break; + default: + reset(); + } + return model; + } + + /** + * Parse a cp production. + */ + private ContentParticle readContentParticle(CPStringBuilder acc) + throws IOException, XMLStreamException + { + ContentParticle cp = new ContentParticle(); + if (tryRead('(')) + { + acc.append('('); + cp.content = readElements(acc); + } + else + { + String name = readNmtoken(true); + acc.append(name); + cp.content = name; + mark(1); + int c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + cp.min = 0; + cp.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + cp.min = 0; + cp.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + cp.min = 1; + cp.max = -1; + break; + default: + reset(); + } + } + return cp; + } + + /** + * Parse an attribute-list definition. + */ + private void readAttlistDecl() + throws IOException, XMLStreamException + { + requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); + String elementName = readNmtoken(true); + expandPE = saved; + boolean white = tryWhitespace(); + while (!tryRead('>')) + { + if (!white) + error("whitespace required before attribute definition"); + readAttDef(elementName); + white = tryWhitespace(); + } + } + + /** + * Parse a single attribute definition. + */ + private void readAttDef(String elementName) + throws IOException, XMLStreamException + { + String name = readNmtoken(true); + requireWhitespace(); + CPStringBuilder acc = new CPStringBuilder(); + HashSet values = new HashSet(); + String type = readAttType(acc, values); + if (validating) + { + if ("ID".equals(type)) + { + // VC: One ID per Element Type + for (Iterator i = doctype.attlistIterator(elementName); + i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if ("ID".equals(decl.type)) + error("element types must not have more than one ID " + + "attribute"); + } + } + else if ("NOTATION".equals(type)) + { + // VC: One Notation Per Element Type + for (Iterator i = doctype.attlistIterator(elementName); + i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if ("NOTATION".equals(decl.type)) + error("element types must not have more than one NOTATION " + + "attribute"); + } + // VC: No Notation on Empty Element + ContentModel model = doctype.getElementModel(elementName); + if (model != null && model.type == ContentModel.EMPTY) + error("attributes of type NOTATION must not be declared on an " + + "element declared EMPTY"); + } + } + String enumer = null; + if ("ENUMERATION".equals(type) || "NOTATION".equals(type)) + enumer = acc.toString(); + else + values = null; + requireWhitespace(); + readDefault(elementName, name, type, enumer, values); + } + + /** + * Parse an attribute type. + */ + private String readAttType(CPStringBuilder acc, HashSet values) + throws IOException, XMLStreamException + { + if (tryRead('(')) + { + readEnumeration(false, acc, values); + return "ENUMERATION"; + } + else + { + String typeString = readNmtoken(true); + if ("NOTATION".equals(typeString)) + { + readNotationType(acc, values); + return typeString; + } + else if ("CDATA".equals(typeString) || + "ID".equals(typeString) || + "IDREF".equals(typeString) || + "IDREFS".equals(typeString) || + "ENTITY".equals(typeString) || + "ENTITIES".equals(typeString) || + "NMTOKEN".equals(typeString) || + "NMTOKENS".equals(typeString)) + return typeString; + else + { + error("illegal attribute type", typeString); + return null; + } + } + } + + /** + * Parse an enumeration. + */ + private void readEnumeration(boolean isNames, CPStringBuilder acc, + HashSet values) + throws IOException, XMLStreamException + { + acc.append('('); + // first token + skipWhitespace(); + String token = readNmtoken(isNames); + acc.append(token); + values.add(token); + // subsequent tokens + skipWhitespace(); + while (!tryRead(')')) + { + require('|'); + acc.append('|'); + skipWhitespace(); + token = readNmtoken(isNames); + // VC: No Duplicate Tokens + if (validating && values.contains(token)) + error("duplicate token", token); + acc.append(token); + values.add(token); + skipWhitespace(); + } + acc.append(')'); + } + + /** + * Parse a notation type for an attribute. + */ + private void readNotationType(CPStringBuilder acc, HashSet values) + throws IOException, XMLStreamException + { + requireWhitespace(); + require('('); + readEnumeration(true, acc, values); + } + + /** + * Parse the default value for an attribute. + */ + private void readDefault(String elementName, String name, + String type, String enumeration, HashSet values) + throws IOException, XMLStreamException + { + int valueType = ATTRIBUTE_DEFAULT_SPECIFIED; + int flags = LIT_ATTRIBUTE; + String value = null, defaultType = null; + boolean saved = expandPE; + + if (!"CDATA".equals(type)) + flags |= LIT_NORMALIZE; + + expandPE = false; + if (tryRead('#')) + { + if (tryRead("FIXED")) + { + defaultType = "#FIXED"; + valueType = ATTRIBUTE_DEFAULT_FIXED; + requireWhitespace(); + value = readLiteral(flags, false); + } + else if (tryRead("REQUIRED")) + { + defaultType = "#REQUIRED"; + valueType = ATTRIBUTE_DEFAULT_REQUIRED; + } + else if (tryRead("IMPLIED")) + { + defaultType = "#IMPLIED"; + valueType = ATTRIBUTE_DEFAULT_IMPLIED; + } + else + error("illegal keyword for attribute default value"); + } + else + value = readLiteral(flags, false); + expandPE = saved; + if (validating) + { + if ("ID".equals(type)) + { + // VC: Attribute Default Value Syntactically Correct + if (value != null && !isNmtoken(value, true)) + error("default value must match Name production", value); + // VC: ID Attribute Default + if (valueType != ATTRIBUTE_DEFAULT_REQUIRED && + valueType != ATTRIBUTE_DEFAULT_IMPLIED) + error("ID attributes must have a declared default of " + + "#IMPLIED or #REQUIRED"); + } + else if (value != null) + { + // VC: Attribute Default Value Syntactically Correct + if ("IDREF".equals(type) || "ENTITY".equals(type)) + { + if (!isNmtoken(value, true)) + error("default value must match Name production", value); + } + else if ("IDREFS".equals(type) || "ENTITIES".equals(type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (!isNmtoken(token, true)) + error("default value must match Name production", token); + } + } + else if ("NMTOKEN".equals(type) || "ENUMERATION".equals(type)) + { + if (!isNmtoken(value, false)) + error("default value must match Nmtoken production", value); + } + else if ("NMTOKENS".equals(type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (!isNmtoken(token, false)) + error("default value must match Nmtoken production", + token); + } + } + } + } + // Register attribute def + AttributeDecl attribute = + new AttributeDecl(type, value, valueType, enumeration, values, + inputStack.size() != 1); + doctype.addAttributeDecl(elementName, name, attribute); + } + + /** + * Parse the EntityDecl production. + */ + private void readEntityDecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + int flags = 0; + // Check if parameter entity + boolean peFlag = false; + expandPE = false; + requireWhitespace(); + if (tryRead('%')) + { + peFlag = true; + requireWhitespace(); + } + expandPE = true; + // Read entity name + String name = readNmtoken(true); + if (name.indexOf(':') != -1) + error("illegal character ':' in entity name", name); + if (peFlag) + name = "%" + name; + requireWhitespace(); + mark(1); + int c = readCh(); + reset(); + if (c == 0x22 || c == 0x27) // " | ' + { + // Internal entity replacement text + String value = readLiteral(flags | LIT_DISABLE_EREF, true); + int ai = value.indexOf('&'); + while (ai != -1) + { + int sci = value.indexOf(';', ai); + if (sci == -1) + error("malformed reference in entity value", value); + String ref = value.substring(ai + 1, sci); + int[] cp = UnicodeReader.toCodePointArray(ref); + if (cp.length == 0) + error("malformed reference in entity value", value); + if (cp[0] == 0x23) // # + { + if (cp.length == 1) + error("malformed reference in entity value", value); + if (cp[1] == 0x78) // 'x' + { + if (cp.length == 2) + error("malformed reference in entity value", value); + for (int i = 2; i < cp.length; i++) + { + int x = cp[i]; + if (x < 0x30 || + (x > 0x39 && x < 0x41) || + (x > 0x46 && x < 0x61) || + x > 0x66) + error("malformed character reference in entity value", + value); + } + } + else + { + for (int i = 1; i < cp.length; i++) + { + int x = cp[i]; + if (x < 0x30 || x > 0x39) + error("malformed character reference in entity value", + value); + } + } + } + else + { + if (!isNameStartCharacter(cp[0], input.xml11)) + error("malformed reference in entity value", value); + for (int i = 1; i < cp.length; i++) + { + if (!isNameCharacter(cp[i], input.xml11)) + error("malformed reference in entity value", value); + } + } + ai = value.indexOf('&', sci); + } + doctype.addEntityDecl(name, value, inExternalSubset); + } + else + { + ExternalIds ids = readExternalIds(false, false); + // Check for NDATA + boolean white = tryWhitespace(); + if (!peFlag && tryRead("NDATA")) + { + if (!white) + error("whitespace required before NDATA"); + requireWhitespace(); + ids.notationName = readNmtoken(true); + } + doctype.addEntityDecl(name, ids, inExternalSubset); + } + // finish + skipWhitespace(); + require('>'); + } + + /** + * Parse the NotationDecl production. + */ + private void readNotationDecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + requireWhitespace(); + String notationName = readNmtoken(true); + if (notationName.indexOf(':') != -1) + error("illegal character ':' in notation name", notationName); + if (validating) + { + // VC: Unique Notation Name + ExternalIds notation = doctype.getNotation(notationName); + if (notation != null) + error("duplicate notation name", notationName); + } + requireWhitespace(); + ExternalIds ids = readExternalIds(true, false); + ids.notationName = notationName; + doctype.addNotationDecl(notationName, ids, inExternalSubset); + skipWhitespace(); + require('>'); + } + + /** + * Returns a tuple {publicId, systemId}. + */ + private ExternalIds readExternalIds(boolean inNotation, boolean isSubset) + throws IOException, XMLStreamException + { + int c; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + ExternalIds ids = new ExternalIds(); + + if (tryRead("PUBLIC")) + { + requireWhitespace(); + ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags, false); + if (inNotation) + { + skipWhitespace(); + mark(1); + c = readCh(); + reset(); + if (c == 0x22 || c == 0x27) // " | ' + { + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + } + else + { + requireWhitespace(); + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + // Check valid URI characters + for (int i = 0; i < ids.publicId.length(); i++) + { + char d = ids.publicId.charAt(i); + if (d >= 'a' && d <= 'z') + continue; + if (d >= 'A' && d <= 'Z') + continue; + if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(d) != -1) + continue; + error("illegal PUBLIC id character", + "U+" + Integer.toHexString(d)); + } + } + else if (tryRead("SYSTEM")) + { + requireWhitespace(); + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + else if (!isSubset) + { + error("missing SYSTEM or PUBLIC keyword"); + } + if (ids.systemId != null && !inNotation) + { + if (ids.systemId.indexOf('#') != -1) + error("SYSTEM id has a URI fragment", ids.systemId); + } + return ids; + } + + /** + * Parse the start of an element. + * @return the state of the parser afterwards (EMPTY_ELEMENT or CONTENT) + */ + private int readStartElement() + throws IOException, XMLStreamException + { + // Read element name + String elementName = readNmtoken(true); + attrs.clear(); + // Push namespace context + if (namespaceAware) + { + if (elementName.charAt(0) == ':' || + elementName.charAt(elementName.length() - 1) == ':') + error("not a QName", elementName); + namespaces.addFirst(new LinkedHashMap()); + } + // Read element content + boolean white = tryWhitespace(); + mark(1); + int c = readCh(); + while (c != 0x2f && c != 0x3e) // '/' | '>' + { + // Read attribute + reset(); + if (!white) + error("need whitespace between attributes"); + readAttribute(elementName); + white = tryWhitespace(); + mark(1); + c = readCh(); + } + // supply defaulted attributes + if (doctype != null) + { + for (Iterator i = doctype.attlistIterator(elementName); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String attName = (String) entry.getKey(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if (validating) + { + switch (decl.valueType) + { + case ATTRIBUTE_DEFAULT_REQUIRED: + // VC: Required Attribute + if (decl.value == null && !attributeSpecified(attName)) + error("value for " + attName + " attribute is required"); + break; + case ATTRIBUTE_DEFAULT_FIXED: + // VC: Fixed Attribute Default + for (Iterator j = attrs.iterator(); j.hasNext(); ) + { + Attribute a = (Attribute) j.next(); + if (attName.equals(a.name) && + !decl.value.equals(a.value)) + error("value for " + attName + " attribute must be " + + decl.value); + } + break; + } + } + if (namespaceAware && attName.equals("xmlns")) + { + LinkedHashMap ctx = + (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX)) + continue; // namespace was specified + } + else if (namespaceAware && attName.startsWith("xmlns:")) + { + LinkedHashMap ctx = + (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(attName.substring(6))) + continue; // namespace was specified + } + else if (attributeSpecified(attName)) + continue; + if (decl.value == null) + continue; + // VC: Standalone Document Declaration + if (validating && decl.external && xmlStandalone == Boolean.TRUE) + error("standalone must be 'no' if attributes inherit values " + + "from externally declared markup declarations"); + Attribute attr = + new Attribute(attName, decl.type, false, decl.value); + if (namespaceAware) + { + if (!addNamespace(attr)) + attrs.add(attr); + } + else + attrs.add(attr); + } + } + if (baseAware) + { + String uri = getAttributeValue(XMLConstants.XML_NS_URI, "base"); + String base = getXMLBase(); + bases.addFirst(absolutize(base, uri)); + } + if (namespaceAware) + { + // check prefix bindings + int ci = elementName.indexOf(':'); + if (ci != -1) + { + String prefix = elementName.substring(0, ci); + String uri = getNamespaceURI(prefix); + if (uri == null) + error("unbound element prefix", prefix); + else if (input.xml11 && "".equals(uri)) + error("XML 1.1 unbound element prefix", prefix); + } + for (Iterator i = attrs.iterator(); i.hasNext(); ) + { + Attribute attr = (Attribute) i.next(); + if (attr.prefix != null && + !XMLConstants.XMLNS_ATTRIBUTE.equals(attr.prefix)) + { + String uri = getNamespaceURI(attr.prefix); + if (uri == null) + error("unbound attribute prefix", attr.prefix); + else if (input.xml11 && "".equals(uri)) + error("XML 1.1 unbound attribute prefix", attr.prefix); + } + } + } + if (validating && doctype != null) + { + validateStartElement(elementName); + currentContentModel = doctype.getElementModel(elementName); + if (currentContentModel == null) + error("no element declaration", elementName); + validationStack.add(new LinkedList()); + } + // make element name available for read + buf.setLength(0); + buf.append(elementName); + // push element onto stack + stack.addLast(elementName); + switch (c) + { + case 0x3e: // '>' + return CONTENT; + case 0x2f: // '/' + require('>'); + return EMPTY_ELEMENT; + } + return -1; // to satisfy compiler + } + + /** + * Indicates whether the specified attribute name was specified for the + * current element. + */ + private boolean attributeSpecified(String attName) + { + for (Iterator j = attrs.iterator(); j.hasNext(); ) + { + Attribute a = (Attribute) j.next(); + if (attName.equals(a.name)) + return true; + } + return false; + } + + /** + * Parse an attribute. + */ + private void readAttribute(String elementName) + throws IOException, XMLStreamException + { + // Read attribute name + String attributeName = readNmtoken(true); + String type = getAttributeType(elementName, attributeName); + readEq(); + // Read literal + final int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF; + String value = (type == null || "CDATA".equals(type)) ? + readLiteral(flags, false) : readLiteral(flags | LIT_NORMALIZE, false); + // add attribute event + Attribute attr = this.new Attribute(attributeName, type, true, value); + if (namespaceAware) + { + if (attributeName.charAt(0) == ':' || + attributeName.charAt(attributeName.length() - 1) == ':') + error("not a QName", attributeName); + else if (attributeName.equals("xmlns")) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX)) + error("duplicate default namespace"); + } + else if (attributeName.startsWith("xmlns:")) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(attributeName.substring(6))) + error("duplicate namespace", attributeName.substring(6)); + } + else if (attrs.contains(attr)) + error("duplicate attribute", attributeName); + } + else if (attrs.contains(attr)) + error("duplicate attribute", attributeName); + if (validating && doctype != null) + { + // VC: Attribute Value Type + AttributeDecl decl = + doctype.getAttributeDecl(elementName, attributeName); + if (decl == null) + error("attribute must be declared", attributeName); + if ("ENUMERATION".equals(decl.type)) + { + // VC: Enumeration + if (!decl.values.contains(value)) + error("value does not match enumeration " + decl.enumeration, + value); + } + else if ("ID".equals(decl.type)) + { + // VC: ID + if (!isNmtoken(value, true)) + error("ID values must match the Name production"); + if (ids.contains(value)) + error("Duplicate ID", value); + ids.add(value); + } + else if ("IDREF".equals(decl.type) || "IDREFS".equals(decl.type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + // VC: IDREF + if (!isNmtoken(token, true)) + error("IDREF values must match the Name production"); + idrefs.add(token); + } + } + else if ("NMTOKEN".equals(decl.type) || "NMTOKENS".equals(decl.type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + // VC: Name Token + if (!isNmtoken(token, false)) + error("NMTOKEN values must match the Nmtoken production"); + } + } + else if ("ENTITY".equals(decl.type)) + { + // VC: Entity Name + if (!isNmtoken(value, true)) + error("ENTITY values must match the Name production"); + Object entity = doctype.getEntity(value); + if (entity == null || !(entity instanceof ExternalIds) || + ((ExternalIds) entity).notationName == null) + error("ENTITY values must match the name of an unparsed " + + "entity declared in the DTD"); + } + else if ("NOTATION".equals(decl.type)) + { + if (!decl.values.contains(value)) + error("NOTATION values must match a declared notation name", + value); + // VC: Notation Attributes + ExternalIds notation = doctype.getNotation(value); + if (notation == null) + error("NOTATION values must match the name of a notation " + + "declared in the DTD", value); + } + } + if (namespaceAware) + { + if (!addNamespace(attr)) + attrs.add(attr); + } + else + attrs.add(attr); + } + + /** + * Determines whether the specified attribute is a namespace declaration, + * and adds it to the current namespace context if so. Returns false if + * the attribute is an ordinary attribute. + */ + private boolean addNamespace(Attribute attr) + throws XMLStreamException + { + if ("xmlns".equals(attr.name)) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.get(XMLConstants.DEFAULT_NS_PREFIX) != null) + error("Duplicate default namespace declaration"); + if (XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't bind XML namespace"); + ctx.put(XMLConstants.DEFAULT_NS_PREFIX, attr.value); + return true; + } + else if ("xmlns".equals(attr.prefix)) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.get(attr.localName) != null) + error("Duplicate namespace declaration for prefix", + attr.localName); + if (XMLConstants.XML_NS_PREFIX.equals(attr.localName)) + { + if (!XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't redeclare xml prefix"); + else + return false; // treat as attribute + } + if (XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't bind non-xml prefix to XML namespace"); + if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.localName)) + error("can't redeclare xmlns prefix"); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.value)) + error("can't bind non-xmlns prefix to XML Namespace namespace"); + if ("".equals(attr.value) && !input.xml11) + error("illegal use of 1.1-style prefix unbinding in 1.0 document"); + ctx.put(attr.localName, attr.value); + return true; + } + return false; + } + + /** + * Parse a closing tag. + */ + private void readEndElement() + throws IOException, XMLStreamException + { + // pop element off stack + String expected = (String) stack.removeLast(); + require(expected); + skipWhitespace(); + require('>'); + // Make element name available + buf.setLength(0); + buf.append(expected); + if (validating && doctype != null) + endElementValidationHook(); + } + + /** + * Validate the end of an element. + * Called on an end-element or empty element if validating. + */ + private void endElementValidationHook() + throws XMLStreamException + { + validateEndElement(); + validationStack.removeLast(); + if (stack.isEmpty()) + currentContentModel = null; + else + { + String parent = (String) stack.getLast(); + currentContentModel = doctype.getElementModel(parent); + } + } + + /** + * Parse a comment. + */ + private void readComment(boolean inDTD) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + expandPE = false; + buf.setLength(0); + readUntil(TEST_END_COMMENT); + require('>'); + expandPE = saved; + if (inDTD) + doctype.addComment(buf.toString()); + } + + /** + * Parse a processing instruction. + */ + private void readPI(boolean inDTD) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + expandPE = false; + piTarget = readNmtoken(true); + if (piTarget.indexOf(':') != -1) + error("illegal character in PI target", new Character(':')); + if ("xml".equalsIgnoreCase(piTarget)) + error("illegal PI target", piTarget); + if (tryRead(TEST_END_PI)) + piData = null; + else + { + if (!tryWhitespace()) + error("whitespace required between PI target and data"); + buf.setLength(0); + readUntil(TEST_END_PI); + piData = buf.toString(); + } + expandPE = saved; + if (inDTD) + doctype.addPI(piTarget, piData); + } + + /** + * Parse an entity reference. + */ + private void readReference() + throws IOException, XMLStreamException + { + buf.setLength(0); + String entityName = readNmtoken(true); + require(';'); + buf.setLength(0); + buf.append(entityName); + } + + /** + * Read an CDATA section. + */ + private void readCDSect() + throws IOException, XMLStreamException + { + buf.setLength(0); + readUntil(TEST_END_CDATA); + } + + /** + * Read character data. + * @return the type of text read (CHARACTERS or SPACE) + */ + private int readCharData(String prefix) + throws IOException, XMLStreamException + { + boolean white = true; + buf.setLength(0); + if (prefix != null) + buf.append(prefix); + boolean done = false; + boolean entities = false; + while (!done) + { + // Block read + mark(tmpBuf.length); + int len = read(tmpBuf, 0, tmpBuf.length); + if (len == -1) + { + if (inputStack.size() > 1) + { + popInput(); + // report end-entity + done = true; + } + else + throw new EOFException(); + } + for (int i = 0; i < len && !done; i++) + { + int c = tmpBuf[i]; + switch (c) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + buf.append(Character.toChars(c)); + break; // whitespace + case 0x26: // '&' + reset(); + read(tmpBuf, 0, i); + // character reference? + mark(3); + c = readCh(); // & + c = readCh(); + if (c == 0x23) // '#' + { + mark(1); + c = readCh(); + boolean hex = (c == 0x78); // 'x' + if (!hex) + reset(); + char[] ch = readCharacterRef(hex ? 16 : 10); + buf.append(ch, 0, ch.length); + for (int j = 0; j < ch.length; j++) + { + switch (ch[j]) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + break; // whitespace + default: + white = false; + } + } + } + else + { + // entity reference + reset(); + c = readCh(); // & + String entityName = readNmtoken(true); + require(';'); + String text = + (String) PREDEFINED_ENTITIES.get(entityName); + if (text != null) + buf.append(text); + else + { + pushInput("", "&" + entityName + ";", false, false); + done = true; + break; + } + } + // continue processing + i = -1; + mark(tmpBuf.length); + len = read(tmpBuf, 0, tmpBuf.length); + if (len == -1) + { + if (inputStack.size() > 1) + { + popInput(); + done = true; + } + else + throw new EOFException(); + } + entities = true; + break; // end of text sequence + case 0x3e: // '>' + int l = buf.length(); + if (l > 1 && + buf.charAt(l - 1) == ']' && + buf.charAt(l - 2) == ']') + error("Character data may not contain unescaped ']]>'"); + buf.append(Character.toChars(c)); + break; + case 0x3c: // '<' + reset(); + // read i characters + int count = 0, remaining = i; + do + { + int r = read(tmpBuf, 0, remaining); + count += r; + remaining -= r; + } + while (count < i); + i = len; + if (coalescing && tryRead(TEST_CDATA)) + readUntil(TEST_END_CDATA); // read CDATA section into buf + else + done = true; // end of text sequence + break; + default: + if (input.xml11) + { + if (!isXML11Char(c) || isXML11RestrictedChar(c)) + error("illegal XML 1.1 character", + "U+" + Integer.toHexString(c)); + } + else if (!isChar(c)) + error("illegal XML character", + "U+" + Integer.toHexString(c)); + white = false; + buf.append(Character.toChars(c)); + } + } + // if text buffer >= 2MB, return it as a chunk + // to avoid excessive memory use + if (buf.length() >= 2097152) + done = true; + } + if (entities) + normalizeCRLF(buf); + return white ? XMLStreamConstants.SPACE : XMLStreamConstants.CHARACTERS; + } + + /** + * Expands the specified entity. + */ + private void expandEntity(String name, boolean inAttr, boolean normalize) + throws IOException, XMLStreamException + { + if (doctype != null) + { + Object value = doctype.getEntity(name); + if (value != null) + { + if (xmlStandalone == Boolean.TRUE) + { + // VC: Standalone Document Declaration + if (doctype.isEntityExternal(name)) + error("reference to external entity in standalone document"); + else if (value instanceof ExternalIds) + { + ExternalIds ids = (ExternalIds) value; + if (ids.notationName != null && + doctype.isNotationExternal(ids.notationName)) + error("reference to external notation in " + + "standalone document"); + } + } + if (value instanceof String) + { + String text = (String) value; + if (inAttr && text.indexOf('<') != -1) + error("< in attribute value"); + pushInput(name, text, !inAttr, normalize); + } + else if (inAttr) + error("reference to external entity in attribute value", name); + else + pushInput(name, (ExternalIds) value, !inAttr, normalize); + return; + } + } + error("reference to undeclared entity", name); + } + + /** + * Indicates whether the specified entity is unparsed. + */ + private boolean isUnparsedEntity(String name) + { + if (doctype != null) + { + Object value = doctype.getEntity(name); + if (value != null && value instanceof ExternalIds) + return ((ExternalIds) value).notationName != null; + } + return false; + } + + /** + * Read an equals sign. + */ + private void readEq() + throws IOException, XMLStreamException + { + skipWhitespace(); + require('='); + skipWhitespace(); + } + + /** + * Character read for reading literals. + * @param recognizePEs whether to recognize parameter-entity references + */ + private int literalReadCh(boolean recognizePEs) + throws IOException, XMLStreamException + { + int c = recognizePEs ? readCh() : read(); + while (c == -1) + { + if (inputStack.size() > 1) + { + inputStack.removeLast(); + input = (Input) inputStack.getLast(); + // Don't issue end-entity + c = recognizePEs ? readCh() : read(); + } + else + throw new EOFException(); + } + return c; + } + + /** + * Read a string literal. + */ + private String readLiteral(int flags, boolean recognizePEs) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + int delim = readCh(); + if (delim != 0x27 && delim != 0x22) + error("expected '\"' or \"'\"", "U+" + Integer.toHexString(delim)); + literalBuf.setLength(0); + if ((flags & LIT_DISABLE_PE) != 0) + expandPE = false; + boolean entities = false; + int inputStackSize = inputStack.size(); + do + { + int c = literalReadCh(recognizePEs); + if (c == delim && inputStackSize == inputStack.size()) + break; + switch (c) + { + case 0x0a: + case 0x0d: + if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0) + c = 0x20; // normalize to space + break; + case 0x09: + if ((flags & LIT_ATTRIBUTE) != 0) + c = 0x20; // normalize to space + break; + case 0x26: // '&' + mark(2); + c = readCh(); + if (c == 0x23) // '#' + { + if ((flags & LIT_DISABLE_CREF) != 0) + { + reset(); + c = 0x26; // '&' + } + else + { + mark(1); + c = readCh(); + boolean hex = (c == 0x78); // 'x' + if (!hex) + reset(); + char[] ref = readCharacterRef(hex ? 16 : 10); + for (int i = 0; i < ref.length; i++) + literalBuf.append(ref[i]); + entities = true; + continue; + } + } + else + { + if ((flags & LIT_DISABLE_EREF) != 0) + { + reset(); + c = 0x26; // '&' + } + else + { + reset(); + String entityName = readNmtoken(true); + require(';'); + String text = + (String) PREDEFINED_ENTITIES.get(entityName); + if (text != null) + literalBuf.append(text); + else + expandEntity(entityName, + (flags & LIT_ATTRIBUTE) != 0, + true); + entities = true; + continue; + } + } + break; + case 0x3c: // '<' + if ((flags & LIT_ATTRIBUTE) != 0) + error("attribute values may not contain '<'"); + break; + case -1: + if (inputStack.size() > 1) + { + popInput(); + continue; + } + throw new EOFException(); + default: + if ((c < 0x0020 || c > 0xfffd) || + (c >= 0xd800 && c < 0xdc00) || + (input.xml11 && (c >= 0x007f) && + (c <= 0x009f) && (c != 0x0085))) + error("illegal character", "U+" + Integer.toHexString(c)); + } + literalBuf.append(Character.toChars(c)); + } + while (true); + expandPE = saved; + if (entities) + normalizeCRLF(literalBuf); + if ((flags & LIT_NORMALIZE) > 0) + literalBuf = normalize(literalBuf); + return literalBuf.toString(); + } + + /** + * Performs attribute-value normalization of the text buffer. + * This discards leading and trailing whitespace, and replaces sequences + * of whitespace with a single space. + */ + private StringBuffer normalize(StringBuffer buf) + { + StringBuffer acc = new StringBuffer(); + int len = buf.length(); + int avState = 0; + for (int i = 0; i < len; i++) + { + char c = buf.charAt(i); + if (c == ' ') + avState = (avState == 0) ? 0 : 1; + else + { + if (avState == 1) + acc.append(' '); + acc.append(c); + avState = 2; + } + } + return acc; + } + + /** + * Replace any CR/LF pairs in the buffer with LF. + * This may be necessary if combinations of CR or LF were declared as + * (character) entity references in the input. + */ + private void normalizeCRLF(StringBuffer buf) + { + int len = buf.length() - 1; + for (int i = 0; i < len; i++) + { + char c = buf.charAt(i); + if (c == '\r' && buf.charAt(i + 1) == '\n') + { + buf.deleteCharAt(i--); + len--; + } + } + } + + /** + * Parse and expand a parameter entity reference. + */ + private void expandPEReference() + throws IOException, XMLStreamException + { + String name = readNmtoken(true, new StringBuffer()); + require(';'); + mark(1); // ensure we don't reset to before the semicolon + if (doctype != null) + { + String entityName = "%" + name; + Object entity = doctype.getEntity(entityName); + if (entity != null) + { + if (xmlStandalone == Boolean.TRUE) + { + if (doctype.isEntityExternal(entityName)) + error("reference to external parameter entity in " + + "standalone document"); + } + if (entity instanceof String) + { + pushInput(name, (String) entity, false, input.normalize); + //pushInput(name, " " + (String) entity + " "); + } + else + { + //pushInput("", " "); + pushInput(name, (ExternalIds) entity, false, input.normalize); + //pushInput("", " "); + } + } + else + error("reference to undeclared parameter entity", name); + } + else + error("reference to parameter entity without doctype", name); + } + + /** + * Parse the digits in a character reference. + * @param base the base of the digits (10 or 16) + */ + private char[] readCharacterRef(int base) + throws IOException, XMLStreamException + { + CPStringBuilder b = new CPStringBuilder(); + for (int c = readCh(); c != 0x3b && c != -1; c = readCh()) + b.append(Character.toChars(c)); + try + { + int ord = Integer.parseInt(b.toString(), base); + if (input.xml11) + { + if (!isXML11Char(ord)) + error("illegal XML 1.1 character reference " + + "U+" + Integer.toHexString(ord)); + } + else + { + if ((ord < 0x20 && !(ord == 0x0a || ord == 0x09 || ord == 0x0d)) + || (ord >= 0xd800 && ord <= 0xdfff) + || ord == 0xfffe || ord == 0xffff + || ord > 0x0010ffff) + error("illegal XML character reference " + + "U+" + Integer.toHexString(ord)); + } + return Character.toChars(ord); + } + catch (NumberFormatException e) + { + error("illegal characters in character reference", b.toString()); + return null; + } + } + + /** + * Parses an NMTOKEN or Name production. + * @param isName if a Name, otherwise an NMTOKEN + */ + private String readNmtoken(boolean isName) + throws IOException, XMLStreamException + { + return readNmtoken(isName, nmtokenBuf); + } + + /** + * Parses an NMTOKEN or Name production using the specified buffer. + * @param isName if a Name, otherwise an NMTOKEN + * @param buf the character buffer to use + */ + private String readNmtoken(boolean isName, StringBuffer buf) + throws IOException, XMLStreamException + { + buf.setLength(0); + int c = readCh(); + if (isName) + { + if (!isNameStartCharacter(c, input.xml11)) + error("not a name start character", + "U+" + Integer.toHexString(c)); + } + else + { + if (!isNameCharacter(c, input.xml11)) + error("not a name character", + "U+" + Integer.toHexString(c)); + } + buf.append(Character.toChars(c)); + do + { + mark(1); + c = readCh(); + switch (c) + { + case 0x25: // '%' + case 0x3c: // '<' + case 0x3e: // '>' + case 0x26: // '&' + case 0x2c: // ',' + case 0x7c: // '|' + case 0x2a: // '*' + case 0x2b: // '+' + case 0x3f: // '?' + case 0x29: // ')' + case 0x3d: // '=' + case 0x27: // '\'' + case 0x22: // '"' + case 0x5b: // '[' + case 0x20: // ' ' + case 0x09: // '\t' + case 0x0a: // '\n' + case 0x0d: // '\r' + case 0x3b: // ';' + case 0x2f: // '/' + case -1: + reset(); + return intern(buf.toString()); + default: + if (!isNameCharacter(c, input.xml11)) + error("not a name character", + "U+" + Integer.toHexString(c)); + else + buf.append(Character.toChars(c)); + } + } + while (true); + } + + /** + * Indicates whether the specified Unicode character is an XML 1.1 Char. + */ + public static boolean isXML11Char(int c) + { + return ((c >= 0x0001 && c <= 0xD7FF) || + (c >= 0xE000 && c < 0xFFFE) || + (c >= 0x10000 && c <= 0x10FFFF)); + } + + /** + * Indicates whether the specified Unicode character is an XML 1.1 + * RestrictedChar. + */ + public static boolean isXML11RestrictedChar(int c) + { + return ((c >= 0x0001 && c <= 0x0008) || + (c >= 0x000B && c <= 0x000C) || + (c >= 0x000E && c <= 0x001F) || + (c >= 0x007F && c <= 0x0084) || + (c >= 0x0086 && c <= 0x009F)); + } + + /** + * Indicates whether the specified text matches the Name or Nmtoken + * production. + */ + private boolean isNmtoken(String text, boolean isName) + { + try + { + int[] cp = UnicodeReader.toCodePointArray(text); + if (cp.length == 0) + return false; + if (isName) + { + if (!isNameStartCharacter(cp[0], input.xml11)) + return false; + } + else + { + if (!isNameCharacter(cp[0], input.xml11)) + return false; + } + for (int i = 1; i < cp.length; i++) + { + if (!isNameCharacter(cp[i], input.xml11)) + return false; + } + return true; + } + catch (IOException e) + { + return false; + } + } + + /** + * Indicates whether the specified Unicode character is a Name start + * character. + */ + public static boolean isNameStartCharacter(int c, boolean xml11) + { + if (xml11) + return ((c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + c == 0x3a | + c == 0x5f | + (c >= 0xC0 && c <= 0xD6) || + (c >= 0xD8 && c <= 0xF6) || + (c >= 0xF8 && c <= 0x2FF) || + (c >= 0x370 && c <= 0x37D) || + (c >= 0x37F && c <= 0x1FFF) || + (c >= 0x200C && c <= 0x200D) || + (c >= 0x2070 && c <= 0x218F) || + (c >= 0x2C00 && c <= 0x2FEF) || + (c >= 0x3001 && c <= 0xD7FF) || + (c >= 0xF900 && c <= 0xFDCF) || + (c >= 0xFDF0 && c <= 0xFFFD) || + (c >= 0x10000 && c <= 0xEFFFF)); + else + return (c == 0x5f || c == 0x3a || isLetter(c)); + } + + /** + * Indicates whether the specified Unicode character is a Name non-initial + * character. + */ + public static boolean isNameCharacter(int c, boolean xml11) + { + if (xml11) + return ((c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + (c >= 0x0030 && c <= 0x0039) || + c == 0x3a | + c == 0x5f | + c == 0x2d | + c == 0x2e | + c == 0xB7 | + (c >= 0xC0 && c <= 0xD6) || + (c >= 0xD8 && c <= 0xF6) || + (c >= 0xF8 && c <= 0x2FF) || + (c >= 0x300 && c <= 0x37D) || + (c >= 0x37F && c <= 0x1FFF) || + (c >= 0x200C && c <= 0x200D) || + (c >= 0x203F && c <= 0x2040) || + (c >= 0x2070 && c <= 0x218F) || + (c >= 0x2C00 && c <= 0x2FEF) || + (c >= 0x3001 && c <= 0xD7FF) || + (c >= 0xF900 && c <= 0xFDCF) || + (c >= 0xFDF0 && c <= 0xFFFD) || + (c >= 0x10000 && c <= 0xEFFFF)); + else + return (c == 0x2e || c == 0x2d || c == 0x5f || c == 0x3a || + isLetter(c) || isDigit(c) || + isCombiningChar(c) || isExtender(c)); + } + + /** + * Indicates whether the specified Unicode character matches the Letter + * production. + */ + public static boolean isLetter(int c) + { + if ((c >= 0x0041 && c <= 0x005A) || + (c >= 0x0061 && c <= 0x007A) || + (c >= 0x00C0 && c <= 0x00D6) || + (c >= 0x00D8 && c <= 0x00F6) || + (c >= 0x00F8 && c <= 0x00FF) || + (c >= 0x0100 && c <= 0x0131) || + (c >= 0x0134 && c <= 0x013E) || + (c >= 0x0141 && c <= 0x0148) || + (c >= 0x014A && c <= 0x017E) || + (c >= 0x0180 && c <= 0x01C3) || + (c >= 0x01CD && c <= 0x01F0) || + (c >= 0x01F4 && c <= 0x01F5) || + (c >= 0x01FA && c <= 0x0217) || + (c >= 0x0250 && c <= 0x02A8) || + (c >= 0x02BB && c <= 0x02C1) || + c == 0x0386 || + (c >= 0x0388 && c <= 0x038A) || + c == 0x038C || + (c >= 0x038E && c <= 0x03A1) || + (c >= 0x03A3 && c <= 0x03CE) || + (c >= 0x03D0 && c <= 0x03D6) || + c == 0x03DA || + c == 0x03DC || + c == 0x03DE || + c == 0x03E0 || + (c >= 0x03E2 && c <= 0x03F3) || + (c >= 0x0401 && c <= 0x040C) || + (c >= 0x040E && c <= 0x044F) || + (c >= 0x0451 && c <= 0x045C) || + (c >= 0x045E && c <= 0x0481) || + (c >= 0x0490 && c <= 0x04C4) || + (c >= 0x04C7 && c <= 0x04C8) || + (c >= 0x04CB && c <= 0x04CC) || + (c >= 0x04D0 && c <= 0x04EB) || + (c >= 0x04EE && c <= 0x04F5) || + (c >= 0x04F8 && c <= 0x04F9) || + (c >= 0x0531 && c <= 0x0556) || + c == 0x0559 || + (c >= 0x0561 && c <= 0x0586) || + (c >= 0x05D0 && c <= 0x05EA) || + (c >= 0x05F0 && c <= 0x05F2) || + (c >= 0x0621 && c <= 0x063A) || + (c >= 0x0641 && c <= 0x064A) || + (c >= 0x0671 && c <= 0x06B7) || + (c >= 0x06BA && c <= 0x06BE) || + (c >= 0x06C0 && c <= 0x06CE) || + (c >= 0x06D0 && c <= 0x06D3) || + c == 0x06D5 || + (c >= 0x06E5 && c <= 0x06E6) || + (c >= 0x0905 && c <= 0x0939) || + c == 0x093D || + (c >= 0x0958 && c <= 0x0961) || + (c >= 0x0985 && c <= 0x098C) || + (c >= 0x098F && c <= 0x0990) || + (c >= 0x0993 && c <= 0x09A8) || + (c >= 0x09AA && c <= 0x09B0) || + c == 0x09B2 || + (c >= 0x09B6 && c <= 0x09B9) || + (c >= 0x09DC && c <= 0x09DD) || + (c >= 0x09DF && c <= 0x09E1) || + (c >= 0x09F0 && c <= 0x09F1) || + (c >= 0x0A05 && c <= 0x0A0A) || + (c >= 0x0A0F && c <= 0x0A10) || + (c >= 0x0A13 && c <= 0x0A28) || + (c >= 0x0A2A && c <= 0x0A30) || + (c >= 0x0A32 && c <= 0x0A33) || + (c >= 0x0A35 && c <= 0x0A36) || + (c >= 0x0A38 && c <= 0x0A39) || + (c >= 0x0A59 && c <= 0x0A5C) || + c == 0x0A5E || + (c >= 0x0A72 && c <= 0x0A74) || + (c >= 0x0A85 && c <= 0x0A8B) || + c == 0x0A8D || + (c >= 0x0A8F && c <= 0x0A91) || + (c >= 0x0A93 && c <= 0x0AA8) || + (c >= 0x0AAA && c <= 0x0AB0) || + (c >= 0x0AB2 && c <= 0x0AB3) || + (c >= 0x0AB5 && c <= 0x0AB9) || + c == 0x0ABD || + c == 0x0AE0 || + (c >= 0x0B05 && c <= 0x0B0C) || + (c >= 0x0B0F && c <= 0x0B10) || + (c >= 0x0B13 && c <= 0x0B28) || + (c >= 0x0B2A && c <= 0x0B30) || + (c >= 0x0B32 && c <= 0x0B33) || + (c >= 0x0B36 && c <= 0x0B39) || + c == 0x0B3D || + (c >= 0x0B5C && c <= 0x0B5D) || + (c >= 0x0B5F && c <= 0x0B61) || + (c >= 0x0B85 && c <= 0x0B8A) || + (c >= 0x0B8E && c <= 0x0B90) || + (c >= 0x0B92 && c <= 0x0B95) || + (c >= 0x0B99 && c <= 0x0B9A) || + c == 0x0B9C || + (c >= 0x0B9E && c <= 0x0B9F) || + (c >= 0x0BA3 && c <= 0x0BA4) || + (c >= 0x0BA8 && c <= 0x0BAA) || + (c >= 0x0BAE && c <= 0x0BB5) || + (c >= 0x0BB7 && c <= 0x0BB9) || + (c >= 0x0C05 && c <= 0x0C0C) || + (c >= 0x0C0E && c <= 0x0C10) || + (c >= 0x0C12 && c <= 0x0C28) || + (c >= 0x0C2A && c <= 0x0C33) || + (c >= 0x0C35 && c <= 0x0C39) || + (c >= 0x0C60 && c <= 0x0C61) || + (c >= 0x0C85 && c <= 0x0C8C) || + (c >= 0x0C8E && c <= 0x0C90) || + (c >= 0x0C92 && c <= 0x0CA8) || + (c >= 0x0CAA && c <= 0x0CB3) || + (c >= 0x0CB5 && c <= 0x0CB9) || + c == 0x0CDE || + (c >= 0x0CE0 && c <= 0x0CE1) || + (c >= 0x0D05 && c <= 0x0D0C) || + (c >= 0x0D0E && c <= 0x0D10) || + (c >= 0x0D12 && c <= 0x0D28) || + (c >= 0x0D2A && c <= 0x0D39) || + (c >= 0x0D60 && c <= 0x0D61) || + (c >= 0x0E01 && c <= 0x0E2E) || + c == 0x0E30 || + (c >= 0x0E32 && c <= 0x0E33) || + (c >= 0x0E40 && c <= 0x0E45) || + (c >= 0x0E81 && c <= 0x0E82) || + c == 0x0E84 || + (c >= 0x0E87 && c <= 0x0E88) || + c == 0x0E8A || + c == 0x0E8D || + (c >= 0x0E94 && c <= 0x0E97) || + (c >= 0x0E99 && c <= 0x0E9F) || + (c >= 0x0EA1 && c <= 0x0EA3) || + c == 0x0EA5 || + c == 0x0EA7 || + (c >= 0x0EAA && c <= 0x0EAB) || + (c >= 0x0EAD && c <= 0x0EAE) || + c == 0x0EB0 || + (c >= 0x0EB2 && c <= 0x0EB3) || + c == 0x0EBD || + (c >= 0x0EC0 && c <= 0x0EC4) || + (c >= 0x0F40 && c <= 0x0F47) || + (c >= 0x0F49 && c <= 0x0F69) || + (c >= 0x10A0 && c <= 0x10C5) || + (c >= 0x10D0 && c <= 0x10F6) || + c == 0x1100 || + (c >= 0x1102 && c <= 0x1103) || + (c >= 0x1105 && c <= 0x1107) || + c == 0x1109 || + (c >= 0x110B && c <= 0x110C) || + (c >= 0x110E && c <= 0x1112) || + c == 0x113C || + c == 0x113E || + c == 0x1140 || + c == 0x114C || + c == 0x114E || + c == 0x1150 || + (c >= 0x1154 && c <= 0x1155) || + c == 0x1159 || + (c >= 0x115F && c <= 0x1161) || + c == 0x1163 || + c == 0x1165 || + c == 0x1167 || + c == 0x1169 || + (c >= 0x116D && c <= 0x116E) || + (c >= 0x1172 && c <= 0x1173) || + c == 0x1175 || + c == 0x119E || + c == 0x11A8 || + c == 0x11AB || + (c >= 0x11AE && c <= 0x11AF) || + (c >= 0x11B7 && c <= 0x11B8) || + c == 0x11BA || + (c >= 0x11BC && c <= 0x11C2) || + c == 0x11EB || + c == 0x11F0 || + c == 0x11F9 || + (c >= 0x1E00 && c <= 0x1E9B) || + (c >= 0x1EA0 && c <= 0x1EF9) || + (c >= 0x1F00 && c <= 0x1F15) || + (c >= 0x1F18 && c <= 0x1F1D) || + (c >= 0x1F20 && c <= 0x1F45) || + (c >= 0x1F48 && c <= 0x1F4D) || + (c >= 0x1F50 && c <= 0x1F57) || + c == 0x1F59 || + c == 0x1F5B || + c == 0x1F5D || + (c >= 0x1F5F && c <= 0x1F7D) || + (c >= 0x1F80 && c <= 0x1FB4) || + (c >= 0x1FB6 && c <= 0x1FBC) || + c == 0x1FBE || + (c >= 0x1FC2 && c <= 0x1FC4) || + (c >= 0x1FC6 && c <= 0x1FCC) || + (c >= 0x1FD0 && c <= 0x1FD3) || + (c >= 0x1FD6 && c <= 0x1FDB) || + (c >= 0x1FE0 && c <= 0x1FEC) || + (c >= 0x1FF2 && c <= 0x1FF4) || + (c >= 0x1FF6 && c <= 0x1FFC) || + c == 0x2126 || + (c >= 0x212A && c <= 0x212B) || + c == 0x212E || + (c >= 0x2180 && c <= 0x2182) || + (c >= 0x3041 && c <= 0x3094) || + (c >= 0x30A1 && c <= 0x30FA) || + (c >= 0x3105 && c <= 0x312C) || + (c >= 0xAC00 && c <= 0xD7A3)) + return true; // BaseChar + if ((c >= 0x4e00 && c <= 0x9fa5) || + c == 0x3007 || + (c >= 0x3021 && c <= 0x3029)) + return true; // Ideographic + return false; + } + + /** + * Indicates whether the specified Unicode character matches the Digit + * production. + */ + public static boolean isDigit(int c) + { + return ((c >= 0x0030 && c <= 0x0039) || + (c >= 0x0660 && c <= 0x0669) || + (c >= 0x06F0 && c <= 0x06F9) || + (c >= 0x0966 && c <= 0x096F) || + (c >= 0x09E6 && c <= 0x09EF) || + (c >= 0x0A66 && c <= 0x0A6F) || + (c >= 0x0AE6 && c <= 0x0AEF) || + (c >= 0x0B66 && c <= 0x0B6F) || + (c >= 0x0BE7 && c <= 0x0BEF) || + (c >= 0x0C66 && c <= 0x0C6F) || + (c >= 0x0CE6 && c <= 0x0CEF) || + (c >= 0x0D66 && c <= 0x0D6F) || + (c >= 0x0E50 && c <= 0x0E59) || + (c >= 0x0ED0 && c <= 0x0ED9) || + (c >= 0x0F20 && c <= 0x0F29)); + } + + /** + * Indicates whether the specified Unicode character matches the + * CombiningChar production. + */ + public static boolean isCombiningChar(int c) + { + return ((c >= 0x0300 && c <= 0x0345) || + (c >= 0x0360 && c <= 0x0361) || + (c >= 0x0483 && c <= 0x0486) || + (c >= 0x0591 && c <= 0x05A1) || + (c >= 0x05A3 && c <= 0x05B9) || + (c >= 0x05BB && c <= 0x05BD) || + c == 0x05BF || + (c >= 0x05C1 && c <= 0x05C2) || + c == 0x05C4 || + (c >= 0x064B && c <= 0x0652) || + c == 0x0670 || + (c >= 0x06D6 && c <= 0x06DC) || + (c >= 0x06DD && c <= 0x06DF) || + (c >= 0x06E0 && c <= 0x06E4) || + (c >= 0x06E7 && c <= 0x06E8) || + (c >= 0x06EA && c <= 0x06ED) || + (c >= 0x0901 && c <= 0x0903) || + c == 0x093C || + (c >= 0x093E && c <= 0x094C) || + c == 0x094D || + (c >= 0x0951 && c <= 0x0954) || + (c >= 0x0962 && c <= 0x0963) || + (c >= 0x0981 && c <= 0x0983) || + c == 0x09BC || + c == 0x09BE || + c == 0x09BF || + (c >= 0x09C0 && c <= 0x09C4) || + (c >= 0x09C7 && c <= 0x09C8) || + (c >= 0x09CB && c <= 0x09CD) || + c == 0x09D7 || + (c >= 0x09E2 && c <= 0x09E3) || + c == 0x0A02 || + c == 0x0A3C || + c == 0x0A3E || + c == 0x0A3F || + (c >= 0x0A40 && c <= 0x0A42) || + (c >= 0x0A47 && c <= 0x0A48) || + (c >= 0x0A4B && c <= 0x0A4D) || + (c >= 0x0A70 && c <= 0x0A71) || + (c >= 0x0A81 && c <= 0x0A83) || + c == 0x0ABC || + (c >= 0x0ABE && c <= 0x0AC5) || + (c >= 0x0AC7 && c <= 0x0AC9) || + (c >= 0x0ACB && c <= 0x0ACD) || + (c >= 0x0B01 && c <= 0x0B03) || + c == 0x0B3C || + (c >= 0x0B3E && c <= 0x0B43) || + (c >= 0x0B47 && c <= 0x0B48) || + (c >= 0x0B4B && c <= 0x0B4D) || + (c >= 0x0B56 && c <= 0x0B57) || + (c >= 0x0B82 && c <= 0x0B83) || + (c >= 0x0BBE && c <= 0x0BC2) || + (c >= 0x0BC6 && c <= 0x0BC8) || + (c >= 0x0BCA && c <= 0x0BCD) || + c == 0x0BD7 || + (c >= 0x0C01 && c <= 0x0C03) || + (c >= 0x0C3E && c <= 0x0C44) || + (c >= 0x0C46 && c <= 0x0C48) || + (c >= 0x0C4A && c <= 0x0C4D) || + (c >= 0x0C55 && c <= 0x0C56) || + (c >= 0x0C82 && c <= 0x0C83) || + (c >= 0x0CBE && c <= 0x0CC4) || + (c >= 0x0CC6 && c <= 0x0CC8) || + (c >= 0x0CCA && c <= 0x0CCD) || + (c >= 0x0CD5 && c <= 0x0CD6) || + (c >= 0x0D02 && c <= 0x0D03) || + (c >= 0x0D3E && c <= 0x0D43) || + (c >= 0x0D46 && c <= 0x0D48) || + (c >= 0x0D4A && c <= 0x0D4D) || + c == 0x0D57 || + c == 0x0E31 || + (c >= 0x0E34 && c <= 0x0E3A) || + (c >= 0x0E47 && c <= 0x0E4E) || + c == 0x0EB1 || + (c >= 0x0EB4 && c <= 0x0EB9) || + (c >= 0x0EBB && c <= 0x0EBC) || + (c >= 0x0EC8 && c <= 0x0ECD) || + (c >= 0x0F18 && c <= 0x0F19) || + c == 0x0F35 || + c == 0x0F37 || + c == 0x0F39 || + c == 0x0F3E || + c == 0x0F3F || + (c >= 0x0F71 && c <= 0x0F84) || + (c >= 0x0F86 && c <= 0x0F8B) || + (c >= 0x0F90 && c <= 0x0F95) || + c == 0x0F97 || + (c >= 0x0F99 && c <= 0x0FAD) || + (c >= 0x0FB1 && c <= 0x0FB7) || + c == 0x0FB9 || + (c >= 0x20D0 && c <= 0x20DC) || + c == 0x20E1 || + (c >= 0x302A && c <= 0x302F) || + c == 0x3099 || + c == 0x309A); + } + + /** + * Indicates whether the specified Unicode character matches the Extender + * production. + */ + public static boolean isExtender(int c) + { + return (c == 0x00B7 || + c == 0x02D0 || + c == 0x02D1 || + c == 0x0387 || + c == 0x0640 || + c == 0x0E46 || + c == 0x0EC6 || + c == 0x3005 || + (c >= 0x3031 && c <= 0x3035) || + (c >= 0x309D && c <= 0x309E) || + (c >= 0x30FC && c <= 0x30FE)); + } + + /** + * Indicates whether the specified Unicode character matches the Char + * production. + */ + public static boolean isChar(int c) + { + return (c >= 0x20 && c < 0xd800) || + (c >= 0xe00 && c < 0xfffe) || + (c >= 0x10000 && c < 0x110000) || + c == 0xa || c == 0x9 || c == 0xd; + } + + /** + * Interns the specified text or not, depending on the value of + * stringInterning. + */ + private String intern(String text) + { + return stringInterning ? text.intern() : text; + } + + /** + * Report a parsing error. + */ + private void error(String message) + throws XMLStreamException + { + error(message, null); + } + + /** + * Report a parsing error. + */ + private void error(String message, Object info) + throws XMLStreamException + { + if (info != null) + { + if (info instanceof String) + message += ": \"" + ((String) info) + "\""; + else if (info instanceof Character) + message += ": '" + ((Character) info) + "'"; + } + throw new XMLStreamException(message); + } + + /** + * Perform validation of a start-element event. + */ + private void validateStartElement(String elementName) + throws XMLStreamException + { + if (currentContentModel == null) + { + // root element + // VC: Root Element Type + if (!elementName.equals(doctype.rootName)) + error("root element name must match name in DTD"); + return; + } + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.EMPTY: + error("child element found in empty element", elementName); + break; + case ContentModel.ELEMENT: + LinkedList ctx = (LinkedList) validationStack.getLast(); + ctx.add(elementName); + break; + case ContentModel.MIXED: + MixedContentModel mm = (MixedContentModel) currentContentModel; + if (!mm.containsName(elementName)) + error("illegal element for content model", elementName); + break; + } + } + + /** + * Perform validation of an end-element event. + */ + private void validateEndElement() + throws XMLStreamException + { + if (currentContentModel == null) + { + // root element + // VC: IDREF + if (!idrefs.containsAll(ids)) + error("IDREF values must match the value of some ID attribute"); + return; + } + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.ELEMENT: + LinkedList ctx = (LinkedList) validationStack.getLast(); + ElementContentModel ecm = (ElementContentModel) currentContentModel; + validateElementContent(ecm, ctx); + break; + } + } + + /** + * Perform validation of character data. + */ + private void validatePCData(String text) + throws XMLStreamException + { + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.EMPTY: + error("character data found in empty element", text); + break; + case ContentModel.ELEMENT: + boolean white = true; + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') + { + white = false; + break; + } + } + if (!white) + error("character data found in element with element content", text); + else if (xmlStandalone == Boolean.TRUE && currentContentModel.external) + // VC: Standalone Document Declaration + error("whitespace in element content of externally declared " + + "element in standalone document"); + break; + } + } + + /** + * Validates the specified validation context (list of child elements) + * against the element content model for the current element. + */ + private void validateElementContent(ElementContentModel model, + LinkedList children) + throws XMLStreamException + { + // Use regular expression + CPStringBuilder buf = new CPStringBuilder(); + for (Iterator i = children.iterator(); i.hasNext(); ) + { + buf.append((String) i.next()); + buf.append(' '); + } + String c = buf.toString(); + String regex = createRegularExpression(model); + if (!c.matches(regex)) + error("element content "+model.text+" does not match expression "+regex, c); + } + + /** + * Creates the regular expression used to validate an element content + * model. + */ + private String createRegularExpression(ElementContentModel model) + { + if (model.regex == null) + { + CPStringBuilder buf = new CPStringBuilder(); + buf.append('('); + for (Iterator i = model.contentParticles.iterator(); i.hasNext(); ) + { + ContentParticle cp = (ContentParticle) i.next(); + if (cp.content instanceof String) + { + buf.append('('); + buf.append((String) cp.content); + buf.append(' '); + buf.append(')'); + if (cp.max == -1) + { + if (cp.min == 0) + buf.append('*'); + else + buf.append('+'); + } + else if (cp.min == 0) + buf.append('?'); + } + else + { + ElementContentModel ecm = (ElementContentModel) cp.content; + buf.append(createRegularExpression(ecm)); + } + if (model.or && i.hasNext()) + buf.append('|'); + } + buf.append(')'); + if (model.max == -1) + { + if (model.min == 0) + buf.append('*'); + else + buf.append('+'); + } + else if (model.min == 0) + buf.append('?'); + model.regex = buf.toString(); + } + return model.regex; + } + + /** + * Performs validation of a document type declaration event. + */ + void validateDoctype() + throws XMLStreamException + { + for (Iterator i = doctype.entityIterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + Object entity = entry.getValue(); + if (entity instanceof ExternalIds) + { + ExternalIds ids = (ExternalIds) entity; + if (ids.notationName != null) + { + // VC: Notation Declared + ExternalIds notation = doctype.getNotation(ids.notationName); + if (notation == null) + error("Notation name must match the declared name of a " + + "notation", ids.notationName); + } + } + } + } + + /** + * Simple test harness for reading an XML file. + * args[0] is the filename of the XML file + * If args[1] is "-x", enable XInclude processing + */ + public static void main(String[] args) + throws Exception + { + boolean validating = false; + boolean namespaceAware = false; + boolean xIncludeAware = false; + int pos = 0; + while (pos < args.length && args[pos].startsWith("-")) + { + if ("-x".equals(args[pos])) + xIncludeAware = true; + else if ("-v".equals(args[pos])) + validating = true; + else if ("-n".equals(args[pos])) + namespaceAware = true; + pos++; + } + if (pos >= args.length) + { + System.out.println("Syntax: XMLParser [-n] [-v] [-x] [ [...]]"); + System.out.println("\t-n: use namespace aware mode"); + System.out.println("\t-v: use validating parser"); + System.out.println("\t-x: use XInclude aware mode"); + System.exit(2); + } + while (pos < args.length) + { + XMLParser p = new XMLParser(new java.io.FileInputStream(args[pos]), + absolutize(null, args[pos]), + validating, // validating + namespaceAware, // namespaceAware + true, // coalescing, + true, // replaceERefs + true, // externalEntities + true, // supportDTD + true, // baseAware + true, // stringInterning + true, // extendedEventTypes + null, + null); + XMLStreamReader reader = p; + if (xIncludeAware) + reader = new XIncludeFilter(p, args[pos], true, true, true); + try + { + int event; + //do + while (reader.hasNext()) + { + event = reader.next(); + Location loc = reader.getLocation(); + System.out.print(loc.getLineNumber() + ":" + + loc.getColumnNumber() + " "); + switch (event) + { + case XMLStreamConstants.START_DOCUMENT: + System.out.println("START_DOCUMENT version=" + + reader.getVersion() + + " encoding=" + + reader.getEncoding()); + break; + case XMLStreamConstants.END_DOCUMENT: + System.out.println("END_DOCUMENT"); + break; + case XMLStreamConstants.START_ELEMENT: + System.out.println("START_ELEMENT " + + reader.getName()); + int l = reader.getNamespaceCount(); + for (int i = 0; i < l; i++) + System.out.println("\tnamespace " + + reader.getNamespacePrefix(i) + "='" + + reader.getNamespaceURI(i)+"'"); + l = reader.getAttributeCount(); + for (int i = 0; i < l; i++) + System.out.println("\tattribute " + + reader.getAttributeName(i) + "='" + + reader.getAttributeValue(i) + "'"); + break; + case XMLStreamConstants.END_ELEMENT: + System.out.println("END_ELEMENT " + reader.getName()); + break; + case XMLStreamConstants.CHARACTERS: + System.out.println("CHARACTERS '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.CDATA: + System.out.println("CDATA '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.SPACE: + System.out.println("SPACE '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.DTD: + System.out.println("DTD " + reader.getText()); + break; + case XMLStreamConstants.ENTITY_REFERENCE: + System.out.println("ENTITY_REFERENCE " + reader.getText()); + break; + case XMLStreamConstants.COMMENT: + System.out.println("COMMENT '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + System.out.println("PROCESSING_INSTRUCTION " + + reader.getPITarget() + " " + + reader.getPIData()); + break; + case START_ENTITY: + System.out.println("START_ENTITY " + reader.getText()); + break; + case END_ENTITY: + System.out.println("END_ENTITY " + reader.getText()); + break; + default: + System.out.println("Unknown event: " + event); + } + } + } + catch (XMLStreamException e) + { + Location l = reader.getLocation(); + System.out.println("At line "+l.getLineNumber()+ + ", column "+l.getColumnNumber()+ + " of "+l.getSystemId()); + throw e; + } + pos++; + } + } + + /** + * Escapes control characters in the specified text. For debugging. + */ + private static String encodeText(String text) + { + CPStringBuilder b = new CPStringBuilder(); + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + switch (c) + { + case '\t': + b.append("\\t"); + break; + case '\n': + b.append("\\n"); + break; + case '\r': + b.append("\\r"); + break; + default: + b.append(c); + } + } + return b.toString(); + } + + /** + * An attribute instance. + */ + class Attribute + { + + /** + * Attribute name. + */ + final String name; + + /** + * Attribute type as declared in the DTD, or CDATA otherwise. + */ + final String type; + + /** + * Whether the attribute was specified or defaulted. + */ + final boolean specified; + + /** + * The attribute value. + */ + final String value; + + /** + * The namespace prefix. + */ + final String prefix; + + /** + * The namespace local-name. + */ + final String localName; + + Attribute(String name, String type, boolean specified, String value) + { + this.name = name; + this.type = type; + this.specified = specified; + this.value = value; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = intern(name); + } + else + { + prefix = intern(name.substring(0, ci)); + localName = intern(name.substring(ci + 1)); + } + } + + public boolean equals(Object other) + { + if (other instanceof Attribute) + { + Attribute a = (Attribute) other; + if (namespaceAware) + { + if (!a.localName.equals(localName)) + return false; + String auri = getNamespaceURI(a.prefix); + String uri = getNamespaceURI(prefix); + if (uri == null && (auri == null || + (input.xml11 && "".equals(auri)))) + return true; + if (uri != null) + { + if ("".equals(uri) && input.xml11 && "".equals(auri)) + return true; + return uri.equals(auri); + } + return false; + } + else + return a.name.equals(name); + } + return false; + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(getClass().getName()); + buf.append('['); + buf.append("name="); + buf.append(name); + if (value != null) + { + buf.append(",value="); + buf.append(value); + } + if (type != null) + { + buf.append(",type="); + buf.append(type); + } + if (specified) + buf.append(",specified"); + buf.append(']'); + return buf.toString(); + } + + } + + /** + * Representation of a DTD. + */ + class Doctype + { + + /** + * Name of the root element. + */ + final String rootName; + + /** + * Public ID, if any, of external subset. + */ + final String publicId; + + /** + * System ID (URL), if any, of external subset. + */ + final String systemId; + + /** + * Map of element names to content models. + */ + private final LinkedHashMap elements = new LinkedHashMap(); + + /** + * Map of element names to maps of attribute declarations. + */ + private final LinkedHashMap attlists = new LinkedHashMap(); + + /** + * Map of entity names to entities (String or ExternalIds). + */ + private final LinkedHashMap entities = new LinkedHashMap(); + + /** + * Map of notation names to ExternalIds. + */ + private final LinkedHashMap notations = new LinkedHashMap(); + + /** + * Map of anonymous keys to comments. + */ + private final LinkedHashMap comments = new LinkedHashMap(); + + /** + * Map of anonymous keys to processing instructions (String[2] + * containing {target, data}). + */ + private final LinkedHashMap pis = new LinkedHashMap(); + + /** + * List of keys to all markup entries in the DTD. + */ + private final LinkedList entries = new LinkedList(); + + /** + * Set of the entities defined in the external subset. + */ + private final HashSet externalEntities = new HashSet(); + + /** + * Set of the notations defined in the external subset. + */ + private final HashSet externalNotations = new HashSet(); + + /** + * Counter for making anonymous keys. + */ + private int anon = 1; + + /** + * Constructor. + */ + Doctype(String rootName, String publicId, String systemId) + { + this.rootName = rootName; + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * Adds an element declaration. + * @param name the element name + * @param text the content model text + * @param model the parsed content model + */ + void addElementDecl(String name, String text, ContentModel model) + { + if (elements.containsKey(name)) + return; + model.text = text; + model.external = (inputStack.size() != 1); + elements.put(name, model); + entries.add("E" + name); + } + + /** + * Adds an attribute declaration. + * @param ename the element name + * @param aname the attribute name + * @param decl the attribute declaration details + */ + void addAttributeDecl(String ename, String aname, AttributeDecl decl) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + if (attlist == null) + { + attlist = new LinkedHashMap(); + attlists.put(ename, attlist); + } + else if (attlist.containsKey(aname)) + return; + attlist.put(aname, decl); + String key = "A" + ename; + if (!entries.contains(key)) + entries.add(key); + } + + /** + * Adds an entity declaration. + * @param name the entity name + * @param text the entity replacement text + * @param inExternalSubset if we are in the exernal subset + */ + void addEntityDecl(String name, String text, boolean inExternalSubset) + { + if (entities.containsKey(name)) + return; + entities.put(name, text); + entries.add("e" + name); + if (inExternalSubset) + externalEntities.add(name); + } + + /** + * Adds an entity declaration. + * @param name the entity name + * @param ids the external IDs + * @param inExternalSubset if we are in the exernal subset + */ + void addEntityDecl(String name, ExternalIds ids, boolean inExternalSubset) + { + if (entities.containsKey(name)) + return; + entities.put(name, ids); + entries.add("e" + name); + if (inExternalSubset) + externalEntities.add(name); + } + + /** + * Adds a notation declaration. + * @param name the notation name + * @param ids the external IDs + * @param inExternalSubset if we are in the exernal subset + */ + void addNotationDecl(String name, ExternalIds ids, boolean inExternalSubset) + { + if (notations.containsKey(name)) + return; + notations.put(name, ids); + entries.add("n" + name); + if (inExternalSubset) + externalNotations.add(name); + } + + /** + * Adds a comment. + */ + void addComment(String text) + { + String key = Integer.toString(anon++); + comments.put(key, text); + entries.add("c" + key); + } + + /** + * Adds a processing instruction. + */ + void addPI(String target, String data) + { + String key = Integer.toString(anon++); + pis.put(key, new String[] {target, data}); + entries.add("p" + key); + } + + /** + * Returns the content model for the specified element. + * @param name the element name + */ + ContentModel getElementModel(String name) + { + return (ContentModel) elements.get(name); + } + + /** + * Returns the attribute definition for the given attribute + * @param ename the element name + * @param aname the attribute name + */ + AttributeDecl getAttributeDecl(String ename, String aname) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? null : (AttributeDecl) attlist.get(aname); + } + + /** + * Indicates whether the specified attribute was declared in the DTD. + * @param ename the element name + * @param aname the attribute name + */ + boolean isAttributeDeclared(String ename, String aname) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? false : attlist.containsKey(aname); + } + + /** + * Returns an iterator over the entries in the attribute list for the + * given element. + * @param ename the element name + */ + Iterator attlistIterator(String ename) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? Collections.EMPTY_LIST.iterator() : + attlist.entrySet().iterator(); + } + + /** + * Returns the entity (String or ExternalIds) for the given entity name. + */ + Object getEntity(String name) + { + return entities.get(name); + } + + /** + * Indicates whether the specified entity was declared in the external + * subset. + */ + boolean isEntityExternal(String name) + { + return externalEntities.contains(name); + } + + /** + * Returns an iterator over the entity map entries. + */ + Iterator entityIterator() + { + return entities.entrySet().iterator(); + } + + /** + * Returns the notation IDs for the given notation name. + */ + ExternalIds getNotation(String name) + { + return (ExternalIds) notations.get(name); + } + + /** + * Indicates whether the specified notation was declared in the external + * subset. + */ + boolean isNotationExternal(String name) + { + return externalNotations.contains(name); + } + + /** + * Returns the comment associated with the specified (anonymous) key. + */ + String getComment(String key) + { + return (String) comments.get(key); + } + + /** + * Returns the processing instruction associated with the specified + * (anonymous) key. + */ + String[] getPI(String key) + { + return (String[]) pis.get(key); + } + + /** + * Returns an iterator over the keys of the markup entries in this DTD, + * in the order declared. + */ + Iterator entryIterator() + { + return entries.iterator(); + } + + } + + /** + * Combination of an ExternalID and an optional NDataDecl. + */ + class ExternalIds + { + + /** + * The public ID. + */ + String publicId; + + /** + * The system ID. + */ + String systemId; + + /** + * The notation name declared with the NDATA keyword. + */ + String notationName; + } + + /** + * A content model. + */ + abstract class ContentModel + { + static final int EMPTY = 0; + static final int ANY = 1; + static final int ELEMENT = 2; + static final int MIXED = 3; + + int min; + int max; + final int type; + String text; + boolean external; + + ContentModel(int type) + { + this.type = type; + min = 1; + max = 1; + } + + } + + /** + * The EMPTY content model. + */ + class EmptyContentModel + extends ContentModel + { + + EmptyContentModel() + { + super(ContentModel.EMPTY); + min = 0; + max = 0; + } + + } + + /** + * The ANY content model. + */ + class AnyContentModel + extends ContentModel + { + + AnyContentModel() + { + super(ContentModel.ANY); + min = 0; + max = -1; + } + + } + + /** + * An element content model. + */ + class ElementContentModel + extends ContentModel + { + + LinkedList contentParticles; + boolean or; + String regex; // regular expression cache + + ElementContentModel() + { + super(ContentModel.ELEMENT); + contentParticles = new LinkedList(); + } + + void addContentParticle(ContentParticle cp) + { + contentParticles.add(cp); + } + + } + + class ContentParticle + { + + int min = 1; + int max = 1; + Object content; // Name (String) or ElementContentModel + + } + + /** + * A mixed content model. + */ + class MixedContentModel + extends ContentModel + { + + private HashSet names; + + MixedContentModel() + { + super(ContentModel.MIXED); + names = new HashSet(); + } + + void addName(String name) + { + names.add(name); + } + + boolean containsName(String name) + { + return names.contains(name); + } + + } + + /** + * An attribute definition. + */ + class AttributeDecl + { + + /** + * The attribute type (CDATA, ID, etc). + */ + final String type; + + /** + * The default value. + */ + final String value; + + /** + * The value type (#FIXED, #IMPLIED, etc). + */ + final int valueType; + + /** + * The enumeration text. + */ + final String enumeration; + + /** + * The enumeration tokens. + */ + final HashSet values; + + /** + * Whether this attribute declaration occurred in the external subset. + */ + final boolean external; + + AttributeDecl(String type, String value, + int valueType, String enumeration, + HashSet values, boolean external) + { + this.type = type; + this.value = value; + this.valueType = valueType; + this.enumeration = enumeration; + this.values = values; + this.external = external; + } + + } + + /** + * An XML input source. + */ + static class Input + implements Location + { + + int line = 1, markLine; + int column, markColumn; + int offset, markOffset; + final String publicId, systemId, name; + final boolean report; // report start- and end-entity + final boolean normalize; // normalize CR, etc to LF + + InputStream in; + Reader reader; + UnicodeReader unicodeReader; + boolean initialized; + boolean encodingDetected; + String inputEncoding; + boolean xml11; + + Input(InputStream in, Reader reader, String publicId, String systemId, + String name, String inputEncoding, boolean report, + boolean normalize) + { + if (inputEncoding == null) + inputEncoding = "UTF-8"; + this.inputEncoding = inputEncoding; + this.publicId = publicId; + this.systemId = systemId; + this.name = name; + this.report = report; + this.normalize = normalize; + if (in != null) + { + if (reader != null) + throw new IllegalStateException("both byte and char streams "+ + "specified"); + if (normalize) + in = new CRLFInputStream(in); + in = new BufferedInputStream(in); + this.in = in; + } + else + { + this.reader = normalize ? new CRLFReader(reader) : reader; + unicodeReader = new UnicodeReader(this.reader); + } + initialized = false; + } + + // -- Location -- + + public int getCharacterOffset() + { + return offset; + } + + public int getColumnNumber() + { + return column; + } + + public int getLineNumber() + { + return line; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + void init() + throws IOException + { + if (initialized) + return; + if (in != null) + detectEncoding(); + initialized = true; + } + + void mark(int len) + throws IOException + { + markOffset = offset; + markLine = line; + markColumn = column; + if (unicodeReader != null) + unicodeReader.mark(len); + else + in.mark(len); + } + + /** + * Character read. + */ + int read() + throws IOException + { + offset++; + int ret = (unicodeReader != null) ? unicodeReader.read() : in.read(); + if (normalize && + (ret == 0x0d || (xml11 && (ret == 0x85 || ret == 0x2028)))) + { + // Normalize CR etc to LF + ret = 0x0a; + } + // Locator handling + if (ret == 0x0a) + { + line++; + column = 0; + } + else + column++; + return ret; + } + + /** + * Block read. + */ + int read(int[] b, int off, int len) + throws IOException + { + int ret; + if (unicodeReader != null) + { + ret = unicodeReader.read(b, off, len); + } + else + { + byte[] b2 = new byte[len]; + ret = in.read(b2, 0, len); + if (ret != -1) + { + String s = new String(b2, 0, ret, inputEncoding); + int[] c = UnicodeReader.toCodePointArray(s); + ret = c.length; + System.arraycopy(c, 0, b, off, ret); + } + } + if (ret != -1) + { + // Locator handling + for (int i = 0; i < ret; i++) + { + int c = b[off + i]; + if (normalize && + (c == 0x0d || (xml11 && (c == 0x85 || c == 0x2028)))) + { + // Normalize CR etc to LF + c = 0x0a; + b[off + i] = c; + } + if (c == 0x0a) + { + line++; + column = 0; + } + else + column++; + } + } + return ret; + } + + void reset() + throws IOException + { + if (unicodeReader != null) + unicodeReader.reset(); + else + in.reset(); + offset = markOffset; + line = markLine; + column = markColumn; + } + + // Detection of input encoding + + private static final int[] SIGNATURE_UCS_4_1234 = + new int[] { 0x00, 0x00, 0x00, 0x3c }; + private static final int[] SIGNATURE_UCS_4_4321 = + new int[] { 0x3c, 0x00, 0x00, 0x00 }; + private static final int[] SIGNATURE_UCS_4_2143 = + new int[] { 0x00, 0x00, 0x3c, 0x00 }; + private static final int[] SIGNATURE_UCS_4_3412 = + new int[] { 0x00, 0x3c, 0x00, 0x00 }; + private static final int[] SIGNATURE_UCS_2_12 = + new int[] { 0xfe, 0xff }; + private static final int[] SIGNATURE_UCS_2_21 = + new int[] { 0xff, 0xfe }; + private static final int[] SIGNATURE_UCS_2_12_NOBOM = + new int[] { 0x00, 0x3c, 0x00, 0x3f }; + private static final int[] SIGNATURE_UCS_2_21_NOBOM = + new int[] { 0x3c, 0x00, 0x3f, 0x00 }; + private static final int[] SIGNATURE_UTF_8 = + new int[] { 0x3c, 0x3f, 0x78, 0x6d }; + private static final int[] SIGNATURE_UTF_8_BOM = + new int[] { 0xef, 0xbb, 0xbf }; + + /** + * Detect the input encoding. + */ + private void detectEncoding() + throws IOException + { + int[] signature = new int[4]; + in.mark(4); + for (int i = 0; i < 4; i++) + signature[i] = in.read(); + in.reset(); + + // 4-byte encodings + if (equals(SIGNATURE_UCS_4_1234, signature)) + { + in.read(); + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-32BE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_4_4321, signature)) + { + in.read(); + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-32LE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_4_2143, signature) || + equals(SIGNATURE_UCS_4_3412, signature)) + throw new UnsupportedEncodingException("unsupported UCS-4 byte ordering"); + + // 2-byte encodings + else if (equals(SIGNATURE_UCS_2_12, signature)) + { + in.read(); + in.read(); + setInputEncoding("UTF-16BE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_2_21, signature)) + { + in.read(); + in.read(); + setInputEncoding("UTF-16LE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_2_12_NOBOM, signature)) + { + //setInputEncoding("UTF-16BE"); + throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity"); + } + else if (equals(SIGNATURE_UCS_2_21_NOBOM, signature)) + { + //setInputEncoding("UTF-16LE"); + throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity"); + } + // ASCII-derived encodings + else if (equals(SIGNATURE_UTF_8, signature)) + { + // UTF-8 input encoding implied, TextDecl + } + else if (equals(SIGNATURE_UTF_8_BOM, signature)) + { + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-8"); + encodingDetected = true; + } + } + + private static boolean equals(int[] b1, int[] b2) + { + for (int i = 0; i < b1.length; i++) + { + if (b1[i] != b2[i]) + return false; + } + return true; + } + + void setInputEncoding(String encoding) + throws IOException + { + if (encoding.equals(inputEncoding)) + return; + if ("UTF-16".equalsIgnoreCase(encoding) && + inputEncoding.startsWith("UTF-16")) + return; + if (encodingDetected) + throw new UnsupportedEncodingException("document is not in its " + + "declared encoding " + + inputEncoding + + ": " + encoding); + inputEncoding = encoding; + finalizeEncoding(); + } + + void finalizeEncoding() + throws IOException + { + if (reader != null) + return; + reader = new BufferedReader(new InputStreamReader(in, inputEncoding)); + unicodeReader = new UnicodeReader(reader); + mark(1); + } + + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java new file mode 100644 index 000000000..83b8f7239 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java @@ -0,0 +1,1016 @@ +/* XMLStreamWriterImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.xml.sax.helpers.NamespaceSupport; + +/** + * Simple XML stream writer. + * + * @author Chris Burdess + */ +public class XMLStreamWriterImpl + implements XMLStreamWriter +{ + + /** + * The underlying character stream to write to. + */ + protected final Writer writer; + + /** + * The encoding being used. + * Note that this must match the encoding of the character stream. + */ + protected final String encoding; + + /** + * Whether prefix defaulting is being used. + * If true and a prefix has not been defined for a namespace specified on + * an element or an attribute, a new prefix and namespace declaration will + * be created. + */ + protected final boolean prefixDefaulting; + + /** + * The namespace context used to determine the namespace-prefix mappings + * in scope. + */ + protected NamespaceContext namespaceContext; + + /** + * The stack of elements in scope. + * Used to close the remaining elements. + */ + private LinkedList elements; + + /** + * Whether a start element has been opened but not yet closed. + */ + private boolean inStartElement; + + /** + * Whether we are in an empty element. + */ + private boolean emptyElement; + + private NamespaceSupport namespaces; + private int count = 0; + + private boolean xml11; + private boolean hasXML11RestrictedChars; + + /** + * Constructor. + * @see #writer + * @see #encoding + * @see #prefixDefaulting + */ + protected XMLStreamWriterImpl(Writer writer, String encoding, + boolean prefixDefaulting) + { + this.writer = writer; + this.encoding = encoding; + this.prefixDefaulting = prefixDefaulting; + elements = new LinkedList(); + namespaces = new NamespaceSupport(); + } + + /** + * Write the end of a start-element event. + * This will close the element if it was defined to be an empty element. + */ + private void endStartElement() + throws IOException + { + if (!inStartElement) + return; + if (emptyElement) + { + writer.write('/'); + elements.removeLast(); + namespaces.popContext(); + emptyElement = false; + } + writer.write('>'); + inStartElement = false; + } + + public void writeStartElement(String localName) + throws XMLStreamException + { + try + { + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + + endStartElement(); + namespaces.pushContext(); + + writer.write('<'); + writer.write(localName); + + elements.addLast(new String[] { null, localName }); + inStartElement = true; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeStartElement(String namespaceURI, String localName) + throws XMLStreamException + { + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + + endStartElement(); + namespaces.pushContext(); + + String prefix = getPrefix(namespaceURI); + boolean isDeclared = (prefix != null); + if (!isDeclared) + { + if (prefixDefaulting) + prefix = createPrefix(namespaceURI); + else + throw new XMLStreamException("namespace " + namespaceURI + + " has not been declared"); + } + writer.write('<'); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + inStartElement = true; + if (!isDeclared) + { + writeNamespaceImpl(prefix, namespaceURI); + } + + elements.addLast(new String[] { prefix, localName }); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + /** + * Creates a new unique prefix in the document. + * Subclasses may override this method to provide a suitably unique prefix + * for the given namespace. + * @param namespaceURI the namespace URI + */ + protected String createPrefix(String namespaceURI) + { + Set prefixes = new HashSet(); + for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); ) + prefixes.add(e.nextElement()); + String ret; + do + { + ret = "ns" + (count++); + } + while (prefixes.contains(ret)); + return ret; + } + + public void writeStartElement(String prefix, String localName, + String namespaceURI) + throws XMLStreamException + { + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isPrefix(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + if (!isNCName(localName)) + throw new IllegalArgumentException("illegal NCName: " + localName); + + endStartElement(); + namespaces.pushContext(); + + String currentPrefix = getPrefix(namespaceURI); + boolean isCurrent = prefix.equals(currentPrefix); + writer.write('<'); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + if (prefixDefaulting && !isCurrent) + { + writeNamespaceImpl(prefix, namespaceURI); + } + + elements.addLast(new String[] { prefix, localName }); + inStartElement = true; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEmptyElement(String namespaceURI, String localName) + throws XMLStreamException + { + writeStartElement(namespaceURI, localName); + emptyElement = true; + } + + public void writeEmptyElement(String prefix, String localName, + String namespaceURI) + throws XMLStreamException + { + writeStartElement(prefix, localName, namespaceURI); + emptyElement = true; + } + + public void writeEmptyElement(String localName) + throws XMLStreamException + { + writeStartElement(localName); + emptyElement = true; + } + + public void writeEndElement() + throws XMLStreamException + { + if (elements.isEmpty()) + throw new IllegalStateException("no matching start element"); + try + { + endStartElement(); + String[] element = (String[]) elements.removeLast(); + namespaces.popContext(); + + writer.write('<'); + writer.write('/'); + if (element[0] != null && !"".equals(element[0])) + { + writer.write(element[0]); + writer.write(':'); + } + writer.write(element[1]); + writer.write('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEndDocument() + throws XMLStreamException + { + while (!elements.isEmpty()) + writeEndElement(); + } + + public void close() + throws XMLStreamException + { + flush(); + } + + public void flush() + throws XMLStreamException + { + try + { + writer.flush(); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String localName, String value) + throws XMLStreamException + { + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + + writer.write(' '); + writer.write(localName); + writer.write('='); + writer.write('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String prefix, String namespaceURI, + String localName, String value) + throws XMLStreamException + { + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isPrefix(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + if (!isNCName(localName)) + throw new IllegalArgumentException("illegal NCName: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + + String currentPrefix = getPrefix(namespaceURI); + if (currentPrefix == null) + { + if (prefixDefaulting) + writeNamespaceImpl(prefix, namespaceURI); + else + throw new XMLStreamException("namespace " + namespaceURI + + " is not bound"); + } + else if (!currentPrefix.equals(prefix)) + throw new XMLStreamException("namespace " + namespaceURI + + " is bound to prefix " + + currentPrefix); + writer.write(' '); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + writer.write('='); + writer.write('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String namespaceURI, String localName, + String value) + throws XMLStreamException + { + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + + String prefix = getPrefix(namespaceURI); + if (prefix == null) + { + if (prefixDefaulting) + { + prefix = XMLConstants.DEFAULT_NS_PREFIX; + writeNamespaceImpl(prefix, namespaceURI); + } + else + throw new XMLStreamException("namespace " + namespaceURI + + " is not bound"); + } + writer.write(' '); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + writer.write('='); + writer.write('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeNamespace(String prefix, String namespaceURI) + throws XMLStreamException + { + if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix)) + { + writeDefaultNamespace(namespaceURI); + return; + } + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (!isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isPrefix(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + writeNamespaceImpl(prefix, namespaceURI); + } + + private void writeNamespaceImpl(String prefix, String namespaceURI) + throws XMLStreamException + { + try + { + if (prefix == null) + prefix = XMLConstants.DEFAULT_NS_PREFIX; + + setPrefix(prefix, namespaceURI); + + writer.write(' '); + writer.write("xmlns"); + if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) + { + writer.write(':'); + writer.write(prefix); + } + writer.write('='); + writer.write('"'); + writer.write(namespaceURI); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeDefaultNamespace(String namespaceURI) + throws XMLStreamException + { + if (!inStartElement) + throw new IllegalStateException(); + if (!isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + writeNamespaceImpl(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI); + } + + public void writeComment(String data) + throws XMLStreamException + { + if (data == null) + return; + try + { + if (!isChars(data)) + throw new IllegalArgumentException("illegal XML character: " + data); + if (data.indexOf("--") != -1) + throw new IllegalArgumentException("illegal comment: " + data); + + endStartElement(); + + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeProcessingInstruction(String target) + throws XMLStreamException + { + writeProcessingInstruction(target, null); + } + + public void writeProcessingInstruction(String target, String data) + throws XMLStreamException + { + try + { + if (!isName(target) || "xml".equalsIgnoreCase(target)) + throw new IllegalArgumentException("illegal PITarget: " + target); + if (data != null && !isChars(data)) + throw new IllegalArgumentException("illegal XML character: " + data); + + endStartElement(); + + writer.write('<'); + writer.write('?'); + writer.write(target); + if (data != null) + { + writer.write(' '); + if (hasXML11RestrictedChars) + { + int[] seq = UnicodeReader.toCodePointArray(data); + for (int i = 0; i < seq.length; i++) + { + int c = seq[i]; + if (XMLParser.isXML11RestrictedChar(c)) + writer.write("&#x" + Integer.toHexString(c) + ";"); + else + writer.write(Character.toChars(i)); + } + } + else + writer.write(data); + } + writer.write('?'); + writer.write('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCData(String data) + throws XMLStreamException + { + try + { + if (!isChars(data) || hasXML11RestrictedChars) + throw new IllegalArgumentException("illegal XML character: " + data); + if (data.indexOf("]]") != -1) + throw new IllegalArgumentException("illegal CDATA section: " + data); + + endStartElement(); + + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeDTD(String dtd) + throws XMLStreamException + { + try + { + // XXX: Should we parse the doctypedecl at this point to ensure + // wellformedness? + writer.write("'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEntityRef(String name) + throws XMLStreamException + { + try + { + if (!isName(name)) + throw new IllegalArgumentException("illegal Name: " + name); + + endStartElement(); + + writer.write('&'); + writer.write(name); + writer.write(';'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeStartDocument() + throws XMLStreamException + { + writeStartDocument(null, null); + } + + public void writeStartDocument(String version) + throws XMLStreamException + { + writeStartDocument(null, version); + } + + public void writeStartDocument(String encoding, String version) + throws XMLStreamException + { + if (version == null) + version = "1.0"; + else if ("1.1".equals(version)) + xml11 = true; + encoding = this.encoding; // YES: the parameter must be ignored + if (encoding == null) + encoding = "UTF-8"; + if (!"1.0".equals(version) && !"1.1".equals(version)) + throw new IllegalArgumentException(version); + try + { + writer.write(""); + writer.write(System.getProperty("line.separator")); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCharacters(String text) + throws XMLStreamException + { + if (text == null) + return; + try + { + if (!isChars(text)) + throw new IllegalArgumentException("illegal XML character: " + text); + + endStartElement(); + + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(text, false); + else + writeEncoded(text, false); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCharacters(char[] text, int start, int len) + throws XMLStreamException + { + writeCharacters(new String(text, start, len)); + } + + public String getPrefix(String uri) + throws XMLStreamException + { + String prefix = namespaces.getPrefix(uri); + if (prefix == null && namespaceContext != null) + prefix = namespaceContext.getPrefix(uri); + return prefix; + } + + public void setPrefix(String prefix, String uri) + throws XMLStreamException + { + try + { + if (!isURI(uri)) + throw new IllegalArgumentException("illegal URI: " + uri); + if (!isPrefix(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + if (!namespaces.declarePrefix(prefix, uri)) + throw new XMLStreamException("illegal prefix " + prefix); + } + + public void setDefaultNamespace(String uri) + throws XMLStreamException + { + if (!isURI(uri)) + throw new IllegalArgumentException("illegal URI: " + uri); + if (!namespaces.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri)) + throw new XMLStreamException("illegal default namespace prefix"); + } + + public void setNamespaceContext(NamespaceContext context) + throws XMLStreamException + { + namespaceContext = context; + } + + public NamespaceContext getNamespaceContext() + { + return namespaceContext; + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + throw new IllegalArgumentException(name); + } + + /** + * Write the specified text, ensuring that the content is suitably encoded + * for XML. + * @param text the text to write + * @param inAttr whether we are in an attribute value + */ + private void writeEncoded(String text, boolean inAttr) + throws IOException + { + char[] chars = text.toCharArray(); + int start = 0; + int end = chars.length; + int len = 0; + for (int i = start; i < end; i++) + { + char c = chars[i]; + if (c == '<' || c == '>' || c == '&') + { + writer.write(chars, start, len); + if (c == '<') + writer.write("<"); + else if (c == '>') + writer.write(">"); + else + writer.write("&"); + start = i + 1; + len = 0; + } + else if (inAttr && (c == '"' || c == '\'')) + { + writer.write(chars, start, len); + if (c == '"') + writer.write("""); + else + writer.write("'"); + start = i + 1; + len = 0; + } + else + len++; + } + if (len > 0) + writer.write(chars, start, len); + } + + /** + * Writes the specified text, in the knowledge that some of the + * characters are XML 1.1 restricted characters. + */ + private void writeEncodedWithRestrictedChars(String text, boolean inAttr) + throws IOException + { + int[] seq = UnicodeReader.toCodePointArray(text); + for (int i = 0; i < seq.length; i++) + { + int c = seq[i]; + switch (c) + { + case 0x3c: // '<' + writer.write("<"); + break; + case 0x3e: // '>' + writer.write(">"); + break; + case 0x26: // '&' + writer.write("&"); + break; + case 0x22: // '"' + if (inAttr) + writer.write("""); + else + writer.write(c); + break; + case 0x27: // '\'' + if (inAttr) + writer.write("'"); + else + writer.write(c); + break; + default: + if (XMLParser.isXML11RestrictedChar(c)) + writer.write("&#x" + Integer.toHexString(c) + ";"); + else + { + char[] chars = Character.toChars(c); + writer.write(chars, 0, chars.length); + } + } + } + } + + private boolean isName(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + if (seq.length < 1) + return false; + if (!XMLParser.isNameStartCharacter(seq[0], xml11)) + return false; + for (int i = 1; i < seq.length; i++) + { + if (!XMLParser.isNameCharacter(seq[i], xml11)) + return false; + } + return true; + } + + private boolean isPrefix(String text) + throws IOException + { + if (XMLConstants.DEFAULT_NS_PREFIX.equals(text)) { + return true; + } + return isNCName(text); + } + + private boolean isNCName(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + if (seq.length < 1) + return false; + if (!XMLParser.isNameStartCharacter(seq[0], xml11) || seq[0] == 0x3a) + return false; + for (int i = 1; i < seq.length; i++) + { + if (!XMLParser.isNameCharacter(seq[i], xml11) || seq[i] == 0x3a) + return false; + } + return true; + } + + private boolean isChars(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + hasXML11RestrictedChars = false; + if (xml11) + { + for (int i = 0; i < seq.length; i++) + { + if (!XMLParser.isXML11Char(seq[i])) + return false; + if (XMLParser.isXML11RestrictedChar(seq[i])) + hasXML11RestrictedChars = true; + } + } + else + { + for (int i = 0; i < seq.length; i++) + { + if (!XMLParser.isChar(seq[i])) + return false; + } + } + return true; + } + + private boolean isURI(String text) + { + if (text == null) + return false; + char[] chars = text.toCharArray(); + if (chars.length < 1) + return false; + for (int i = 0; i < chars.length; i++) + { + if (chars[i] < 0x20 || chars[i] >= 0x7f) + return false; + } + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java new file mode 100644 index 000000000..6e478bdc4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java @@ -0,0 +1,330 @@ +/* AbstractNumberNode.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL number instruction. + * + * @author Chris Burdess + */ +abstract class AbstractNumberNode + extends TemplateNode +{ + + static final int ALPHABETIC = 0; + static final int TRADITIONAL = 1; + + final TemplateNode format; + final String lang; + final int letterValue; + final String groupingSeparator; + final int groupingSize; + + AbstractNumberNode(TemplateNode format, String lang, + int letterValue, String groupingSeparator, + int groupingSize) + { + this.format = format; + this.lang = lang; + this.letterValue = letterValue; + this.groupingSeparator = groupingSeparator; + this.groupingSize = groupingSize; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + format.apply(stylesheet, mode, context, pos, len, fragment, null); + String f = Expr._string(context, Collections.singleton(fragment)); + String value = format(f, compute(stylesheet, context, pos, len)); + Text text = doc.createTextNode(value); + if (nextSibling != null) + { + parent.insertBefore(text, nextSibling); + } + else + { + parent.appendChild(text); + } + // xsl:number doesn't process children + if (next != null) + { + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + } + + String format(String format, int[] number) + { + if (number.length == 0) + { + return ""; + } + int start = 0, end = 0, len = format.length(); // region of format + // Tokenize + List tokens = new ArrayList((number.length * 2) + 1); + List types = new ArrayList(tokens.size()); + while (end < len) + { + while (end < len && !isAlphanumeric(format.charAt(end))) + { + end++; + } + if (end > start) + { + tokens.add(format.substring(start, end)); + types.add(Boolean.FALSE); + } + start = end; + while (end < len && isAlphanumeric(format.charAt(end))) + { + end++; + } + if (end > start) + { + tokens.add(format.substring(start, end)); + types.add(Boolean.TRUE); + } + start = end; + } + // Process tokens + CPStringBuilder buf = new CPStringBuilder(); + len = tokens.size(); + int pos = 0; + for (int i = 0; i < len; i++) + { + String token = (i < 0) ? "." : (String) tokens.get(i); + boolean alpha = (i < 0) ? true : + ((Boolean) types.get(i)).booleanValue(); + if (!alpha) + { + buf.append(token); + } + else + { + if (pos < number.length) + { + format(buf, number[pos++], token); + if (((i + 1 == len) || (i + 2 == len)) && + (pos < number.length)) + { + // More numbers than tokens, reuse last token + i -= 2; + } + } + if (pos == number.length && i < (len - 2)) + { + // No more numbers. Skip to the end... + i = len - 2; + if (((Boolean) types.get(i + 1)).booleanValue()) + { + // number formatting token, ignore + i++; + } + } + } + } + //System.err.println("format: '"+format+"' "+asList(number)+" = '"+buf.toString()+"'"); + return buf.toString(); + } + + /*List asList(int[] number) + { + List l = new ArrayList(); + for (int i = 0; i < number.length; i++) + l.add(new Integer(number[i])); + return l; + }*/ + + void format(CPStringBuilder buf, int number, String formatToken) + { + int len = formatToken.length(); + char c = formatToken.charAt(len - 1); + if (Character.digit(c, 10) == 1) + { + // Check preceding characters + for (int i = len - 2; i >= 0; i--) + { + if (formatToken.charAt(i) != (c - 1)) + { + format(buf, number, "1"); + return; + } + } + // Decimal representation + String val = Integer.toString(number); + for (int d = len - val.length(); d > 0; d--) + { + buf.append('0'); + } + buf.append(val); + } + else if ("A".equals(formatToken)) + { + buf.append(alphabetic('@', number)); + } + else if ("a".equals(formatToken)) + { + buf.append(alphabetic('`', number)); + } + else if ("i".equals(formatToken)) + { + buf.append(roman(false, number)); + } + else if ("I".equals(formatToken)) + { + buf.append(roman(true, number)); + } + else + { + // Unknown numbering sequence + format(buf, number, "1"); + } + } + + static final boolean isAlphanumeric(char c) + { + switch (Character.getType(c)) + { + case Character.DECIMAL_DIGIT_NUMBER: // Nd + case Character.LETTER_NUMBER: // Nl + case Character.OTHER_NUMBER: // No + case Character.UPPERCASE_LETTER: // Lu + case Character.LOWERCASE_LETTER: // Ll + case Character.TITLECASE_LETTER: // Lt + case Character.MODIFIER_LETTER: // Lm + case Character.OTHER_LETTER: // Lo + return true; + default: + return false; + } + } + + static final String alphabetic(char offset, int number) + { + CPStringBuilder buf = new CPStringBuilder(); + while (number > 0) + { + int r = number % 26; + number = number / 26; + buf.insert(0, (char) (offset + r)); + } + return buf.toString(); + } + + static final int[] roman_numbers = {1, 5, 10, 50, 100, 500, 1000}; + static final char[] roman_chars = {'i', 'v', 'x', 'l', 'c', 'd', 'm'}; + + static final String roman(boolean upper, int number) + { + CPStringBuilder buf = new CPStringBuilder(); + for (int pos = roman_numbers.length - 1; pos >= 0; pos -= 2) + { + int f = number / roman_numbers[pos]; + if (f != 0) + { + number = number % (f * roman_numbers[pos]); + } + if (f > 4 && f < 9) + { + buf.append(roman_chars[pos + 1]); + f -= 5; + } + if (f == 4) + { + buf.append(roman_chars[pos]); + buf.append(roman_chars[pos + 1]); + } + else if (f == 9) + { + buf.append(roman_chars[pos]); + buf.append(roman_chars[pos + 2]); + } + else + { + for (; f > 0; f--) + { + buf.append(roman_chars[pos]); + } + } + } + return upper ? buf.toString().toUpperCase() : buf.toString(); + } + + abstract int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException; + + public boolean references(QName var) + { + if (format.references(var)) + { + return true; + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("number"); + buf.append('['); + buf.append("format="); + buf.append(format); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java new file mode 100644 index 000000000..298c49da4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java @@ -0,0 +1,82 @@ +/* ApplyImportsNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSLT apply-imports instruction. + * + * @author Chris Burdess + */ +final class ApplyImportsNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ApplyImportsNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + TemplateNode t = stylesheet.getTemplate(mode, context, true); + if (t != null) + t.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "apply-imports"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java new file mode 100644 index 000000000..6aa36954a --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java @@ -0,0 +1,219 @@ +/* ApplyTemplatesNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL apply-templates + * instruction. + * + * @author Chris Burdess + */ +final class ApplyTemplatesNode + extends TemplateNode +{ + + final Expr select; + final QName mode; + final List sortKeys; + final List withParams; + final boolean isDefault; + + ApplyTemplatesNode(Expr select, QName mode, + List sortKeys, List withParams, boolean isDefault) + { + this.select = select; + this.mode = mode; + this.sortKeys = sortKeys; + this.withParams = withParams; + this.isDefault = isDefault; + } + + TemplateNode clone(Stylesheet stylesheet) + { + int len = sortKeys != null ? sortKeys.size() : 0; + List sortKeys2 = new ArrayList(len); + for (int i = 0; i < len; i++) + sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet)); + len = withParams != null ? withParams.size() : 0; + List withParams2 = new ArrayList(len); + for (int i = 0; i < len; i++) + withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); + TemplateNode ret = new ApplyTemplatesNode(select.clone(stylesheet), + mode, sortKeys2, withParams2, + isDefault); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = select.evaluate(context, pos, len); + if (ret != null && ret instanceof Collection) + { + if (withParams != null) + { + // compute the parameter values + LinkedList values = new LinkedList(); + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + WithParam p = (WithParam) i.next(); + Object value = p.getValue(stylesheet, mode, context, pos, len); + Object[] pair = new Object[2]; + pair[0] = p.name; + pair[1] = value; + values.add(pair); + } + // push the parameter context + stylesheet.bindings.push(Bindings.WITH_PARAM); + // set the parameters + for (Iterator i = values.iterator(); i.hasNext(); ) + { + Object[] pair = (Object[]) i.next(); + QName name = (QName) pair[0]; + Object value = pair[1]; + stylesheet.bindings.set(name, value, Bindings.WITH_PARAM); + } + } + Collection ns = (Collection) ret; + List nodes = new ArrayList(ns); + if (sortKeys != null) + { + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + SortKey sortKey = (SortKey) i.next(); + sortKey.init(stylesheet, mode, context, pos, len, parent, + nextSibling); + } + Collections.sort(nodes, new XSLComparator(sortKeys)); + } + else + Collections.sort(nodes, documentOrderComparator); + int l = nodes.size(); + QName effectiveMode = isDefault ? mode : this.mode; + for (int i = 0; i < l; i++) + { + Node node = (Node) nodes.get(i); + TemplateNode t = stylesheet.getTemplate(effectiveMode, node, + false); + if (t != null) + { + stylesheet.current = node; + t.apply(stylesheet, effectiveMode, node, i + 1, l, + parent, nextSibling); + } + } + if (withParams != null) + { + // pop the variable context + stylesheet.bindings.pop(Bindings.WITH_PARAM); + } + } + // apply-templates doesn't have processable children + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + if (withParams != null) + { + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + if (((WithParam) i.next()).references(var)) + return true; + } + } + if (sortKeys != null) + { + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + if (((SortKey) i.next()).references(var)) + return true; + } + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("apply-templates"); + buf.append('['); + boolean o = false; + if (select != null) + { + buf.append("select="); + buf.append(select); + o = true; + } + if (mode != null) + { + if (o) + { + buf.append(','); + } + buf.append("mode="); + buf.append(mode); + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/AttributeNode.java b/libjava/classpath/gnu/xml/transform/AttributeNode.java new file mode 100644 index 000000000..4c71f6a92 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AttributeNode.java @@ -0,0 +1,244 @@ +/* AttributeNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL attribute instruction. + * + * @author Chris Burdess + */ +final class AttributeNode + extends TemplateNode +{ + + final TemplateNode name; + final TemplateNode namespace; + final Node source; + + AttributeNode(TemplateNode name, + TemplateNode namespace, Node source) + { + this.name = name; + this.namespace = namespace; + this.source = source; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new AttributeNode(name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + // Create a document fragment to hold the name + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply name to the fragment + name.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + String nameValue = Expr.stringValue(fragment); + + String namespaceValue = null; + if (namespace != null) + { + // Create a document fragment to hold the namespace + fragment = doc.createDocumentFragment(); + // Apply namespace to the fragment + namespace.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + namespaceValue = Expr.stringValue(fragment); + if (namespaceValue.length() == 0) + namespaceValue = null; + } + + String prefix = getPrefix(nameValue); + if (namespaceValue == null) + { + if (prefix != null) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + namespaceValue = XMLConstants.XML_NS_URI; + else + { + // Resolve namespace for this prefix + namespaceValue = source.lookupNamespaceURI(prefix); + } + } + } + else + { + if (prefix != null) + { + String ns2 = source.lookupNamespaceURI(prefix); + if (ns2 != null && !ns2.equals(namespaceValue)) + { + // prefix clashes, reset it + prefix = null; + int ci = nameValue.indexOf(':'); + nameValue = nameValue.substring(ci + 1); + } + } + } + if (prefix == null) + { + // Resolve prefix for this namespace + prefix = source.lookupPrefix(namespaceValue); + if (prefix != null) + nameValue = prefix + ":" + nameValue; + else + { + if (namespaceValue != null) + { + // Must invent a prefix + prefix = inventPrefix(parent); + nameValue = prefix + ":" + nameValue; + } + } + } + NamedNodeMap attrs = parent.getAttributes(); + boolean insert = true; + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceValue) || + XMLConstants.XMLNS_ATTRIBUTE.equals(nameValue) || + nameValue.startsWith("xmlns:")) + { + // Namespace declaration, do not output + insert = false; + } + if (prefix != null && namespaceValue == null) + { + // Not a QName + insert = false; + } + if (parent.getNodeType() == Node.ELEMENT_NODE && + parent.getFirstChild() != null) + { + // XSLT 7.1.3 Adding an attribute to an element after children have + // been added to it is an error + insert = false; + } + if (insert) + { + // Insert attribute + Attr attr = (namespaceValue != null) ? + doc.createAttributeNS(namespaceValue, nameValue) : + doc.createAttribute(nameValue); + if (attrs != null) + { + if (namespace != null) + attrs.setNamedItemNS(attr); + else + attrs.setNamedItem(attr); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + attr, null); + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + final String getPrefix(String name) + { + int ci = name.indexOf(':'); + return (ci == -1) ? null : name.substring(0, ci); + } + + final String inventPrefix(Node parent) + { + String base = "ns"; + int count = 0; + String ret = base + Integer.toString(count); + while (parent.lookupNamespaceURI(ret) != null) + { + count++; + ret = base + Integer.toString(count); + } + return ret; + } + + public boolean references(QName var) + { + if (name != null && name.references(var)) + return true; + if (namespace != null && namespace.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("attribute"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/AttributeSet.java b/libjava/classpath/gnu/xml/transform/AttributeSet.java new file mode 100644 index 000000000..ced50f11c --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AttributeSet.java @@ -0,0 +1,66 @@ +/* AttributeSet.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +/** + * An attribute-set entry in a stylesheet. + * + * @author Chris Burdess + */ +final class AttributeSet +{ + + final TemplateNode children; + final String name; + final String uas; + + AttributeSet(TemplateNode children, String name, String uas) + { + this.children = children; + this.name = name; + this.uas = uas; + } + + AttributeSet clone(Stylesheet stylesheet) + { + return new AttributeSet((children == null) ? null : + children.clone(stylesheet), + name, uas); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Bindings.java b/libjava/classpath/gnu/xml/transform/Bindings.java new file mode 100644 index 000000000..37d45880c --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Bindings.java @@ -0,0 +1,346 @@ +/* Bindings.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Node; + +/** + * The set of variable bindings in effect for a stylesheet. + * + * @author Chris Burdess + */ +public class Bindings + implements XPathVariableResolver, Cloneable +{ + + static final int VARIABLE = 0; + static final int PARAM = 1; + static final int WITH_PARAM = 2; + + final Stylesheet stylesheet; + + /** + * Global variables. + */ + final LinkedList> variables; + + /** + * Parameter value stack. + */ + final LinkedList> parameters; + + /** + * Argument (with-param) value stack. + */ + final LinkedList> withParameters; + + /** + * Only search globals. + */ + boolean global; + + Bindings(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + variables = new LinkedList>(); + parameters = new LinkedList>(); + withParameters = new LinkedList>(); + for (int i = 0; i < 3; i++) + { + push(i); + } + } + + public Object clone() + { + try + { + return (Bindings) super.clone(); + } + catch (CloneNotSupportedException e) + { + throw new Error(e.getMessage()); + } + } + + void push(int type) + { + switch (type) + { + case VARIABLE: + variables.addFirst(new HashMap()); + break; + case PARAM: + parameters.addFirst(new HashMap()); + break; + case WITH_PARAM: + withParameters.addFirst(new HashMap()); + break; + } + } + + void pop(int type) + { + switch (type) + { + case VARIABLE: + variables.removeFirst(); + break; + case PARAM: + parameters.removeFirst(); + break; + case WITH_PARAM: + withParameters.removeFirst(); + break; + } + } + + public boolean containsKey(QName name, int type) + { + if (global) + { + Map ctx1 = variables.getLast(); + Map ctx2 = parameters.getLast(); + return (ctx1.containsKey(name) || ctx2.containsKey(name)); + } + Iterator> i = null; + switch (type) + { + case VARIABLE: + i = variables.iterator(); + break; + case PARAM: + i = parameters.iterator(); + break; + case WITH_PARAM: + Map ctx = withParameters.getFirst(); + return ctx.containsKey(name); + } + if (i != null) + { + while (i.hasNext()) + { + Map ctx = i.next(); + if (ctx.containsKey(name)) + { + return true; + } + } + } + return false; + } + + public Object get(QName name, Node context, int pos, int len) + { + if (global) + { + Map ctx = variables.getLast(); + Object ret = ctx.get(name); + if (ret == null) + { + ctx = parameters.getLast(); + ret = ctx.get(name); + } + return ret; + } + //System.err.println("bindings.get: "+name); + //System.err.println("\t"+toString()); + Object ret = null; + //if (parameters.size() > 1 && containsKey(name, PARAM)) + // check that template defines parameter + { + Map cwp = withParameters.getFirst(); + ret = cwp.get(name); + //System.err.println("\twith-param: ret="+ret); + } + if (ret == null) + { + for (Iterator> i = variables.iterator(); + i.hasNext() && ret == null; ) + { + Map vctx = i.next(); + ret = vctx.get(name); + } + //System.err.println("\tvariable: ret="+ret); + } + if (ret == null) + { + for (Iterator> i = parameters.iterator(); + i.hasNext() && ret == null; ) + { + Map pctx = i.next(); + ret = pctx.get(name); + } + //System.err.println("\tparam: ret="+ret); + } + /*if (ret instanceof Expr && context != null) + { + Expr expr = (Expr) ret; + ret = expr.evaluate(context, 1, 1); + }*/ + if (ret instanceof Node) + { + ret = Collections.singleton(ret); + } + if (ret == null) + { + ret = ""; + } + //System.err.println("\tret="+ret); + return ret; + } + + void set(QName name, Object value, int type) + { + switch (type) + { + case VARIABLE: + Map vctx = variables.getFirst(); + vctx.put(name, value); + break; + case PARAM: + Map pctx = parameters.getFirst(); + pctx.put(name, value); + break; + case WITH_PARAM: + Map wctx = withParameters.getFirst(); + wctx.put(name, value); + break; + } + //System.err.println("Set "+name+"="+value); + } + + public Object resolveVariable(QName qName) + { + return get(qName, null, 1, 1); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + boolean next = false; + Collection seen = new HashSet(); + Map wctx = withParameters.getFirst(); + buf.append('('); + for (Map.Entry entry : wctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + buf.append(')'); + next = false; + seen.clear(); + buf.append('{'); + for (Map ctx : variables) + { + for (Map.Entry entry : ctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + } + buf.append('}'); + next = false; + seen.clear(); + buf.append('['); + for (Map ctx : parameters) + { + for (Map.Entry entry : ctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CallTemplateNode.java b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java new file mode 100644 index 000000000..cc08d93e3 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java @@ -0,0 +1,156 @@ +/* CallTemplateNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing the XSL call-template + * instruction. + * + * @author Chris Burdess + */ +final class CallTemplateNode + extends TemplateNode +{ + + final QName name; + final List withParams; + + CallTemplateNode(QName name, List withParams) + { + this.name = name; + this.withParams = withParams; + } + + TemplateNode clone(Stylesheet stylesheet) + { + int len = withParams.size(); + List withParams2 = new ArrayList(len); + for (int i = 0; i < len; i++) + withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); + TemplateNode ret = new CallTemplateNode(name, withParams2); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + TemplateNode t = stylesheet.getTemplate(mode, name); + if (t != null) + { + if (!withParams.isEmpty()) + { + // compute the parameter values + LinkedList values = new LinkedList(); + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + WithParam p = (WithParam) i.next(); + if (t.hasParam(p.name)) // ignore parameters not specified + { + Object value = p.getValue(stylesheet, mode, context, + pos, len); + Object[] pair = new Object[2]; + pair[0] = p.name; + pair[1] = value; + values.add(pair); + } + } + // push the parameter context + stylesheet.bindings.push(Bindings.WITH_PARAM); + // set the parameters + for (Iterator i = values.iterator(); i.hasNext(); ) + { + Object[] pair = (Object[]) i.next(); + QName name = (QName) pair[0]; + Object value = pair[1]; + stylesheet.bindings.set(name, value, Bindings.WITH_PARAM); + if (stylesheet.debug) + System.err.println("with-param: " + name + " = " + value); + } + } + t.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + if (!withParams.isEmpty()) + { + // pop the variable context + stylesheet.bindings.pop(Bindings.WITH_PARAM); + } + } + // call-template doesn't have processable children + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + if (((WithParam) i.next()).references(var)) + return true; + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("call-template"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ChooseNode.java b/libjava/classpath/gnu/xml/transform/ChooseNode.java new file mode 100644 index 000000000..262cde144 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ChooseNode.java @@ -0,0 +1,88 @@ +/* ChooseNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSL choose instruction. + * + * @author Chris Burdess + */ +final class ChooseNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ChooseNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("choose"); + buf.append('['); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CommentNode.java b/libjava/classpath/gnu/xml/transform/CommentNode.java new file mode 100644 index 000000000..1c14e5fa8 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CommentNode.java @@ -0,0 +1,103 @@ +/* CommentNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL comment instruction. + * + * @author Chris Burdess + */ +final class CommentNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CommentNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + String value = ""; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (children != null) + { + // Create a document fragment to hold the text + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply children to the fragment + children.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + value = Expr.stringValue(fragment); + } + Comment comment = doc.createComment(value); + // Insert into result tree + if (nextSibling != null) + parent.insertBefore(comment, nextSibling); + else + parent.appendChild(comment); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "comment"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CopyNode.java b/libjava/classpath/gnu/xml/transform/CopyNode.java new file mode 100644 index 000000000..9cc2fdecd --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CopyNode.java @@ -0,0 +1,168 @@ +/* CopyNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Iterator; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A template node representing the XSL copy instruction. + * + * @author Chris Burdess + */ +final class CopyNode + extends TemplateNode +{ + + final String uas; + + CopyNode(String uas) + { + this.uas = uas; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CopyNode(uas); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Node copy = parent; + switch (context.getNodeType()) + { + case Node.TEXT_NODE: + case Node.ATTRIBUTE_NODE: + case Node.ELEMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + case Node.COMMENT_NODE: + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + copy = context.cloneNode(false); + copy = doc.adoptNode(copy); + if (copy.getNodeType() == Node.ATTRIBUTE_NODE) + { + if (parent.getFirstChild() != null) + { + // Ignore attempt to add attribute after children + } + else + { + NamedNodeMap attrs = parent.getAttributes(); + if (attrs != null) + attrs.setNamedItemNS(copy); + } + } + else + { + if (nextSibling != null) + parent.insertBefore(copy, nextSibling); + else + parent.appendChild(copy); + } + } + if (uas != null) + { + StringTokenizer st = new StringTokenizer(uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + copy, null, st.nextToken()); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + copy, null); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + void addAttributeSet(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling, String attributeSet) + throws TransformerException + { + for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); ) + { + AttributeSet as = (AttributeSet) i.next(); + if (!as.name.equals(attributeSet)) + continue; + if (as.uas != null) + { + StringTokenizer st = new StringTokenizer(as.uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + parent, nextSibling, st.nextToken()); + } + if (as.children != null) + as.children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("copy"); + if (uas != null) + { + buf.append('['); + buf.append("uas="); + buf.append(uas); + buf.append(']'); + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CopyOfNode.java b/libjava/classpath/gnu/xml/transform/CopyOfNode.java new file mode 100644 index 000000000..2b06fed4d --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CopyOfNode.java @@ -0,0 +1,174 @@ +/* CopyOfNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSLT copy-of instruction. + * + * @author Chris Burdess + */ +final class CopyOfNode + extends TemplateNode +{ + + final Expr select; + + CopyOfNode(Expr select) + { + this.select = select; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CopyOfNode(select.clone(stylesheet)); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = select.evaluate(context, pos, len); + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (ret instanceof Collection) + { + Collection ns = (Collection) ret; + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + for (Iterator i = list.iterator(); i.hasNext(); ) + { + Node src = (Node) i.next(); + short nodeType = src.getNodeType(); + if (nodeType == Node.DOCUMENT_NODE) + { + // Use document element + src = ((Document) src).getDocumentElement(); + if (src == null) + continue; + nodeType = Node.ELEMENT_NODE; + } + else if (nodeType == Node.ATTRIBUTE_NODE) + { + if (parent.getFirstChild() != null) + { + // Ignore attempt to add attribute after children + continue; + } + } + if (parent.getNodeType() == Node.ATTRIBUTE_NODE && + nodeType != Node.TEXT_NODE && + nodeType != Node.ENTITY_REFERENCE_NODE) + { + // Ignore + continue; + } + Node node = src.cloneNode(true); + node = doc.adoptNode(node); + if (nodeType == Node.ATTRIBUTE_NODE) + { + NamedNodeMap attrs = parent.getAttributes(); + if (attrs != null) + attrs.setNamedItemNS(node); + } + else + { + if (nextSibling != null) + parent.insertBefore(node, nextSibling); + else + parent.appendChild(node); + } + } + } + else + { + String value = Expr._string(context, ret); + if (value != null && value.length() > 0) + { + Text textNode = doc.createTextNode(value); + if (nextSibling != null) + parent.insertBefore(textNode, nextSibling); + else + parent.appendChild(textNode); + } + } + // copy-of doesn't process children + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("copy-of"); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CurrentFunction.java b/libjava/classpath/gnu/xml/transform/CurrentFunction.java new file mode 100644 index 000000000..96899679a --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CurrentFunction.java @@ -0,0 +1,103 @@ +/* CurrentFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT current()function. + * + * @author Chris Burdess + */ +final class CurrentFunction + extends Expr + implements Function, XPathFunction +{ + + final Stylesheet stylesheet; + + CurrentFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // We can't do anything useful here. + // So much for the JAXP API... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + } + + public Object evaluate(Node context, int pos, int len) + { + return Collections.singleton(stylesheet.current); + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + return new CurrentFunction(s); + } + + public boolean references(QName var) + { + return false; + } + + public String toString() + { + return "current()"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java new file mode 100644 index 000000000..fbf31de55 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java @@ -0,0 +1,84 @@ +/* DOMSourceLocator.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.transform.dom.DOMLocator; +import org.w3c.dom.Node; + +/** + * Simple DOMLocator implementation. + * + * @author Chris Burdess + */ +class DOMSourceLocator + implements DOMLocator +{ + + final Node node; + + DOMSourceLocator(Node node) + { + this.node = node; + } + + public Node getOriginatingNode() + { + return node; + } + + public String getPublicId() + { + return null; + } + + public String getSystemId() + { + return null; + } + + public int getLineNumber() + { + return -1; + } + + public int getColumnNumber() + { + return -1; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/DocumentFunction.java b/libjava/classpath/gnu/xml/transform/DocumentFunction.java new file mode 100644 index 000000000..d0aee25b3 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/DocumentFunction.java @@ -0,0 +1,244 @@ +/* DocumentFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Constant; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; +import gnu.xml.xpath.IdFunction; + +/** + * The XSLT document()function. + * + * @author Chris Burdess + */ +final class DocumentFunction + extends Expr + implements Function, XPathFunction +{ + + final Stylesheet stylesheet; + final Node base; + List args; + List values; + + DocumentFunction(Stylesheet stylesheet, Node base) + { + this.stylesheet = stylesheet; + this.base = base; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + values = args; + return evaluate(null, 1, 1); + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + if (values == null) + { + values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + } + Object ret; + switch (arity) + { + case 1: + Object arg = values.get(0); + if (arg instanceof Collection) + { + Collection ns = (Collection) arg; + Collection acc = new TreeSet(); + for (Iterator i = ns.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + String s = Expr.stringValue(node); + acc.addAll(document(s, node.getBaseURI())); + } + ret = acc; + } + else + { + String s = Expr._string(context, arg); + ret = document(s, base.getBaseURI()); + } + break; + case 2: + Object arg1 = values.get(0); + Object arg2 = values.get(1); + if (!(arg2 instanceof Collection)) + throw new RuntimeException("second argument is not a node-set"); + Collection arg2ns = (Collection) arg2; + String base2 = arg2ns.isEmpty() ? null : + ((Node) arg2ns.iterator().next()).getBaseURI(); + if (arg1 instanceof Collection) + { + Collection arg1ns = (Collection) arg1; + Collection acc = new TreeSet(); + for (Iterator i = arg1ns.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + String s = Expr.stringValue(node); + acc.addAll(document(s, base2)); + } + ret = acc; + } + else + { + String s = Expr._string(context, arg1); + ret = document(s, base2); + } + break; + default: + throw new RuntimeException("invalid arity"); + } + values = null; + return ret; + } + + /** + * The XSL document function. + * @see XSLT 12.1 + * @param uri the URI from which to retrieve nodes + * @param base the base URI for relative URIs + */ + Collection document(String uri, String base) + { + if ("".equals(uri) || uri == null) + uri = this.base.getBaseURI(); + + // Get fragment + Expr fragment = null; + int hi = uri.indexOf('#'); + if (hi != -1) + { + String f = uri.substring(hi + 1); + uri = uri.substring(0, hi); + // TODO handle xpointer() here + // this only handles IDs + fragment = new IdFunction(new Constant(f)); + } + + // Get document source + try + { + DOMSource source; + XSLURIResolver resolver = stylesheet.factory.resolver; + synchronized (resolver) + { + if (stylesheet.transformer != null) + { + resolver.setUserResolver(stylesheet.transformer.uriResolver); + resolver.setUserListener(stylesheet.transformer.errorListener); + } + source = resolver.resolveDOM(null, base, uri); + } + Node node = source.getNode(); + // Strip whitespace + TransformerImpl.strip(stylesheet, node); + if (fragment == null) + return Collections.singleton(node); + else + { + Object ret = fragment.evaluate(node, 1, 1); + if (!(ret instanceof Collection)) + { + // XXX Report error? + return Collections.EMPTY_SET; + } + return (Collection) ret; + } + } + catch (TransformerException e) + { + String msg = "can't open " + uri; + if (base != null) + msg += " with base " + base; + throw new RuntimeException(msg); + } + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + s = (Stylesheet) context; + DocumentFunction f = new DocumentFunction(s, base); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + args2.add(((Expr) args.get(i)).clone(context)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java new file mode 100644 index 000000000..6a9d256be --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java @@ -0,0 +1,181 @@ +/* ElementAvailableFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.QName; +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT element-available function. + * + * @author Chris Burdess + */ +class ElementAvailableFunction + extends Expr + implements Function, XPathFunction +{ + + static final Collection elements; + static + { + TreeSet acc = new TreeSet(); + acc.add("stylesheet"); + acc.add("template"); + acc.add("param"); + acc.add("variable"); + acc.add("include"); + acc.add("import"); + acc.add("output"); + acc.add("preserve-space"); + acc.add("strip-space"); + acc.add("key"); + acc.add("decimal-format"); + acc.add("namespace-alias"); + acc.add("attribute-set"); + acc.add("apply-templates"); + acc.add("call-template"); + acc.add("value-of"); + acc.add("for-each"); + acc.add("if"); + acc.add("choose"); + acc.add("when"); + acc.add("otherwise"); + acc.add("element"); + acc.add("attribute"); + acc.add("text"); + acc.add("copy"); + acc.add("processing-instruction"); + acc.add("comment"); + acc.add("number"); + acc.add("copy-of"); + acc.add("message"); + acc.add("sort"); + acc.add("with-param"); + acc.add("fallback"); + acc.add("apply-imports"); + elements = Collections.unmodifiableSet(acc); + } + + final NamespaceContext nsctx; + List args; + + ElementAvailableFunction(NamespaceContext nsctx) + { + this.nsctx = nsctx; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + Expr arg = (Expr) args.get(0); + Object val = arg.evaluate(context, pos, len); + String name = _string(context, val); + String prefix, localName, uri; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = name; + } + else + { + prefix = name.substring(0, ci); + localName = name.substring(ci + 1); + } + uri = nsctx.getNamespaceURI(prefix); + if (Stylesheet.XSL_NS.equals(uri)) + { + return elements.contains(localName) ? + Boolean.TRUE : Boolean.FALSE; + } + // TODO extension elements + return Boolean.FALSE; + } + + public Expr clone(Object context) + { + NamespaceContext n = nsctx; + if (context instanceof NamespaceContext) + n = (NamespaceContext) context; + ElementAvailableFunction f = new ElementAvailableFunction(n); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + args2.add(((Expr) args.get(i)).clone(context)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + + public String toString() + { + return "element-available(" + args.get(0) + ")"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ElementNode.java b/libjava/classpath/gnu/xml/transform/ElementNode.java new file mode 100644 index 000000000..78a2007b7 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ElementNode.java @@ -0,0 +1,261 @@ +/* ElementNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.StringTokenizer; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL element instruction. + * + * @author Chris Burdess + */ +final class ElementNode + extends TemplateNode +{ + + final TemplateNode name; + final TemplateNode namespace; + final String uas; + final Node source; + final Collection elementExcludeResultPrefixes; + + ElementNode(TemplateNode name, + TemplateNode namespace, String uas, Node source) + { + this.name = name; + this.namespace = namespace; + this.uas = uas; + this.source = source; + NamedNodeMap attrs = source.getAttributes(); + Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS, + "exclude-result-prefixes"); + if (attr != null) + { + elementExcludeResultPrefixes = new HashSet(); + StringTokenizer st = new StringTokenizer(attr.getNodeValue()); + while (st.hasMoreTokens()) + elementExcludeResultPrefixes.add(st.nextToken()); + } + else + elementExcludeResultPrefixes = Collections.EMPTY_SET; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ElementNode(name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + uas, source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + // Create a document fragment to hold the name + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply name to the fragment + name.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + String nameValue = Expr.stringValue(fragment); + + String namespaceValue = null; + if (namespace != null) + { + // Create a document fragment to hold the namespace + fragment = doc.createDocumentFragment(); + // Apply namespace to the fragment + namespace.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + namespaceValue = Expr.stringValue(fragment); + if (namespaceValue.length() == 0) + namespaceValue = null; + } + else + { + String prefix = getPrefix(nameValue); + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + int ci = nameValue.indexOf(':'); + nameValue = nameValue.substring(ci + 1); + } + else + { + // Namespace aliasing + if (prefix == null) + prefix = "#default"; + String resultPrefix = + (String) stylesheet.namespaceAliases.get(prefix); + if (resultPrefix != null) + { + if ("#default".equals(resultPrefix)) + resultPrefix = null; + namespaceValue = source.lookupNamespaceURI(resultPrefix); + } + if (prefix == "#default") + prefix = null; + // Look up ordinary namespace for this prefix + if (namespaceValue == null) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + namespaceValue = XMLConstants.XML_NS_URI; + else + { + // Resolve namespace for this prefix + namespaceValue = source.lookupNamespaceURI(prefix); + } + } + } + } + + // Create element + Element element = (namespaceValue != null) ? + doc.createElementNS(namespaceValue, nameValue) : + doc.createElement(nameValue); + if (nextSibling != null) + parent.insertBefore(element, nextSibling); + else + parent.appendChild(element); + stylesheet.addNamespaceNodes(source, element, doc, + elementExcludeResultPrefixes); + if (uas != null) + { + StringTokenizer st = new StringTokenizer(uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + element, null, st.nextToken()); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + element, null); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + final String getPrefix(String name) + { + int ci = name.indexOf(':'); + return (ci == -1) ? null : name.substring(0, ci); + } + + void addAttributeSet(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling, String attributeSet) + throws TransformerException + { + stylesheet.bindings.global = true; + for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); ) + { + AttributeSet as = (AttributeSet) i.next(); + if (!as.name.equals(attributeSet)) + continue; + if (as.uas != null) + { + StringTokenizer st = new StringTokenizer(as.uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + parent, nextSibling, st.nextToken()); + } + if (as.children != null) + as.children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + stylesheet.bindings.global = false; + } + + public boolean references(QName var) + { + if (name != null && name.references(var)) + return true; + if (namespace != null && namespace.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("element"); + buf.append('['); + buf.append("name="); + if (namespace != null) + { + buf.append(",namespace="); + buf.append(namespace); + } + buf.append(name); + if (uas != null) + { + buf.append(",uas="); + buf.append(uas); + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java new file mode 100644 index 000000000..8a28795c4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java @@ -0,0 +1,101 @@ +/* ErrorListenerErrorHandler.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * An ErrorHandler that wraps an ErrorListener. + * + * @author Chris Burdess + */ +class ErrorListenerErrorHandler + implements ErrorHandler +{ + + final ErrorListener listener; + + ErrorListenerErrorHandler(ErrorListener listener) + { + this.listener = listener; + } + + public void warning(SAXParseException e) + throws SAXException + { + try + { + listener.warning(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + + public void error(SAXParseException e) + throws SAXException + { + try + { + listener.error(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + + public void fatalError(SAXParseException e) + throws SAXException + { + try + { + listener.fatalError(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ForEachNode.java b/libjava/classpath/gnu/xml/transform/ForEachNode.java new file mode 100644 index 000000000..1613f768b --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ForEachNode.java @@ -0,0 +1,159 @@ +/* ForEachNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSLT for-each instruction. + * + * @author Chris Burdess + */ +final class ForEachNode + extends TemplateNode +{ + + final Expr select; + final List sortKeys; + + ForEachNode(Expr select, List sortKeys) + { + this.select = select; + this.sortKeys = sortKeys; + } + + TemplateNode clone(Stylesheet stylesheet) + { + int len = sortKeys.size(); + List sortKeys2 = new ArrayList(len); + for (int i = 0; i < len; i++) + sortKeys2.add(sortKeys.get(i).clone(stylesheet)); + TemplateNode ret = new ForEachNode(select.clone(stylesheet), + sortKeys2); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + @Override + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + { + // Set current template to null + Template saved = stylesheet.currentTemplate; + stylesheet.currentTemplate = null; + Object ret = select.evaluate(context, pos, len); + //System.err.println(toString() + ": " + context+" -> "+ret); + if (ret instanceof Collection) + { + /* Suppression is safe, as we know context produces Collection */ + @SuppressWarnings("unchecked") + Collection ns = (Collection) ret; + List list = new ArrayList(ns); + if (!sortKeys.isEmpty()) + { + for (SortKey sortKey : sortKeys) + { + sortKey.init(stylesheet, mode, context, pos, len, parent, + nextSibling); + } + Collections.sort(list, new XSLComparator(sortKeys)); + } + else + Collections.sort(list, documentOrderComparator); + // Perform children for each node + int l = list.size(); + int p = 1; + for (Node node : list) + { + stylesheet.current = node; + children.apply(stylesheet, mode, + node, p++, l, + parent, nextSibling); + } + } + // Restore current template + stylesheet.currentTemplate = saved; + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + @Override + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + if (i.next().references(var)) + return true; + } + return super.references(var); + } + + @Override + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("for-each"); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java new file mode 100644 index 000000000..82872be77 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java @@ -0,0 +1,145 @@ +/* FormatNumberFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT format-number()function. + * + * @author Chris Burdess + */ +final class FormatNumberFunction + extends Expr + implements XPathFunction, Function +{ + + final Stylesheet stylesheet; + List args; + + FormatNumberFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + double number = _number(context, values.get(0)); + String pattern = _string(context, values.get(1)); + // Currency symbol ¤ is not supposed to be present + if (pattern.indexOf('\u00a4') != -1) + { + // Replace with $ (Xalan does this) + pattern = pattern.replace('\u00a4', '$'); + } + String dfName = null; + if (arity > 2) + { + dfName = _string(context, values.get(2)); + // otherwise the default decimal-format will be used + } + DecimalFormat df = (DecimalFormat) stylesheet.decimalFormats.get(dfName); + if (df == null) + { + throw new IllegalArgumentException("No such decimal-format: " + + dfName); + } + df.applyLocalizedPattern(pattern); + return df.format(number); + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + FormatNumberFunction f = new FormatNumberFunction(s); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java new file mode 100644 index 000000000..1ac50327e --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java @@ -0,0 +1,192 @@ +/* FunctionAvailableFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT function-available function. + * + * @author Chris Burdess + */ +class FunctionAvailableFunction + extends Expr + implements Function, XPathFunction +{ + + static final Collection xsltFunctions; + static final Collection xpathFunctions; + static + { + TreeSet acc = new TreeSet(); + acc.add("document"); + acc.add("key"); + acc.add("format-number"); + acc.add("current"); + acc.add("unparsed-entity-uri"); + acc.add("generate-id"); + acc.add("system-property"); + acc.add("element-available"); + acc.add("function-available"); + xsltFunctions = Collections.unmodifiableSet(acc); + acc = new TreeSet(); + acc.add("boolean"); + acc.add("ceiling"); + acc.add("concat"); + acc.add("contains"); + acc.add("count"); + acc.add("false"); + acc.add("floor"); + acc.add("id"); + acc.add("lang"); + acc.add("last"); + acc.add("local-name"); + acc.add("name"); + acc.add("namespace-uri"); + acc.add("normalize-space"); + acc.add("not"); + acc.add("number"); + acc.add("position"); + acc.add("round"); + acc.add("starts-with"); + acc.add("string"); + acc.add("string-length"); + acc.add("substring-after"); + acc.add("substring-before"); + acc.add("substring"); + acc.add("sum"); + acc.add("translate"); + acc.add("true"); + xpathFunctions = Collections.unmodifiableSet(acc); + } + + final NamespaceContext nsctx; + List args; + + FunctionAvailableFunction(NamespaceContext nsctx) + { + this.nsctx = nsctx; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + Expr arg = (Expr) args.get(0); + Object val = arg.evaluate(context, pos, len); + String name = _string(context, val); + String prefix, localName, uri; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = name; + } + else + { + prefix = name.substring(0, ci); + localName = name.substring(ci + 1); + } + uri = nsctx.getNamespaceURI(prefix); + if (uri == null) + { + return (xpathFunctions.contains(localName) || + xsltFunctions.contains(localName)) ? + Boolean.TRUE : Boolean.FALSE; + } + else if (Stylesheet.XSL_NS.equals(uri)) + { + return xsltFunctions.contains(localName) ? + Boolean.TRUE : Boolean.FALSE; + } + // TODO extension functions + return Boolean.FALSE; + } + + public Expr clone(Object context) + { + NamespaceContext n = nsctx; + if (context instanceof NamespaceContext) + n = (NamespaceContext) context; + FunctionAvailableFunction f = new FunctionAvailableFunction(n); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + args2.add(((Expr) args.get(i)).clone(context)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + + public String toString() + { + return "function-available(" + args.get(0) + ")"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java new file mode 100644 index 000000000..efc583cc8 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java @@ -0,0 +1,139 @@ +/* GenerateIdFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT generate-id()function. + * + * @author Chris Burdess + */ +final class GenerateIdFunction + extends Expr + implements XPathFunction, Function +{ + + List args; + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + Node node; + Collection ns = (arity == 0) ? Collections.EMPTY_SET : + (Collection) values.get(0); + if (ns.isEmpty()) + { + node = context; + } + else + { + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + node = (Node) list.get(0); + } + + String name = node.getNodeName(); + int index = 0, depth = 0; + for (Node ctx = node.getPreviousSibling(); ctx != null; + ctx = ctx.getPreviousSibling()) + { + index++; + } + for (Node ctx = node.getParentNode(); ctx != null; + ctx = ctx.getParentNode()) + { + depth++; + } + return name + "-" + index + "-" + depth; + } + + public Expr clone(Object context) + { + GenerateIdFunction f = new GenerateIdFunction(); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/IfNode.java b/libjava/classpath/gnu/xml/transform/IfNode.java new file mode 100644 index 000000000..f31fed555 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/IfNode.java @@ -0,0 +1,112 @@ +/* IfNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL if instruction. + * + * @author Chris Burdess + */ +final class IfNode + extends TemplateNode +{ + + final Expr test; + + IfNode(Expr test) + { + this.test = test; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new IfNode(test.clone(stylesheet)); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = test.evaluate(context, pos, len); + boolean success = (ret instanceof Boolean) ? + ((Boolean) ret).booleanValue() : + Expr._boolean(context, ret); + if (success) + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (test != null && test.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("if"); + buf.append('['); + buf.append("test="); + buf.append(test); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Key.java b/libjava/classpath/gnu/xml/transform/Key.java new file mode 100644 index 000000000..18d83394f --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Key.java @@ -0,0 +1,70 @@ +/* Key.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.namespace.QName; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Pattern; + +/** + * An XSL key. + * + * @author Chris Burdess + */ +class Key +{ + + final QName name; + final Pattern match; + final Expr use; + + Key(QName name, Pattern match, Expr use) + { + this.name = name; + this.match = match; + this.use = use; + } + + Key clone(Stylesheet stylesheet) + { + return new Key(name, + (Pattern) match.clone(stylesheet), + use.clone(stylesheet)); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/KeyFunction.java b/libjava/classpath/gnu/xml/transform/KeyFunction.java new file mode 100644 index 000000000..b962626c9 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/KeyFunction.java @@ -0,0 +1,227 @@ +/* KeyFunction.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; +import gnu.xml.xpath.Pattern; + +/** + * The XSLT key()function. + * + * @author Chris Burdess + */ +final class KeyFunction + extends Pattern + implements XPathFunction, Function +{ + + final Stylesheet stylesheet; + List args; + + KeyFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public boolean matches(Node context) + { + Object ret = evaluate(context, 1, 1); + return !((Collection) ret).isEmpty(); + } + + public Object evaluate(Node context, int pos, int len) + { + // Evaluate arguments + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + // Get key name + QName keyName = QName.valueOf(_string(context, values.get(0))); + // Expand qualified name + String uri = keyName.getNamespaceURI(); + String prefix = keyName.getPrefix(); + if ((uri == null || uri.length() == 0) && + (prefix != null && prefix.length() > 0)) + { + uri = stylesheet.getNamespaceURI(prefix); + if (uri != null && uri.length() > 0) + { + String localName = keyName.getLocalPart(); + keyName = new QName(uri, localName, prefix); + } + } + // Compute matching key set + Collection keySet = new LinkedList(); + for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); ) + { + Key key = (Key) i.next(); + if (key.name.equals(keyName)) + { + keySet.add(key); + } + } + // Get target + Object target = values.get(1); + Collection acc = new LinkedHashSet(); + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + if (target instanceof Collection) + { + for (Iterator i = ((Collection) target).iterator(); i.hasNext(); ) + { + String val = Expr.stringValue((Node) i.next()); + addKeyNodes(doc, keySet, val, acc); + } + } + else + { + String val = Expr._string(context, target); + addKeyNodes(doc, keySet, val, acc); + } + List ret = new ArrayList(acc); + Collections.sort(ret, documentOrderComparator); + return ret; + } + + final void addKeyNodes(Node node, Collection keySet, + String value, Collection acc) + { + addKeyNodeIfMatch(node, keySet, value, acc); + // Apply children + for (Node ctx = node.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + addKeyNodes(ctx, keySet, value, acc); + } + } + + final void addKeyNodeIfMatch(Node node, Collection keySet, + String value, Collection acc) + { + for (Iterator i = keySet.iterator(); i.hasNext(); ) + { + Key key = (Key) i.next(); + if (key.match.matches(node)) + { + Object eval = key.use.evaluate(node, 1, 1); + if (eval instanceof Collection) + { + for (Iterator j = ((Collection) eval).iterator(); + j.hasNext(); ) + { + String keyValue = Expr.stringValue((Node) j.next()); + if (value.equals(keyValue)) + { + acc.add(node); + return; + } + } + } + else + { + String keyValue = Expr._string(node, eval); + if (value.equals(keyValue)) + { + acc.add(node); + return; + } + } + } + } + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + KeyFunction f = new KeyFunction(s); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/LiteralNode.java b/libjava/classpath/gnu/xml/transform/LiteralNode.java new file mode 100644 index 000000000..3405b3364 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/LiteralNode.java @@ -0,0 +1,202 @@ +/* LiteralNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A template node that copies a DOM node in the template to the result + * tree. + * + * @author Chris Burdess + */ +final class LiteralNode + extends TemplateNode +{ + + /** + * The source node in the XSL template. + */ + final Node source; + + final Collection elementExcludeResultPrefixes; + + LiteralNode(Node source) + { + this.source = source; + if (source.getNodeType() == Node.ELEMENT_NODE) + { + NamedNodeMap attrs = source.getAttributes(); + Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS, + "exclude-result-prefixes"); + if (attr != null) + { + elementExcludeResultPrefixes = new HashSet(); + StringTokenizer st = new StringTokenizer(attr.getNodeValue()); + while (st.hasMoreTokens()) + elementExcludeResultPrefixes.add(st.nextToken()); + } + else + elementExcludeResultPrefixes = Collections.EMPTY_SET; + } + else + elementExcludeResultPrefixes = null; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new LiteralNode(source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Node result = null; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + short nodeType = source.getNodeType(); + if (nodeType == Node.ATTRIBUTE_NODE && + parent.getFirstChild() != null) + { + // Ignore attributes added after child elements + } + else + { + // Namespace aliasing + if (nodeType == Node.ELEMENT_NODE) + { + String prefix = source.getPrefix(); + if (prefix == null) + prefix = "#default"; + String resultPrefix = + (String) stylesheet.namespaceAliases.get(prefix); + if (resultPrefix != null) + { + if ("#default".equals(resultPrefix)) + resultPrefix = null; + String uri = source.lookupNamespaceURI(resultPrefix); + String name = source.getNodeName(); + // Create a new element node in the result document + result = doc.createElementNS(uri, name); + // copy attributes + NamedNodeMap srcAttrs = source.getAttributes(); + NamedNodeMap dstAttrs = result.getAttributes(); + int l = srcAttrs.getLength(); + for (int i = 0; i < l; i++) + { + Node attr = srcAttrs.item(i); + if (!Stylesheet.XSL_NS.equals(attr.getNamespaceURI())) + { + attr = attr.cloneNode(true); + attr = doc.adoptNode(attr); + dstAttrs.setNamedItemNS(attr); + } + } + } + } + if (result == null) + { + // Create result node + result = source.cloneNode(false); + // Remove any XSL attributes + NamedNodeMap attrs = result.getAttributes(); + if (attrs != null) + { + int l = attrs.getLength(); + for (int i = 0; i < l; i++) + { + Node attr = attrs.item(i); + if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI())) + { + attrs.removeNamedItem(attr.getNodeName()); + i--; + l--; + } + } + } + Node result2 = doc.adoptNode(result); + if (result2 == null) + { + String msg = "Error adopting node to result tree: " + + result + " (" + result.getClass().getName() + ")"; + DOMSourceLocator l = new DOMSourceLocator(context); + throw new TransformerException(msg, l); + } + result = result2; + } + if (nextSibling != null) + parent.insertBefore(result, nextSibling); + else + parent.appendChild(result); + if (nodeType == Node.ELEMENT_NODE) + stylesheet.addNamespaceNodes(source, result, doc, + elementExcludeResultPrefixes); + // children + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + result, null); + } + // next sibling + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return source.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/MessageNode.java b/libjava/classpath/gnu/xml/transform/MessageNode.java new file mode 100644 index 000000000..3e4899aeb --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/MessageNode.java @@ -0,0 +1,110 @@ +/* MessageNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.logging.Logger; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * An XSL message instruction. + * + * @author Chris Burdess + */ +final class MessageNode + extends TemplateNode +{ + + static final Logger logger = Logger.getLogger("gnu.xml.transform"); + + final boolean terminate; + + MessageNode(boolean terminate) + { + this.terminate = terminate; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new MessageNode(terminate); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + children.apply(stylesheet, mode, context, pos, len, fragment, null); + String message = Expr.stringValue(fragment); + logger.info(message); + if (terminate) + stylesheet.terminated = true; + } + if (next != null && !terminate) + next.apply(stylesheet, mode, context, pos, len, parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("message"); + if (terminate) + { + buf.append('['); + buf.append("terminate"); + buf.append(']'); + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NamespaceProxy.java b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java new file mode 100644 index 000000000..695fbeb52 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java @@ -0,0 +1,77 @@ +/* NamespaceProxy.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.Collections; +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.Node; + +/** + * A namespace context using a DOM node to resolve the namespace. + * + * @author Chris Burdess + */ +class NamespaceProxy + implements NamespaceContext +{ + + private final Node node; + + NamespaceProxy(Node node) + { + this.node = node; + } + + public String getNamespaceURI(String prefix) + { + return (node == null) ? null : node.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return (node == null) ? null : node.lookupPrefix(namespaceURI); + } + + public Iterator getPrefixes(String namespaceURI) + { + // TODO + return Collections.singleton(getPrefix(namespaceURI)).iterator(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NodeNumberNode.java b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java new file mode 100644 index 000000000..6663db371 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java @@ -0,0 +1,269 @@ +/* NodeNumberNode.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.UnionExpr; + +/** + * A template node representing the XSL number instruction + * with no value expression, i.e. the value is computed from + * the document position of the context node. + * + * @author Chris Burdess + */ +final class NodeNumberNode + extends AbstractNumberNode +{ + + static final int SINGLE = 0; + static final int MULTIPLE = 1; + static final int ANY = 2; + + final int level; + final Pattern count; + final Pattern from; + + NodeNumberNode(int level, Pattern count, Pattern from, + TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(format, lang, letterValue, groupingSeparator, groupingSize); + this.level = level; + this.count = count; + this.from = from; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new NodeNumberNode(level, + (count == null) ? null : + (Pattern) count.clone(stylesheet), + (from == null) ? from : + (Pattern) from.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + if (children != null) + { + ret.children = children.clone(stylesheet); + } + if (next != null) + { + ret.next = next.clone(stylesheet); + } + return ret; + } + + int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException + { + /*if (from != null) + { + Object ret = from.evaluate(context, pos, len); + if (ret instanceof Collection) + { + Collection ns = (Collection) ret; + if (ns.size() > 0) + { + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + context = (Node) list.get(0); + } + else + { + return new int[0]; + } + } + else + { + return new int[0]; + } + }*/ + Node current = context; + switch (level) + { + case SINGLE: + if (from == null) + { + while (context != null && !countMatches(current, context)) + { + context = context.getParentNode(); + } + } + else + { + while (context != null && !countMatches(current, context) && + !fromMatches(context)) + { + context = context.getParentNode(); + } + } + return (context == null) ? new int[0] : + new int[] { (context == current) ? pos : getIndex(current, context) }; + case MULTIPLE: + List ancestors = new ArrayList(); + while (context != null) + { + if (countMatches(current, context)) + { + if (from == null || fromMatches(context)) + { + ancestors.add(context); + } + } + context = context.getParentNode(); + } + Collections.sort(ancestors, documentOrderComparator); + int[] ret = new int[ancestors.size()]; + for (int i = 0; i < ret.length; i++) + { + ret[i] = getIndex(current, (Node) ancestors.get(i)); + } + return ret; + case ANY: + Expr preceding = new Selector(Selector.PRECEDING, + Collections.EMPTY_LIST); + Expr ancestorOrSelf = new Selector(Selector.ANCESTOR_OR_SELF, + Collections.EMPTY_LIST); + Expr any = new UnionExpr(preceding, ancestorOrSelf); + Object eval = any.evaluate(context, pos, len); + if (eval instanceof Collection) + { + Collection ns = (Collection) eval; + List candidates = new ArrayList(); + for (Iterator i = ns.iterator(); i.hasNext(); ) + { + Node candidate = (Node) i.next(); + if (countMatches(current, candidate)) + { + candidates.add(candidate); + if (from != null && from.matches(candidate)) + { + break; + } + } + } + return new int[] { candidates.size() }; + } + return new int[0]; + default: + throw new TransformerException("invalid level"); + } + } + + boolean countMatches(Node current, Node node) + { + if (count == null) + { + int cnt = current.getNodeType(); + int nnt = node.getNodeType(); + if (cnt != nnt) + { + return false; + } + if (nnt == Node.ELEMENT_NODE || nnt == Node.ATTRIBUTE_NODE) + { + String curi = current.getNamespaceURI(); + String nuri = node.getNamespaceURI(); + if ((curi == null && nuri != null) || + (curi != null && !curi.equals(nuri))) + { + return false; + } + String cn = current.getLocalName(); + if (cn == null) + { + cn = current.getNodeName(); + } + String nn = node.getLocalName(); + if (nn == null) + { + nn = node.getNodeName(); + } + if (!cn.equals(nn)) + { + return false; + } + } + return true; + } + else + { + return count.matches(node); + } + } + + boolean fromMatches(Node node) + { + for (Node ctx = node.getParentNode(); ctx != null; + ctx = ctx.getParentNode()) + { + if (from.matches(ctx)) + { + return true; + } + } + return false; + } + + int getIndex(Node current, Node node) + { + int index = 0; + do + { + do + { + node = node.getPreviousSibling(); + } + while (node != null && !countMatches(current, node)); + index++; + } + while (node != null); + return index; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NumberNode.java b/libjava/classpath/gnu/xml/transform/NumberNode.java new file mode 100644 index 000000000..cec594b99 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NumberNode.java @@ -0,0 +1,88 @@ +/* NumberNode.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL number instruction + * with a value expression. + * + * @author Chris Burdess + */ +final class NumberNode + extends AbstractNumberNode +{ + + final Expr value; + + NumberNode(Expr value, TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(format, lang, letterValue, groupingSeparator, groupingSize); + this.value = value; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new NumberNode(value.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + if (children != null) + { + ret.children = children.clone(stylesheet); + } + if (next != null) + { + ret.next = next.clone(stylesheet); + } + return ret; + } + + int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException + { + Object ret = value.evaluate(context, pos, len); + Double d = (ret instanceof Double) ? ((Double) ret) : + new Double(Expr._number(context, ret)); + return new int[] { d.intValue() }; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/OtherwiseNode.java b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java new file mode 100644 index 000000000..09057840d --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java @@ -0,0 +1,83 @@ +/* OtherwiseNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSL otherwise instruction. + * + * @author Chris Burdess + */ +final class OtherwiseNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new OtherwiseNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "otherwise"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ParameterNode.java b/libjava/classpath/gnu/xml/transform/ParameterNode.java new file mode 100644 index 000000000..4f3dc7569 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ParameterNode.java @@ -0,0 +1,172 @@ +/* ParameterNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collections; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node that sets a variable or parameter during template + * processing. + * + * @author Chris Burdess + */ +final class ParameterNode + extends TemplateNode + implements Comparable +{ + + final QName name; + final Expr select; + final int type; + + ParameterNode(QName name, Expr select, int type) + { + this.name = name; + this.select = select; + this.type = type; + } + + @Override + ParameterNode clone(Stylesheet stylesheet) + { + ParameterNode ret = new ParameterNode(name, + select == null ? null : select.clone(stylesheet), + type); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + // push the variable context + stylesheet.bindings.push(type); + // set the variable + Object value = getValue(stylesheet, mode, context, pos, len); + if (value != null) + { + stylesheet.bindings.set(name, value, type); + if (stylesheet.debug) + System.err.println(this + ": set to " + value); + } + // variable and param don't process children as such + // all subsequent instructions are processed with that variable context + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + // pop the variable context + stylesheet.bindings.pop(type); + } + + Object getValue(Stylesheet stylesheet, QName mode, + Node context, int pos, int len) + throws TransformerException + { + if (select != null) + return select.evaluate(context, pos, len); + else if (children != null) + { + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + children.apply(stylesheet, mode, context, pos, len, fragment, null); + return Collections.singleton(fragment); + } + else + return null; + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + return super.references(var); + } + + public int compareTo(ParameterNode pn) + { + boolean r1 = references(pn.name); + boolean r2 = pn.references(name); + if (r1 && r2) + throw new IllegalArgumentException("circular definitions"); + if (r1) + return 1; + if (r2) + return -1; + return 0; + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + switch (type) + { + case Bindings.VARIABLE: + buf.append("variable"); + break; + case Bindings.PARAM: + buf.append("param"); + break; + case Bindings.WITH_PARAM: + buf.append("with-param"); + break; + } + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(",select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java new file mode 100644 index 000000000..1e723a8d4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java @@ -0,0 +1,118 @@ +/* ProcessingInstructionNode.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL processing-instruction + * instruction. + * + * @author Chris Burdess + */ +final class ProcessingInstructionNode + extends TemplateNode +{ + + final String name; + + ProcessingInstructionNode(String name) + { + this.name = name; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ProcessingInstructionNode(name); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + String data = null; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (children != null) + { + // Create a document fragment to hold the text + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply children to the fragment + children.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + data = Expr.stringValue(fragment); + } + ProcessingInstruction pi = doc.createProcessingInstruction(name, data); + // Insert into result tree + if (nextSibling != null) + parent.insertBefore(pi, nextSibling); + else + parent.appendChild(pi); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("processing-instruction"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXSerializer.java b/libjava/classpath/gnu/xml/transform/SAXSerializer.java new file mode 100644 index 000000000..2bd1f97ab --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXSerializer.java @@ -0,0 +1,305 @@ +/* SAXSerializer.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import org.w3c.dom.Attr; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + +/** + * Serializes a DOM node to a sequence of SAX events. + * + * @author Chris Burdess + */ +class SAXSerializer + implements Attributes +{ + + transient NamedNodeMap attrs; + transient LinkedList namespaces = new LinkedList(); + + boolean isDefined(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (uri.equals(ctx.get(prefix))) + { + return true; + } + } + return false; + } + + void define(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (ctx.containsKey(prefix)) + { + HashMap newCtx = new HashMap(); + newCtx.put(prefix, uri); + namespaces.addFirst(newCtx); + return; + } + } + HashMap ctx; + if (namespaces.isEmpty()) + { + ctx = new HashMap(); + namespaces.add(ctx); + } + else + { + ctx = (HashMap) namespaces.getFirst(); + } + ctx.put(prefix, uri); + } + + void undefine(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (uri.equals(ctx.get(prefix))) + { + ctx.remove(prefix); + if (ctx.isEmpty()) + { + namespaces.remove(ctx); + } + return; + } + } + } + + public int getLength() + { + return attrs.getLength(); + } + + public String getURI(int index) + { + return attrs.item(index).getNamespaceURI(); + } + + public String getLocalName(int index) + { + return attrs.item(index).getLocalName(); + } + + public String getQName(int index) + { + return attrs.item(index).getNodeName(); + } + + public String getType(int index) + { + Attr attr = (Attr) attrs.item(index); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getValue(int index) + { + return attrs.item(index).getNodeValue(); + } + + public int getIndex(String uri, String localName) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String a_uri = attr.getNamespaceURI(); + String a_localName = attr.getLocalName(); + if (((a_uri == null && uri == null) || + (a_uri != null && a_uri.equals(uri))) && + a_localName.equals(localName)) + { + return i; + } + } + return -1; + } + + public int getIndex(String qName) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String a_name = attr.getNodeName(); + if (a_name.equals(qName)) + { + return i; + } + } + return -1; + } + + public String getType(String uri, String localName) + { + Attr attr = (Attr) attrs.getNamedItemNS(uri, localName); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getType(String qName) + { + Attr attr = (Attr) attrs.getNamedItem(qName); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getValue(String uri, String localName) + { + return attrs.getNamedItemNS(uri, localName).getNodeValue(); + } + + public String getValue(String qName) + { + return attrs.getNamedItem(qName).getNodeValue(); + } + + void serialize(Node node, ContentHandler ch, LexicalHandler lh) + throws SAXException + { + attrs = node.getAttributes(); + Node children; + Node next = node.getNextSibling(); + switch (node.getNodeType()) + { + case Node.ELEMENT_NODE: + String uri = node.getNamespaceURI(); + String prefix = node.getPrefix(); + boolean defined = isDefined(prefix, uri); + if (!defined) + { + define(prefix, uri); + ch.startPrefixMapping(prefix, uri); + } + String localName = node.getLocalName(); + String qName = node.getNodeName(); + ch.startElement(uri, localName, qName, this); + children = node.getFirstChild(); + if (children != null) + { + serialize(children, ch, lh); + } + ch.endElement(uri, localName, qName); + if (!defined) + { + ch.endPrefixMapping(prefix); + undefine(prefix, uri); + } + break; + case Node.TEXT_NODE: + char[] chars = node.getNodeValue().toCharArray(); + ch.characters(chars, 0, chars.length); + break; + case Node.CDATA_SECTION_NODE: + char[] cdata = node.getNodeValue().toCharArray(); + if (lh != null) + { + lh.startCDATA(); + ch.characters(cdata, 0, cdata.length); + lh.endCDATA(); + } + else + { + ch.characters(cdata, 0, cdata.length); + } + break; + case Node.COMMENT_NODE: + if (lh != null) + { + char[] comment = node.getNodeValue().toCharArray(); + lh.comment(comment, 0, comment.length); + } + break; + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + ch.startDocument(); + children = node.getFirstChild(); + if (children != null) + { + serialize(children, ch, lh); + } + ch.endDocument(); + break; + case Node.DOCUMENT_TYPE_NODE: + if (lh != null) + { + DocumentType doctype = (DocumentType) node; + String publicId = doctype.getPublicId(); + String systemId = doctype.getSystemId(); + lh.startDTD(node.getNodeName(), publicId, systemId); + NamedNodeMap entities = doctype.getEntities(); + int len = entities.getLength(); + for (int i = 0; i < len; i++) + { + Node entity = entities.item(i); + String entityName = entity.getNodeName(); + lh.startEntity(entityName); + lh.endEntity(entityName); + } + lh.endDTD(); + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ch.processingInstruction(node.getNodeName(), node.getNodeValue()); + break; + case Node.ENTITY_REFERENCE_NODE: + ch.skippedEntity(node.getNodeName()); + break; + } + attrs = null; + if (next != null) + { + serialize(next, ch, lh); + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java new file mode 100644 index 000000000..24464c067 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java @@ -0,0 +1,97 @@ +/* SAXTemplatesHandler.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.TemplatesHandler; +import org.w3c.dom.Document; +import gnu.xml.dom.ls.SAXEventSink; + +/** + * A content handler that acts as a sink for SAX parse events, + * constructing an XSL stylesheet. + * Internally, this class simply creates a DOM tree from the events, + * and then parses the DOM into a Templates object. + * + * @author Chris Burdess (dog@gnu.org) + */ +class SAXTemplatesHandler + extends SAXEventSink + implements TemplatesHandler +{ + + final TransformerFactoryImpl factory; + String systemId; + + SAXTemplatesHandler(TransformerFactoryImpl factory) + { + this.factory = factory; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public Templates getTemplates() + { + Document doc = getDocument(); + if (doc == null) + throw new IllegalStateException("Parsing of stylesheet incomplete"); + DOMSource ds = new DOMSource(doc, systemId); + try + { + return factory.newTemplates(ds); + } + catch (TransformerConfigurationException e) + { + String msg = "Unable to construct templates from this event stream"; + IllegalStateException e2 = new IllegalStateException(msg); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java new file mode 100644 index 000000000..890e15100 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java @@ -0,0 +1,111 @@ +/* SAXTransformerHandler.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.TransformerHandler; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import gnu.xml.dom.ls.SAXEventSink; + +/** + * A SAX event sink that processes an XML source represented as a stream of + * SAX events into a result tree. + * This works by simply buffering all the events into a DOM tree and then + * using this DOM tree as the source of the transformation. + * + * @author Chris Burdess (dog@gnu.org) + */ +class SAXTransformerHandler + extends SAXEventSink + implements TransformerHandler +{ + + final TransformerFactoryImpl factory; + final Transformer transformer; + String systemId; + Result result; + + SAXTransformerHandler(TransformerFactoryImpl factory, Transformer transformer) + { + this.factory = factory; + this.transformer = transformer; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public Transformer getTransformer() + { + return transformer; + } + + public void setResult(Result result) + { + this.result = result; + } + + public void endDocument() + throws SAXException + { + super.endDocument(); + try + { + Document doc = getDocument(); + DOMSource ds = new DOMSource(doc, systemId); + transformer.transform(ds, result); + } + catch (TransformerException e) + { + SAXException e2 = new SAXException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SortKey.java b/libjava/classpath/gnu/xml/transform/SortKey.java new file mode 100644 index 000000000..dd57df986 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SortKey.java @@ -0,0 +1,239 @@ +/* SortKey.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + *

    + * An XSL sort key, as specified by section 10 of the XSL + * Transformations specification. This takes the form: + *

    + *
    + * <xsl:sort
    + * select = string-expression
    + * lang = { nmtoken }
    + * data-type = { "text" | "number" | qname-but-not-ncname }
    + * order = { "ascending" | "descending" }
    + * case-order = { "upper-first" | "lower-first" } /&rt;
    + * 
    + *

    + * Note that all but the selection expression are optional, + * and so may be {@code null}. + *

    + * + * @author Chris Burdess + */ +final class SortKey +{ + + static final int DEFAULT = 0; + static final int UPPER_FIRST = 1; + static final int LOWER_FIRST = 2; + + final Expr select; + final TemplateNode langTemplate; + final TemplateNode dataTypeTemplate; + final TemplateNode orderTemplate; + final TemplateNode caseOrderTemplate; + + transient String lang; + transient String dataType; + transient boolean descending; + transient int caseOrder; + + /** + * Constructs a new {@link SortKey} to represent an <xsl:sort&rt; + * tag. + * + * @param select the XPath expression which selects the nodes to be sorted. + * @param lang the language of the sort keys or {@code null} if unspecified. + * @param dataType the data type of the strings. May be "string", "number", + * a QName or {@code null} if unspecified. + * @param order the ordering of the nodes, which may be "ascending", "descending" + * or {@code null} if unspecified. + * @param caseOrder the treatment of case when the data type is a string. This + * may be "upper-first", "lower-first" or {@code null} if + * unspecified. + */ + SortKey(Expr select, TemplateNode lang, TemplateNode dataType, + TemplateNode order, TemplateNode caseOrder) + { + this.select = select; + this.langTemplate = lang; + this.dataTypeTemplate = dataType; + this.orderTemplate = order; + this.caseOrderTemplate = caseOrder; + } + + String key(Node node) + { + Object ret = select.evaluate(node, 1, 1); + if (ret instanceof String) + { + return (String) ret; + } + else + { + return Expr._string(node, ret); + } + } + + /** + * Prepare for a sort. + * This sets all transient variables from their AVTs. + */ + void init(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + if (langTemplate == null) + { + lang = null; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + langTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + lang = Expr.stringValue(fragment); + } + if (dataTypeTemplate == null) + { + dataType = "text"; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + dataTypeTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + dataType = Expr.stringValue(fragment); + } + if (orderTemplate == null) + { + descending = false; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + orderTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + String order = Expr.stringValue(fragment); + descending = "descending".equals(order); + } + if (caseOrderTemplate == null) + { + caseOrder = DEFAULT; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + caseOrderTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + String co = Expr.stringValue(fragment); + caseOrder = "upper-first".equals(co) ? UPPER_FIRST : + "lower-first".equals(co) ? LOWER_FIRST : + DEFAULT; + } + } + + boolean references(QName var) + { + if (select != null && select.references(var)) + { + return true; + } + if (langTemplate != null && langTemplate.references(var)) + { + return true; + } + if (dataTypeTemplate != null && dataTypeTemplate.references(var)) + { + return true; + } + if (orderTemplate != null && orderTemplate.references(var)) + { + return true; + } + if (caseOrderTemplate != null && caseOrderTemplate.references(var)) + { + return true; + } + return false; + } + + /** + * Provides a clone of this {@link SortKey}, using the given + * stylesheet as a context. + * + * @param stylesheet the stylesheet which provides context for the cloning. + * @return a clone of this instance. + */ + SortKey clone(Stylesheet stylesheet) + { + return new SortKey(select.clone(stylesheet), + langTemplate == null ? null : cloneAttributeValueTemplate(langTemplate, stylesheet), + dataTypeTemplate == null ? null : cloneAttributeValueTemplate(dataTypeTemplate, stylesheet), + orderTemplate == null ? null : cloneAttributeValueTemplate(orderTemplate, stylesheet), + caseOrderTemplate == null ? null : cloneAttributeValueTemplate(caseOrderTemplate, stylesheet)); + } + + /** + * Clones an attribute value template as created by + * {@link Stylesheet#parseAttributeValueTemplate(String, Node)}. + * The node may either by a literal node or an xsl:value-of expression. + * + * @param node the node to clone. + * @param stylesheet the stylesheet which provides context for the cloning. + * @return the cloned node. + */ + private TemplateNode cloneAttributeValueTemplate(TemplateNode node, Stylesheet stylesheet) + { + if (node instanceof ValueOfNode) + return ((ValueOfNode) node).clone(stylesheet); + return ((LiteralNode) node).clone(stylesheet); + } +} diff --git a/libjava/classpath/gnu/xml/transform/StreamSerializer.java b/libjava/classpath/gnu/xml/transform/StreamSerializer.java new file mode 100644 index 000000000..a5705f891 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/StreamSerializer.java @@ -0,0 +1,854 @@ +/* StreamSerializer.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import javax.xml.XMLConstants; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * Serializes a DOM node to an output stream. + * + * @author Chris Burdess + */ +public class StreamSerializer +{ + + static final int SPACE = 0x20; + static final int BANG = 0x21; // ! + static final int APOS = 0x27; // ' + static final int SLASH = 0x2f; // / + static final int BRA = 0x3c; // < + static final int KET = 0x3e; // > + static final int EQ = 0x3d; // = + + /** + * HTML 4.01 boolean attributes + */ + static final Map HTML_BOOLEAN_ATTRIBUTES = new HashMap(); + static + { + HashSet set; + + set = new HashSet(); + set.add("nohref"); + HTML_BOOLEAN_ATTRIBUTES.put("area", set); + + set = new HashSet(); + set.add("ismap"); + HTML_BOOLEAN_ATTRIBUTES.put("img", set); + + set = new HashSet(); + set.add("declare"); + HTML_BOOLEAN_ATTRIBUTES.put("object", set); + + set = new HashSet(); + set.add("noshade"); + HTML_BOOLEAN_ATTRIBUTES.put("hr", set); + + set = new HashSet(); + set.add("compact"); + HTML_BOOLEAN_ATTRIBUTES.put("dl", set); + HTML_BOOLEAN_ATTRIBUTES.put("ol", set); + HTML_BOOLEAN_ATTRIBUTES.put("ul", set); + HTML_BOOLEAN_ATTRIBUTES.put("dir", set); + HTML_BOOLEAN_ATTRIBUTES.put("menu", set); + + set = new HashSet(); + set.add("checked"); + set.add("disabled"); + set.add("readonly"); + set.add("ismap"); + HTML_BOOLEAN_ATTRIBUTES.put("input", set); + + set = new HashSet(); + set.add("multiple"); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("select", set); + + set = new HashSet(); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("optgroup", set); + + set = new HashSet(); + set.add("selected"); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("option", set); + + set = new HashSet(); + set.add("disabled"); + set.add("readonly"); + HTML_BOOLEAN_ATTRIBUTES.put("textarea", set); + + set = new HashSet(); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("button", set); + + set = new HashSet(); + set.add("nowrap"); + HTML_BOOLEAN_ATTRIBUTES.put("th", set); + HTML_BOOLEAN_ATTRIBUTES.put("td", set); + + set = new HashSet(); + set.add("noresize"); + HTML_BOOLEAN_ATTRIBUTES.put("frame", set); + + set = new HashSet(); + set.add("defer"); + HTML_BOOLEAN_ATTRIBUTES.put("script", set); + } + + // HTML namespace URIs + static final HashSet HTML_URIS = new HashSet(); + static { + HTML_URIS.add("http://www.w3.org/1999/xhtml"); + } + + protected final String encoding; + final Charset charset; + final CharsetEncoder encoder; + final int mode; + final LinkedList namespaces; + protected String eol; + Collection cdataSectionElements = Collections.EMPTY_SET; + + protected boolean discardDefaultContent; + protected boolean xmlDeclaration = true; + + // has a META element with the encoding been added? + private boolean htmlEncoded; + + public StreamSerializer() + { + this(Stylesheet.OUTPUT_XML, null, null); + } + + public StreamSerializer(String encoding) + { + this(Stylesheet.OUTPUT_XML, encoding, null); + } + + public StreamSerializer(int mode, String encoding, String eol) + { + this.mode = mode; + if (encoding == null) + encoding = (mode == Stylesheet.OUTPUT_HTML) ? "ISO-8859-1" : "UTF-8"; + this.encoding = encoding.intern(); + charset = Charset.forName(this.encoding); + encoder = charset.newEncoder(); + this.eol = (eol != null) ? eol : System.getProperty("line.separator"); + namespaces = new LinkedList(); + } + + void setCdataSectionElements(Collection c) + { + cdataSectionElements = c; + } + + public void serialize(final Node node, final OutputStream out) + throws IOException + { + serialize(node, out, false); + } + + void serialize(Node node, final OutputStream out, + boolean convertToCdata) + throws IOException + { + while (node != null) + { + Node next = node.getNextSibling(); + doSerialize(node, out, convertToCdata); + node = next; + } + } + + private void doSerialize(final Node node, final OutputStream out, + boolean convertToCdata) + throws IOException + { + if (out == null) + throw new NullPointerException("no output stream"); + htmlEncoded = false; + String value, prefix; + Node children; + String uri = node.getNamespaceURI(); + short nt = node.getNodeType(); + if (convertToCdata && nt == Node.TEXT_NODE) + nt = Node.CDATA_SECTION_NODE; + switch (nt) + { + case Node.ATTRIBUTE_NODE: + prefix = node.getPrefix(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) || + XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + (prefix != null && prefix.startsWith("xmlns:"))) + { + String nsuri = node.getNodeValue(); + if (isDefined(nsuri, prefix)) + break; + String name = node.getLocalName(); + if (name == null) + { + // Namespace-unaware + name = node.getNodeName(); + int ci = name.indexOf(':'); + if (ci != -1) + name = name.substring(ci + 1); + } + define(nsuri, name); + } + else if (uri != null && !isDefined(uri, prefix)) + { + prefix = define(uri, prefix); + String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix; + out.write(SPACE); + out.write(encodeText(nsname)); + out.write(EQ); + String nsvalue = "\"" + encode(uri, true, true) + "\""; + out.write(nsvalue.getBytes(encoding)); + } + out.write(SPACE); + String a_nodeName = node.getNodeName(); + out.write(encodeText(a_nodeName)); + String a_nodeValue = node.getNodeValue(); + if (mode == Stylesheet.OUTPUT_HTML && + a_nodeName.equals(a_nodeValue) && + isHTMLBoolean((Attr) node, a_nodeName)) + break; + out.write(EQ); + value = "\"" + encode(a_nodeValue, true, true) + "\""; + out.write(encodeText(value)); + break; + case Node.ELEMENT_NODE: + pushNamespaceContext(); + value = node.getNodeName(); + out.write(BRA); + out.write(encodeText(value)); + prefix = node.getPrefix(); + if (uri != null && !isDefined(uri, prefix)) + { + prefix = define(uri, prefix); + String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix; + out.write(SPACE); + out.write(encodeText(nsname)); + out.write(EQ); + String nsvalue = "\"" + encode(uri, true, true) + "\""; + out.write(encodeText(nsvalue)); + } + NamedNodeMap attrs = node.getAttributes(); + if (attrs != null) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Attr attr = (Attr) attrs.item(i); + if (discardDefaultContent && !attr.getSpecified()) + { + // NOOP + } + else + serialize(attr, out, false); + } + } + convertToCdata = cdataSectionElements.contains(value); + children = node.getFirstChild(); + if (children == null) + { + out.write(SLASH); + out.write(KET); + } + else + { + out.write(KET); + serialize(children, out, convertToCdata); + out.write(BRA); + out.write(SLASH); + out.write(encodeText(value)); + out.write(KET); + } + popNamespaceContext(); + break; + case Node.TEXT_NODE: + value = node.getNodeValue(); + if (!"yes".equals(node.getUserData("disable-output-escaping")) && + mode != Stylesheet.OUTPUT_TEXT) + value = encode(value, false, false); + out.write(encodeText(value)); + break; + case Node.CDATA_SECTION_NODE: + value = node.getNodeValue(); + // Where any instanceof of ]]> occur, split into multiple CDATA + // sections + int bbk = value.indexOf("]]>"); + while (bbk != -1) + { + String head = value.substring(0, bbk + 2); + out.write(encodeText("")); + value = value.substring(bbk + 2); + bbk = value.indexOf("]]>"); + } + // Write final tail value + out.write(encodeText("")); + break; + case Node.COMMENT_NODE: + value = ""; + out.write(encodeText(value)); + Node cp = node.getParentNode(); + if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE) + out.write(encodeText(eol)); + break; + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + if (mode == Stylesheet.OUTPUT_XML) + { + if ("UTF-16".equalsIgnoreCase(encoding)) + { + out.write(0xfe); + out.write(0xff); + } + if (!"yes".equals(node.getUserData("omit-xml-declaration")) && + xmlDeclaration) + { + Document doc = (node instanceof Document) ? + (Document) node : null; + String version = (doc != null) ? doc.getXmlVersion() : null; + if (version == null) + version = (String) node.getUserData("version"); + if (version == null) + version = "1.0"; + out.write(BRA); + out.write(0x3f); + out.write("xml version=\"".getBytes("US-ASCII")); + out.write(version.getBytes("US-ASCII")); + out.write(0x22); + if (!("UTF-8".equalsIgnoreCase(encoding))) + { + out.write(" encoding=\"".getBytes("US-ASCII")); + out.write(encoding.getBytes("US-ASCII")); + out.write(0x22); + } + if ((doc != null && doc.getXmlStandalone()) || + "yes".equals(node.getUserData("standalone"))) + out.write(" standalone=\"yes\"".getBytes("US-ASCII")); + out.write(0x3f); + out.write(KET); + out.write(encodeText(eol)); + } + // TODO warn if not outputting the declaration would be a + // problem + } + else if (mode == Stylesheet.OUTPUT_HTML) + { + // Ensure that encoding is accessible if head element is present + String mediaType = (String) node.getUserData("media-type"); + if (mediaType == null) + mediaType = "text/html"; + String contentType = mediaType + "; charset=" + + ((encoding.indexOf(' ') != -1) ? + "\"" + encoding + "\"" : + encoding); + Document doc = (node instanceof Document) ? (Document) node : + node.getOwnerDocument(); + Node html = null; + for (Node ctx = node.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx.getNodeType() == Node.ELEMENT_NODE && + isHTMLElement(ctx, "html")) + { + html = ctx; + break; + } + } + if (html != null) + { + Node head = null; + for (Node ctx = html.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (isHTMLElement(ctx, "head")) + { + head = ctx; + break; + } + } + if (head != null) + { + Node meta = null; + Node metaContent = null; + for (Node ctx = head.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (isHTMLElement(ctx, "meta")) + { + NamedNodeMap metaAttrs = ctx.getAttributes(); + int len = metaAttrs.getLength(); + String httpEquiv = null; + Node content = null; + for (int i = 0; i < len; i++) + { + Node attr = metaAttrs.item(i); + String attrName = attr.getNodeName(); + if ("http-equiv".equalsIgnoreCase(attrName)) + httpEquiv = attr.getNodeValue(); + else if ("content".equalsIgnoreCase(attrName)) + content = attr; + } + if ("Content-Type".equalsIgnoreCase(httpEquiv)) + { + meta = ctx; + metaContent = content; + break; + } + } + } + if (meta == null) + { + meta = doc.createElement("meta"); + // Insert first + Node first = head.getFirstChild(); + if (first == null) + head.appendChild(meta); + else + head.insertBefore(meta, first); + Node metaHttpEquiv = doc.createAttribute("http-equiv"); + meta.getAttributes().setNamedItem(metaHttpEquiv); + metaHttpEquiv.setNodeValue("Content-Type"); + } + if (metaContent == null) + { + metaContent = doc.createAttribute("content"); + meta.getAttributes().setNamedItem(metaContent); + } + metaContent.setNodeValue(contentType); + htmlEncoded = true; + } + } + } + children = node.getFirstChild(); + if (children != null) + serialize(children, out, convertToCdata); + break; + case Node.DOCUMENT_TYPE_NODE: + DocumentType doctype = (DocumentType) node; + out.write(BRA); + out.write(BANG); + out.write(encodeText("DOCTYPE ")); + value = doctype.getNodeName(); + out.write(encodeText(value)); + String publicId = doctype.getPublicId(); + if (publicId != null) + { + out.write(encodeText(" PUBLIC ")); + out.write(APOS); + out.write(encodeText(publicId)); + out.write(APOS); + } + String systemId = doctype.getSystemId(); + if (systemId != null) + { + out.write(encodeText(" SYSTEM ")); + out.write(APOS); + out.write(encodeText(systemId)); + out.write(APOS); + } + String internalSubset = doctype.getInternalSubset(); + if (internalSubset != null) + { + out.write(encodeText(internalSubset)); + } + out.write(KET); + out.write(eol.getBytes(encoding)); + break; + case Node.ENTITY_REFERENCE_NODE: + value = "&" + node.getNodeValue() + ";"; + out.write(encodeText(value)); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + value = ""; + out.write(encodeText(value)); + Node pp = node.getParentNode(); + if (pp != null && pp.getNodeType() == Node.DOCUMENT_NODE) + { + out.write(encodeText(eol)); + } + break; + default: + System.err.println("Unhandled node type: "+nt); + } + } + + boolean isHTMLElement(Node node, String name) + { + if (node.getNodeType() != Node.ELEMENT_NODE) + return false; + String localName = node.getLocalName(); + if (localName == null) + localName = node.getNodeName(); + if (!name.equalsIgnoreCase(localName)) + return false; + String uri = node.getNamespaceURI(); + return (uri == null || HTML_URIS.contains(uri)); + } + + boolean isDefined(String uri, String prefix) + { + if (XMLConstants.XML_NS_URI.equals(uri)) + return "xml".equals(prefix); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri)) + return "xmlns".equals(prefix); + if (prefix == null) + prefix = ""; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + Map ctx = (Map) i.next(); + String val = (String) ctx.get(uri); + if (val != null && val.equals(prefix)) + return true; + } + return false; + } + + void pushNamespaceContext() + { + namespaces.addFirst(new HashMap()); + } + + String define(String uri, String prefix) + { + if (namespaces.isEmpty()) + return prefix; + HashMap ctx = (HashMap) namespaces.getFirst(); + while (ctx.containsValue(prefix)) + { + // Fabricate new prefix + prefix = prefix + "_"; + } + ctx.put(uri, prefix); + return prefix; + } + + void popNamespaceContext() + { + namespaces.removeFirst(); + } + + final byte[] encodeText(String text) + throws IOException + { + encoder.reset(); + boolean htmlNeedingEncoding = + (mode == Stylesheet.OUTPUT_HTML && !htmlEncoded); + if (!encoder.canEncode(text) || htmlNeedingEncoding) + { + // Check each character + CPStringBuilder buf = new CPStringBuilder(); + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (!encoder.canEncode(c)) + { + // Replace with character entity reference + String hex = Integer.toHexString((int) c); + buf.append("&#x"); + buf.append(hex); + buf.append(';'); + } + else if (htmlNeedingEncoding) + { + String entityName = getHTMLCharacterEntity(c); + if (entityName != null) + { + buf.append('&'); + buf.append(entityName); + buf.append(';'); + } + else + buf.append(c); + } + else + buf.append(c); + } + text = buf.toString(); + } + ByteBuffer encoded = encoder.encode(CharBuffer.wrap(text)); + int len = encoded.limit() - encoded.position(); + if (encoded.hasArray()) + { + byte[] ret = encoded.array(); + if (ret.length > len) + { + // Why? + byte[] ret2 = new byte[len]; + System.arraycopy(ret, 0, ret2, 0, len); + ret = ret2; + } + return ret; + } + encoded.flip(); + byte[] ret = new byte[len]; + encoded.get(ret, 0, len); + return ret; + } + + String encode(String text, boolean encodeCtl, boolean inAttr) + { + int len = text.length(); + CPStringBuilder buf = null; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '<') + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("<"); + } + else if (c == '>') + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append(">"); + } + else if (c == '&') + { + if (mode == Stylesheet.OUTPUT_HTML && (i + 1) < len && + text.charAt(i + 1) == '{') + { + if (buf != null) + buf.append(c); + } + else + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("&"); + } + } + else if (c == '\'' && inAttr) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + if (mode == Stylesheet.OUTPUT_HTML) + // HTML does not define ', use character entity ref + buf.append("'"); + else + buf.append("'"); + } + else if (c == '"' && inAttr) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("""); + } + else if (encodeCtl) + { + if (c < 0x20) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append('&'); + buf.append('#'); + buf.append((int) c); + buf.append(';'); + } + else if (buf != null) + buf.append(c); + } + else if (buf != null) + buf.append(c); + } + return (buf == null) ? text : buf.toString(); + } + + String toString(Node node) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try + { + serialize(node, out); + return new String(out.toByteArray(), encoding); + } + catch (IOException e) + { + throw new RuntimeException(e.getMessage()); + } + } + + boolean isHTMLBoolean(Attr attr, String attrName) + { + attrName = attrName.toLowerCase(); + Node element = attr.getOwnerElement(); + String elementName = element.getLocalName(); + if (elementName == null) + { + elementName = element.getNodeName(); + } + elementName = elementName.toLowerCase(); + Collection attributes = + (Collection) HTML_BOOLEAN_ATTRIBUTES.get(elementName); + return (attributes != null && attributes.contains(attrName)); + } + + static String getHTMLCharacterEntity(char c) + { + // Hardcode these here to avoid loading the HTML DTD + switch (c) + { + case 160: return "nbsp"; + case 161: return "iexcl"; + case 162: return "cent"; + case 163: return "pound"; + case 164: return "curren"; + case 165: return "yen"; + case 166: return "brvbar"; + case 167: return "sect"; + case 168: return "uml"; + case 169: return "copy"; + case 170: return "ordf"; + case 171: return "laquo"; + case 172: return "not"; + case 173: return "shy"; + case 174: return "reg"; + case 175: return "macr"; + case 176: return "deg"; + case 177: return "plusmn"; + case 178: return "sup2"; + case 179: return "sup3"; + case 180: return "acute"; + case 181: return "micro"; + case 182: return "para"; + case 183: return "middot"; + case 184: return "cedil"; + case 185: return "sup1"; + case 186: return "ordm"; + case 187: return "raquo"; + case 188: return "frac14"; + case 189: return "frac12"; + case 190: return "frac34"; + case 191: return "iquest"; + case 192: return "Agrave"; + case 193: return "Aacute"; + case 194: return "Acirc"; + case 195: return "Atilde"; + case 196: return "Auml"; + case 197: return "Aring"; + case 198: return "AElig"; + case 199: return "Ccedil"; + case 200: return "Egrave"; + case 201: return "Eacute"; + case 202: return "Ecirc"; + case 203: return "Euml"; + case 204: return "Igrave"; + case 205: return "Iacute"; + case 206: return "Icirc"; + case 207: return "Iuml"; + case 208: return "ETH"; + case 209: return "Ntilde"; + case 210: return "Ograve"; + case 211: return "Oacute"; + case 212: return "Ocirc"; + case 213: return "Otilde"; + case 214: return "Ouml"; + case 215: return "times"; + case 216: return "Oslash"; + case 217: return "Ugrave"; + case 218: return "Uacute"; + case 219: return "Ucirc"; + case 220: return "Uuml"; + case 221: return "Yacute"; + case 222: return "THORN"; + case 223: return "szlig"; + case 224: return "agrave"; + case 225: return "aacute"; + case 226: return "acirc"; + case 227: return "atilde"; + case 228: return "auml"; + case 229: return "aring"; + case 230: return "aelig"; + case 231: return "ccedil"; + case 232: return "egrave"; + case 233: return "eacute"; + case 234: return "ecirc"; + case 235: return "euml"; + case 236: return "igrave"; + case 237: return "iacute"; + case 238: return "icirc"; + case 239: return "iuml"; + case 240: return "eth"; + case 241: return "ntilde"; + case 242: return "ograve"; + case 243: return "oacute"; + case 244: return "ocirc"; + case 245: return "otilde"; + case 246: return "ouml"; + case 247: return "divide"; + case 248: return "oslash"; + case 249: return "ugrave"; + case 250: return "uacute"; + case 251: return "ucirc"; + case 252: return "uuml"; + case 253: return "yacute"; + case 254: return "thorn"; + case 255: return "yuml"; + default: return null; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/StrippingInstruction.java b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java new file mode 100644 index 000000000..27e9fc8ca --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java @@ -0,0 +1,73 @@ +/* StrippingInstruction.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.xml.xpath.NameTest; + +/** + * An entry in a strip-space or preserve-space list. + * + * @author Chris Burdess + */ +class StrippingInstruction +{ + + final NameTest element; + final int precedence; + + StrippingInstruction(NameTest element, int precedence) + { + this.element = element; + this.precedence = precedence; + } + + /** + * Returns the default priority of the element name test. + * @see http://www.w3.org/TR/xslt#dt-default-priority + */ + float getPriority() + { + if (element.matchesAny()) + return -0.5f; + else if (element.matchesAnyLocalName()) + return -0.25f; + else + return 0.0f; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Stylesheet.java b/libjava/classpath/gnu/xml/transform/Stylesheet.java new file mode 100644 index 000000000..786b258f5 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Stylesheet.java @@ -0,0 +1,1772 @@ +/* Stylesheet.java -- + Copyright (C) 2004,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.NameTest; +import gnu.xml.xpath.NodeTypeTest; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.Root; +import gnu.xml.xpath.Test; +import gnu.xml.xpath.XPathImpl; + +/** + * An XSL stylesheet. + * + * @author Chris Burdess + */ +class Stylesheet + implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable +{ + + static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform"; + private static final NameTest STYLESHEET_PRESERVE_TEXT = + new NameTest(new QName(XSL_NS, "text"), false, false); + + static final int OUTPUT_XML = 0; + static final int OUTPUT_HTML = 1; + static final int OUTPUT_TEXT = 2; + + final TransformerFactoryImpl factory; + TransformerImpl transformer; + Stylesheet parent; + final XPathImpl xpath; + final String systemId; + final int precedence; + + final boolean debug; + + /** + * Version of XSLT. + */ + String version; + + Collection extensionElementPrefixes; + Collection excludeResultPrefixes; + + /** + * Set of element names for which we should strip whitespace. + */ + Set stripSpace; + + /** + * Set of element names for which we should preserve whitespace. + */ + Set preserveSpace; + + /** + * Output options. + */ + Node output; + int outputMethod; + String outputVersion; + String outputEncoding; + boolean outputOmitXmlDeclaration; + boolean outputStandalone; + String outputPublicId; + String outputSystemId; + Collection outputCdataSectionElements; + boolean outputIndent; + String outputMediaType; + + /** + * Keys. + */ + Collection keys; + + /** + * Decimal formats. + */ + Map decimalFormats; + + /** + * Namespace aliases. + */ + Map namespaceAliases; + + /** + * Attribute-sets. + */ + List attributeSets; + + /** + * Variables. + */ + List variables; + + /** + * Variable and parameter bindings. + */ + Bindings bindings; + + /** + * Templates. + */ + LinkedList