pax_global_header00006660000000000000000000000064122536660750014526gustar00rootroot0000000000000052 comment=70e0937b1f6903cdaaaa484245310be046443525 jing-trang-20131210+dfsg+1/000077500000000000000000000000001225366607500150745ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/.project000066400000000000000000000005531225366607500165460ustar00rootroot00000000000000 jing org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature jing-trang-20131210+dfsg+1/ant000077500000000000000000000006271225366607500156110ustar00rootroot00000000000000#!/bin/sh test -x "$JAVA_HOME/bin/java" || { cat <&2 You must set JAVA_HOME environment variable to point to the directory where your JDK is installed. EOF exit 1 } JING_TRANG_HOME=`dirname $0` "$JAVA_HOME/bin/java" \ "-Dant.home=$JING_TRANG_HOME" \ -cp "$JING_TRANG_HOME/lib/ant-launcher.jar" \ org.apache.tools.ant.launch.Launcher \ -buildfile "$JING_TRANG_HOME/build.xml" \ "$@" jing-trang-20131210+dfsg+1/ant.bat000077500000000000000000000007551225366607500163600ustar00rootroot00000000000000@echo off setlocal if exist "%JAVA_HOME%\bin\java.exe" goto found echo You must set JAVA_HOME to the directory containing the JDK exit /b 1 :found rem %~dp0 gives the directory including the trailing slash rem we need the directory without the trailing slash, so add the dot set JING_TRANG_HOME=%~dp0. "%JAVA_HOME%\bin\java.exe" -classpath "%JING_TRANG_HOME%\lib\ant-launcher.jar" "-Dant.home=%JING_TRANG_HOME%" org.apache.tools.ant.launch.Launcher -buildfile "%JING_TRANG_HOME%\build.xml" %* jing-trang-20131210+dfsg+1/build-gcj.xml000066400000000000000000000042341225366607500174610ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/build.xml000066400000000000000000000373621225366607500167300ustar00rootroot00000000000000 <modules> <module>${modfrag}</module> </modules> jing-trang-20131210+dfsg+1/build.xsl000066400000000000000000000352451225366607500167340ustar00rootroot00000000000000 init , init ,mod. .test init ,mod. .services init , , ,mod. .compile-main mod. .compile-main ,mod. .compile-test init , , dummy ,mod. .test- com.thaiopensource.relaxng.util.TestDriver test/split.xsl jing com.thaiopensource.relaxng.translate.test.CompactTestDriver trang/test/compactsplit.xsl trang /mod/ /test- mod/ /test true jing-trang-20131210+dfsg+1/convert/000077500000000000000000000000001225366607500165545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/convert/from-relax.xsl000066400000000000000000000227601225366607500213670ustar00rootroot00000000000000
The "include" element is only supported with MSXSL and SAXON.
jing-trang-20131210+dfsg+1/convert/from-trex.xsl000066400000000000000000000044751225366607500212410ustar00rootroot00000000000000 http://www.w3.org/2001/XMLSchema-datatypes interleave jing-trang-20131210+dfsg+1/convert/simplify.xsl000066400000000000000000000014331225366607500211410ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/copying.html000066400000000000000000000033601225366607500174340ustar00rootroot00000000000000 Jing Copying Conditions

Jing Copying Conditions

Copyright (c) 2001-2003 Thai Open Source Software Center Ltd
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

jing-trang-20131210+dfsg+1/copying.txt000066400000000000000000000030211225366607500173010ustar00rootroot00000000000000Copyright (c) 2001-2003 Thai Open Source Software Center Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jing-trang-20131210+dfsg+1/datatype-sample/000077500000000000000000000000001225366607500201665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/build.xml000066400000000000000000000011351225366607500220070ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/datatype-sample/datatype-sample.rng000066400000000000000000000003071225366607500237700ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/datatype-sample/index.html000066400000000000000000000031771225366607500221730ustar00rootroot00000000000000 RELAX NG Pluggable Datatype Library Example

RELAX NG Pluggable Datatype Library Example

This package contains a very simple example of a pluggable datatype library. The datatype library is implemented by the class com.thaiopensource.datatype.sample.BalancedString. The bulk of the implementation is inherited from the abstract class com.thaiopensource.datatype.sample.SimpleDatatypeLibrary, which provides default implementations for the methods in the interfaces which a datatype library must implement. A class that derives from SimpleDatatypeLibrary has only to implement a boolean isValid(String literal) method. The datatype library has the URI http://www.thaiopensource.com/relaxng/datatypes/sample, and contains exactly one datatype, which is called balancedString. This datatype allows any string in which parentheses are properly balanced (nested). To use this sample datatype library, simply include datatype-sample.jar in your CLASSPATH. You will then be able to validate against schemas using this additional datatype. The file datatype-sample.rng is a simple RELAX NG schema using this datatype; valid.xml is an instance that is valid with respect to this schema; invalid.xml is an instance that is not valid with respect to this schema.

James Clark
jing-trang-20131210+dfsg+1/datatype-sample/invalid.xml000066400000000000000000000000561225366607500223370ustar00rootroot00000000000000foo(bar(baz) jing-trang-20131210+dfsg+1/datatype-sample/src/000077500000000000000000000000001225366607500207555ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/META-INF/000077500000000000000000000000001225366607500221155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/META-INF/services/000077500000000000000000000000001225366607500237405ustar00rootroot00000000000000org.relaxng.datatype.DatatypeLibraryFactory000066400000000000000000000000621225366607500342710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/META-INF/servicescom.thaiopensource.datatype.sample.BalancedString jing-trang-20131210+dfsg+1/datatype-sample/src/com/000077500000000000000000000000001225366607500215335ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/com/thaiopensource/000077500000000000000000000000001225366607500245635ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/com/thaiopensource/datatype/000077500000000000000000000000001225366607500263765ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/com/thaiopensource/datatype/sample/000077500000000000000000000000001225366607500276575ustar00rootroot00000000000000BalancedString.java000066400000000000000000000012701225366607500333230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/com/thaiopensource/datatype/samplepackage com.thaiopensource.datatype.sample; public class BalancedString extends SimpleDatatypeLibrary { private static final String DATATYPE_LIBRARY = "http://www.thaiopensource.com/relaxng/datatypes/sample"; private static final String TYPE = "balancedString"; public BalancedString() { super(DATATYPE_LIBRARY, TYPE); System.err.println("Loaded balanced string"); } protected boolean isValid(String literal) { int len = literal.length(); int level = 0; for (int i = 0; i < len; i++) { switch (literal.charAt(i)) { case '(': ++level; break; case ')': if (--level < 0) return false; break; } } return level == 0; } } SimpleDatatypeLibrary.java000066400000000000000000000037571225366607500347310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/datatype-sample/src/com/thaiopensource/datatype/samplepackage com.thaiopensource.datatype.sample; import org.relaxng.datatype.*; import org.relaxng.datatype.helpers.ParameterlessDatatypeBuilder; import org.relaxng.datatype.helpers.StreamingValidatorImpl; public abstract class SimpleDatatypeLibrary implements Datatype, DatatypeLibrary, DatatypeLibraryFactory { private final String uri; private final String localName; private final DatatypeBuilder datatypeBuilder; protected SimpleDatatypeLibrary(String uri, String localName) { this.uri = uri; this.localName = localName; this.datatypeBuilder = new ParameterlessDatatypeBuilder(this); } public DatatypeLibrary createDatatypeLibrary(String uri) { return this.uri.equals(uri) ? this : null; } public DatatypeBuilder createDatatypeBuilder(String localName) throws DatatypeException { if (!this.localName.equals(localName)) throw new DatatypeException(); return datatypeBuilder; } public Datatype createDatatype(String localName) throws DatatypeException { return createDatatypeBuilder(localName).createDatatype(); } protected abstract boolean isValid(String literal); public void checkValid(String literal, ValidationContext context) throws DatatypeException { if (!isValid(literal, context)) throw new DatatypeException(); } public boolean isValid(String literal, ValidationContext context) { return isValid(literal); } public DatatypeStreamingValidator createStreamingValidator(ValidationContext context) { return new StreamingValidatorImpl(this, context); } public Object createValue(String literal, ValidationContext context) { if (!isValid(literal, context)) return null; return literal; } public boolean sameValue(Object obj1, Object obj2) { return obj1.equals(obj2); } public int valueHashCode(Object obj) { return obj.hashCode(); } public int getIdType() { return ID_TYPE_NULL; } public boolean isContextDependent() { return false; } } jing-trang-20131210+dfsg+1/datatype-sample/valid.xml000066400000000000000000000000571225366607500220110ustar00rootroot00000000000000foo(bar(baz)) jing-trang-20131210+dfsg+1/doc/000077500000000000000000000000001225366607500156415ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/doc/04-05-03.xsl000066400000000000000000000172141225366607500172630ustar00rootroot00000000000000 <xsl:value-of select="head/title"/> James Clark
Thai Open Source Software Center Thailand jjc@thaiopensource.com http://www.thaiopensource.com
James Clark has been involved with SGML and XML for more than 10 years, both in contributing to standards and in creating open source software. James was technical lead of the XML WG during the creation of the XML 1.0 Recommendation. He was editor of the XPath and XSLT Recommendations. He was the main author of the DSSSL (ISO 10179) standard. Currently, he is chair of the OASIS RELAX NG TC and editor of the RELAX NG specification. The open source software that James has written includes SGML parsers (sgmls and SP), a DSSSL implementation (Jade), XML parsers (expat and XP), an XPath/XSLT processor (XT), a RELAX NG validator (Jing), a schema conversion tool (Trang), and an XML mode for GNU Emacs (nXML mode). Prior to his involvement with SGML and XML, James wrote the GNU groff typesetting system. James read Mathematics and Philosophy at Merton College, Oxford, where he obtained First Class Honours. James lives in Thailand, where he runs the Thai Open Source Software Center.
<xsl:apply-templates/>
  • < xmlns=" " xmlns: =" " > </ > /> > </ > =" " =" "

    jing-trang-20131210+dfsg+1/doc/compact/000077500000000000000000000000001225366607500172675ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/doc/compact/index.html000066400000000000000000000015671225366607500212750ustar00rootroot00000000000000 RELAX NG Compact Syntax

    RELAX NG Compact Syntax

    The RELAX NG Compact Syntax is compact, non-XML syntax for RELAX NG. It is now defined by an OASIS Committee Specification.

    The following tools provide support for the syntax:

    James Clark
    jing-trang-20131210+dfsg+1/doc/compact/relaxng-for-xsd.rnc000066400000000000000000000061341225366607500230170ustar00rootroot00000000000000# A schema for RELAX NG syntax staying within the # expressive power of W3C XML Schema. default namespace rng = "http://relaxng.org/ns/structure/1.0" namespace local = "" datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" start = pattern patternNotChoice = element element { nameQName?, commonAttributes, foreignElement*, nameClassOrPattern, foreignElement*, (patternAfterNameClass, foreignElement*)* } | element attribute { nameQName?, commonAttributes, foreignElement*, (nameClassOrPattern, foreignElement*, (patternAfterNameClass, foreignElement*)?)? } | element group|interleave|optional |zeroOrMore|oneOrMore|list|mixed { oneOrMorePatternsType } | element ref|parentRef { nameNCName, common } | element empty|notAllowed|text { common } | element data { type, commonAttributes, foreignElement*, (param, foreignElement*)*, (exceptPattern, foreignElement*)? } | element value { commonAttributes, type?, xsd:string } | element externalRef { href, common } | element grammar { grammarType } oneOrMorePatternsType = commonAttributes, foreignElement*, (pattern, foreignElement*)+ grammarType = commonAttributes, foreignElement*, (grammarContent, foreignElement*)* pattern = patternNotChoice | element choice { oneOrMorePatternsType } patternAfterNameClass = patternNotChoice | choice nameClassOrPattern = nameClassNotChoice | patternNotChoice | choice choice = element choice { commonAttributes, foreignElement*, (nameClassOrPattern, foreignElement*)+ } param = element param { commonAttributes, nameNCName, xsd:string } exceptPattern = element except { oneOrMorePatternsType } grammarContent = definition | element div { grammarType } | element include { href, includeType } includeContent = definition | element div { includeType } includeType = commonAttributes, foreignElement*, (includeContent, foreignElement*)* definition = element start { combine?, oneOrMorePatternsType } | element define { nameNCName, combine?, oneOrMorePatternsType } combine = attribute combine { "choice" | "interleave" } nameClassNotChoice = element name { commonAttributes, xsd:QName } | element anyName|nsName { commonAttributes, foreignElement*, (exceptNameClass, foreignElement*)? } nameClass = nameClassNotChoice | element choice { oneOrMoreNameClassType } exceptNameClass = element except { oneOrMoreNameClassType } oneOrMoreNameClassType = commonAttributes, foreignElement*, (nameClass, foreignElement*)+ nameQName = attribute name { xsd:QName } nameNCName = attribute name { xsd:NCName } href = attribute href { xsd:anyURI } type = attribute type { xsd:NCName } common = commonAttributes, foreignElement* commonAttributes = attribute ns { xsd:string }?, attribute datatypeLibrary { xsd:anyURI }?, foreignAttributes foreignElement = element * - rng:* { anyAttributes, (text | anyElement)* } foreignAttributes = attribute * - (rng:*|local:*) { text }* anyElement = element * { anyAttributes, (text | anyElement)* } anyAttributes = attribute * { text }* jing-trang-20131210+dfsg+1/doc/compact/relaxng.rnc000066400000000000000000000040731225366607500214370ustar00rootroot00000000000000# RELAX NG syntax expressed in non-XML syntax. default namespace rng = "http://relaxng.org/ns/structure/1.0" namespace local = "" datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" start = pattern pattern = element element { (nameQName | nameClass), (common & pattern+) } | element attribute { (nameQName | nameClass), (common & pattern?) } | element group|interleave|choice|optional |zeroOrMore|oneOrMore|list|mixed { common & pattern+ } | element ref|parentRef { nameNCName, common } | element empty|notAllowed|text { common } | element data { type, param*, (common & exceptPattern?) } | element value { commonAttributes, type?, xsd:string } | element externalRef { href, common } | element grammar { common & grammarContent* } param = element param { commonAttributes, nameNCName, xsd:string } exceptPattern = element except { common & pattern+ } grammarContent = definition | element div { common & grammarContent* } | element include { href, (common & includeContent*) } includeContent = definition | element div { common & includeContent* } definition = element start { combine?, (common & pattern+) } | element define { nameNCName, combine?, (common & pattern+) } combine = attribute combine { "choice" | "interleave" } nameClass = element name { commonAttributes, xsd:QName } | element anyName { common & exceptNameClass? } | element nsName { common & exceptNameClass? } | element choice { common & nameClass+ } exceptNameClass = element except { common & nameClass+ } nameQName = attribute name { xsd:QName } nameNCName = attribute name { xsd:NCName } href = attribute href { xsd:anyURI } type = attribute type { xsd:NCName } common = commonAttributes, foreignElement* commonAttributes = attribute ns { xsd:string }?, attribute datatypeLibrary { xsd:anyURI }?, foreignAttribute* foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* } foreignAttribute = attribute * - (rng:*|local:*) { text } anyElement = element * { (anyAttribute | text | anyElement)* } anyAttribute = attribute * { text } jing-trang-20131210+dfsg+1/doc/compact/syntax.html000066400000000000000000000005321225366607500215030ustar00rootroot00000000000000 Compact Syntax for RELAX NG

    Compact Syntax for RELAX NG

    The compact syntax is now described by the RELAX NG Compact Syntax Committee Specification.

    jing-trang-20131210+dfsg+1/doc/derivative.xml000066400000000000000000001014761225366607500205360ustar00rootroot00000000000000 ]> An algorithm for RELAX NG validation

    An algorithm for RELAX NG validation

    James Clark (jjc@thaiopensource.com)

    2002-02-13

    This document describes an algorithm for validating an XML document against a RELAX NG schema. This algorithm is based on the idea of what's called a derivative (sometimes called a residual). It is not the only possible algorithm for RELAX NG validation. This document does not describe any algorithms for transforming a RELAX NG schema into simplified form, nor for determining whether a RELAX NG schema is correct.

    We use Haskell to describe the algorithm. Do not worry if you don't know Haskell; we use only a tiny subset which should be easily understandable.

    Basics

    First, we define the datatypes we will be using. URIs and local names are just strings.

    type Uri = String type LocalName = String

    A ParamList represents a list of parameters; each parameter is a pair consisting of a local name and a value.

    type ParamList = [(LocalName, String)]

    A Context represents the context of an XML element. It consists of a base URI and a mapping from prefixes to namespace URIs.

    type Prefix = String type Context = (Uri, [(Prefix, Uri)])

    A Datatype identifies a datatype by a datatype library name and a local name.

    type Datatype = (Uri, LocalName)

    A NameClass represents a name class.

    data NameClass = AnyName | AnyNameExcept NameClass | Name Uri LocalName | NsName Uri | NsNameExcept Uri NameClass | NameClassChoice NameClass NameClass

    A Pattern represents a pattern after simplification.

    data Pattern = Empty | NotAllowed | Text | Choice Pattern Pattern | Interleave Pattern Pattern | Group Pattern Pattern | OneOrMore Pattern | List Pattern | Data Datatype ParamList | DataExcept Datatype ParamList Pattern | Value Datatype String Context | Attribute NameClass Pattern | Element NameClass Pattern | After Pattern Pattern

    The After pattern is used internally and will be explained later.

    Note that there is an Element pattern rather than a Ref pattern. In the simplified XML representation of patterns, every ref element refers to an element pattern. In the internal representation of patterns, we can replace each reference to a ref pattern by a reference to the element pattern that the ref pattern references, resulting in a cyclic data structure. (Note that even though Haskell is purely functional it can handle cyclic data structures because of its laziness.)

    In the instance, elements and attributes are labelled with QNames; a QName is a URI/local name pair.

    data QName = QName Uri LocalName

    An XML document is represented as a ChildNode. There are two kinds of child node:

    data ChildNode = ElementNode QName Context [AttributeNode] [ChildNode] | TextNode String

    An AttributeNode consists of a QName and a String.

    data AttributeNode = AttributeNode QName String

    Now we're ready to define our first function: contains tests whether a NameClass contains a particular QName.

    contains :: NameClass -> QName -> Bool contains AnyName _ = True contains (AnyNameExcept nc) n = not (contains nc n) contains (NsName ns1) (QName ns2 _) = (ns1 == ns2) contains (NsNameExcept ns1 nc) (QName ns2 ln) = ns1 == ns2 && not (contains nc (QName ns2 ln)) contains (Name ns1 ln1) (QName ns2 ln2) = (ns1 == ns2) && (ln1 == ln2) contains (NameClassChoice nc1 nc2) n = (contains nc1 n) || (contains nc2 n)

    In Haskell, _ is an anonymous variable that matches any argument.

    nullable tests whether a pattern matches the empty sequence.

    nullable:: Pattern -> Bool nullable (Group p1 p2) = nullable p1 && nullable p2 nullable (Interleave p1 p2) = nullable p1 && nullable p2 nullable (Choice p1 p2) = nullable p1 || nullable p2 nullable (OneOrMore p) = nullable p nullable (Element _ _) = False nullable (Attribute _ _) = False nullable (List _) = False nullable (Value _ _ _) = False nullable (Data _ _) = False nullable (DataExcept _ _ _) = False nullable NotAllowed = False nullable Empty = True nullable Text = True nullable (After _ _) = False

    The key concept used by this validation technique is the concept of a derivative. The derivative of a pattern p with respect to a node x is a pattern for what's left of p after matching x; in other words, it is a pattern that matches any sequence that when appended to x will match p.

    If we can compute derivatives, then we can determine whether a pattern matches a node: a pattern matches a node if the derivative of the pattern with respect to the node is nullable.

    It is desirable to be able to compute the derivative of a node in a streaming fashion, making a single pass over the tree. In order to do this, we break down an element into a sequence of components:

    1. a start-tag open containing a QName
    2. a sequence of zero or more attributes
    3. a start-tag close
    4. a sequence of zero or more children
    5. an end-tag

    We compute the derivative of a pattern with respect to an element by computing its derivative with respect to each component in turn.

    We can now explain why we need the After pattern. A pattern After x y is a pattern that matches x followed by an end-tag followed by y. We need the After pattern in order to be able to express the derivative of a pattern with respect to a start-tag open.

    The central function is childNode which computes the derivative of a pattern with respect to a ChildNode and a Context:

    childDeriv :: Context -> Pattern -> ChildNode -> Pattern childDeriv cx p (TextNode s) = textDeriv cx p s childDeriv _ p (ElementNode qn cx atts children) = let p1 = startTagOpenDeriv p qn p2 = attsDeriv cx p1 atts p3 = startTagCloseDeriv p2 p4 = childrenDeriv cx p3 children in endTagDeriv p4

    textDeriv computes the derivative of a pattern with respect to a text node.

    textDeriv :: Context -> Pattern -> String -> Pattern

    Choice is easy:

    textDeriv cx (Choice p1 p2) s = choice (textDeriv cx p1 s) (textDeriv cx p2 s)

    Interleave is almost as easy (one of the main advantages of this validation technique is the ease with which it handles interleave):

    textDeriv cx (Interleave p1 p2) s = choice (interleave (textDeriv cx p1 s) p2) (interleave p1 (textDeriv cx p2 s))

    For Group, the derivative depends on whether the first operand is nullable.

    textDeriv cx (Group p1 p2) s = let p = group (textDeriv cx p1 s) p2 in if nullable p1 then choice p (textDeriv cx p2 s) else p

    For After, we recursively apply textDeriv to the first argument.

    textDeriv cx (After p1 p2) s = after (textDeriv cx p1 s) p2

    For OneOrMore we partially expand the OneOrMore into a Group.

    textDeriv cx (OneOrMore p) s = group (textDeriv cx p s) (choice (OneOrMore p) Empty)

    A text pattern matches zero or more text nodes. Thus the derivative of Text with respect to a text node is Text, not Empty.

    textDeriv cx Text _ = Text

    The derivative of a value, data or list pattern with respect to a text node is Empty if the pattern matches and NotAllowed if it does not.

    To determine whether a value or data pattern matches, we rely respectively on the datatypeEqual and datatypeAllows functions which implement the semantics of a datatype library.

    textDeriv cx1 (Value dt value cx2) s = if datatypeEqual dt value cx2 s cx1 then Empty else NotAllowed textDeriv cx (Data dt params) s = if datatypeAllows dt params s cx then Empty else NotAllowed textDeriv cx (DataExcept dt params p) s = if datatypeAllows dt params s cx && not (nullable (textDeriv cx p s)) then Empty else NotAllowed

    To determine whether a pattern List p matches a text node, the value of the text node is split into a sequence of whitespace-delimited tokens, and the resulting sequence is matched against p:

    textDeriv cx (List p) s = if nullable (listDeriv cx p (words s)) then Empty else NotAllowed

    In any other case, the pattern does not match the node.

    textDeriv _ _ _ = NotAllowed

    To compute the derivative of a pattern with respect to a list of strings, simply compute the derivative with respect to each member of the list in turn.

    listDeriv :: Context -> Pattern -> [String] -> Pattern listDeriv _ p [] = p listDeriv cx p (h:t) = listDeriv cx (textDeriv cx p h) t

    In Haskell, [] refers to the empty list.

    When constructing Choice, Group, Interleave and After patterns while computing derivatives, we recognize the obvious algebraic identities for NotAllowed and Empty:

    choice :: Pattern -> Pattern -> Pattern choice p NotAllowed = p choice NotAllowed p = p choice p1 p2 = Choice p1 p2 group :: Pattern -> Pattern -> Pattern group p NotAllowed = NotAllowed group NotAllowed p = NotAllowed group p Empty = p group Empty p = p group p1 p2 = Group p1 p2 interleave :: Pattern -> Pattern -> Pattern interleave p NotAllowed = NotAllowed interleave NotAllowed p = NotAllowed interleave p Empty = p interleave Empty p = p interleave p1 p2 = Interleave p1 p2 after :: Pattern -> Pattern -> Pattern after p NotAllowed = NotAllowed after NotAllowed p = NotAllowed after p1 p2 = After p1 p2

    The datatypeAllows and datatypeEqual functions represent the semantics of datatype libraries. Here, we specify only the semantics of the builtin datatype library.

    datatypeAllows :: Datatype -> ParamList -> String -> Context -> Bool datatypeAllows ("", "string") [] _ _ = True datatypeAllows ("", "token") [] _ _ = True datatypeEqual :: Datatype -> String -> Context -> String -> Context -> Bool datatypeEqual ("", "string") s1 _ s2 _ = (s1 == s2) datatypeEqual ("", "token") s1 _ s2 _ = (normalizeWhitespace s1) == (normalizeWhitespace s2) normalizeWhitespace :: String -> String normalizeWhitespace s = unwords (words s)

    Perhaps the trickiest part of the algorithm is in computing the derivative with respect to a start-tag open. For this, we need a helper function; applyAfter takes a function and applies it to the second operand of each After pattern.

    applyAfter :: (Pattern -> Pattern) -> Pattern -> Pattern applyAfter f (After p1 p2) = after p1 (f p2) applyAfter f (Choice p1 p2) = choice (applyAfter f p1) (applyAfter f p2) applyAfter f NotAllowed = NotAllowed

    We rely here on the fact that After patterns are restricted in where they can occur. Specifically, an After pattern cannot be the descendant of any pattern other than a Choice pattern or another After pattern; also the first operand of an After pattern can neither be an After pattern nor contain any After pattern descendants.

    startTagOpenDeriv :: Pattern -> QName -> Pattern

    The derivative of a Choice pattern is as usual.

    startTagOpenDeriv (Choice p1 p2) qn = choice (startTagOpenDeriv p1 qn) (startTagOpenDeriv p2 qn)

    To represent the derivative of a Element pattern, we introduce an After pattern.

    startTagOpenDeriv (Element nc p) qn = if contains nc qn then after p Empty else NotAllowed

    For Interleave, OneOrMore Group or After we compute the derivative in a similar way to textDeriv but with an important twist. The twist is that instead of applying interleave, group and after directly to the result of recursively applying startTagOpenDeriv, we instead use applyAfter to push the interleave, group or after down into the second operand of After. Note that the following definitions ensure that the invariants on where After patterns can occur are maintained.

    We make use of the standard Haskell function flip which flips the order of the arguments of a function of two arguments. Thus, flip applied to a function of two arguments f and an argument x returns a function of one argument g such that g(y) = f(y, x).

    startTagOpenDeriv (Interleave p1 p2) qn = choice (applyAfter (flip interleave p2) (startTagOpenDeriv p1 qn)) (applyAfter (interleave p1) (startTagOpenDeriv p2 qn)) startTagOpenDeriv (OneOrMore p) qn = applyAfter (flip group (choice (OneOrMore p) Empty)) (startTagOpenDeriv p qn) startTagOpenDeriv (Group p1 p2) qn = let x = applyAfter (flip group p2) (startTagOpenDeriv p1 qn) in if nullable p1 then choice x (startTagOpenDeriv p2 qn) else x startTagOpenDeriv (After p1 p2) qn = applyAfter (flip after p2) (startTagOpenDeriv p1 qn)

    In any other case, the derivative is NotAllowed.

    startTagOpenDeriv _ qn = NotAllowed

    To compute the derivative of a pattern with respect to a sequence of attributes, simply compute the derivative with respect to each attribute in turn.

    attsDeriv :: Context -> Pattern -> [AttributeNode] -> Pattern attsDeriv cx p [] = p attsDeriv cx p ((AttributeNode qn s):t) = attsDeriv cx (attDeriv cx p (AttributeNode qn s)) t

    Computing the derivative with respect to an attribute done in a similar to computing the derivative with respect to a text node. The main difference is in the handling of Group, which has to deal with the fact that the order of attributes is not significant. Computing the derivative of a Group pattern with respect to an attribute node works the same as computing the derivative of an Interleave pattern.

    attDeriv :: Context -> Pattern -> AttributeNode -> Pattern attDeriv cx (After p1 p2) att = after (attDeriv cx p1 att) p2 attDeriv cx (Choice p1 p2) att = choice (attDeriv cx p1 att) (attDeriv cx p2 att) attDeriv cx (Group p1 p2) att = choice (group (attDeriv cx p1 att) p2) (group p1 (attDeriv cx p2 att)) attDeriv cx (Interleave p1 p2) att = choice (interleave (attDeriv cx p1 att) p2) (interleave p1 (attDeriv cx p2 att)) attDeriv cx (OneOrMore p) att = group (attDeriv cx p att) (choice (OneOrMore p) Empty) attDeriv cx (Attribute nc p) (AttributeNode qn s) = if contains nc qn && valueMatch cx p s then Empty else NotAllowed attDeriv _ _ _ = NotAllowed

    valueMatch is used for matching attribute values. It has to implement the RELAX NG rules on whitespace: see (weak match 2) in the RELAX NG spec.

    valueMatch :: Context -> Pattern -> String -> Bool valueMatch cx p s = (nullable p && whitespace s) || nullable (textDeriv cx p s)

    When we see a start-tag close, we know that there cannot be any further attributes. Therefore we can replace each Attribute pattern by NotAllowed.

    startTagCloseDeriv :: Pattern -> Pattern startTagCloseDeriv (After p1 p2) = after (startTagCloseDeriv p1) p2 startTagCloseDeriv (Choice p1 p2) = choice (startTagCloseDeriv p1) (startTagCloseDeriv p2) startTagCloseDeriv (Group p1 p2) = group (startTagCloseDeriv p1) (startTagCloseDeriv p2) startTagCloseDeriv (Interleave p1 p2) = interleave (startTagCloseDeriv p1) (startTagCloseDeriv p2) startTagCloseDeriv (OneOrMore p) = oneOrMore (startTagCloseDeriv p) startTagCloseDeriv (Attribute _ _) = NotAllowed startTagCloseDeriv p = p

    When constructing a OneOrMore, we need to treat an operand of NotAllowed specially:

    oneOrMore :: Pattern -> Pattern oneOrMore NotAllowed = NotAllowed oneOrMore p = OneOrMore p

    Computing the derivative of a pattern with respect to a list of children involves computing the derivative with respect to each pattern in turn, except that whitespace requires special treatment.

    childrenDeriv :: Context -> Pattern -> [ChildNode] -> Pattern

    The case where the list of children is empty is treated as if there were a text node whose value were the empty string. See rule (weak match 3) in the RELAX NG spec.

    childrenDeriv cx p [] = childrenDeriv cx p [(TextNode "")]

    In the case where the list of children consists of a single text node and the value of the text node consists only of whitespace, the list of children matches if the list matches either with or without stripping the text node. Note the similarity with valueMatch.

    childrenDeriv cx p [(TextNode s)] = let p1 = childDeriv cx p (TextNode s) in if whitespace s then choice p p1 else p1

    Otherwise, there must be one or more elements amongst the children, in which case any whitespace-only text nodes are stripped before the derivative is computed.

    childrenDeriv cx p children = stripChildrenDeriv cx p children stripChildrenDeriv :: Context -> Pattern -> [ChildNode] -> Pattern stripChildrenDeriv _ p [] = p stripChildrenDeriv cx p (h:t) = stripChildrenDeriv cx (if strip h then p else (childDeriv cx p h)) t strip :: ChildNode -> Bool strip (TextNode s) = whitespace s strip _ = False

    whitespace tests whether a string is contains only whitespace.

    whitespace :: String -> Bool whitespace s = all isSpace s

    Computing the derivative of a pattern with respect to an end-tag is obvious. Note that we rely here on the invariants about where After patterns can occur.

    endTagDeriv :: Pattern -> Pattern endTagDeriv (Choice p1 p2) = choice (endTagDeriv p1) (endTagDeriv p2) endTagDeriv (After p1 p2) = if nullable p1 then p2 else NotAllowed endTagDeriv _ = NotAllowed

    Optimizations

    Computing nullable

    The nullability of a pattern can be determined straightforwardly as the pattern is being constructed. Instead of computing nullable repeatedly, it should be computed once when the pattern is constructed and stored as a field in the pattern.

    Interning patterns

    Additional optimizations become possible if it is possible to efficiently determine whether two patterns are equal. We don't want to have to completely walk the structure of both patterns to determine equality. To make efficient comparison possible, we intern patterns in a hash table. Two interned patterns are equal if and only if they are the same object (i.e. == in Java terms). (This is similar to the way that Strings are interned to make Symbols which can be compared for equality using ==.) To make interning possible, there are two notions of identity defined on patterns each with a corresponding hash function:

    To intern patterns, we maintain a set of patterns implemented as a hash table. The hash table used uninterned identity and the corresponding uninterned hash function. When a new pattern is constructed, any subpatterns must first be interned. The pattern is interned by looking it up in the hash table. If it is found, we throw the new pattern away and instead return the existing entry in the hash table. If it is not found, we store the pattern in the hash table before returning it. (This is basically hash-consing.)

    Avoiding exponential blowup

    In order to avoid exponential blowup with some patterns, it is essential for the choice function to eliminate redundant choices. Define the choice-leaves of a pattern to be the concatenation of the choice-leaves of its operands if the the pattern is a Choice pattern and the empty-list otherwise. Eliminating redundant choices means ensuring that the list of choice-leaves of the constructed pattern contains no duplicates. One way to do this is to for choice to walk the choice-leaves of one operand building a hash-table of the set of choice-leaves of that operand; then walk the other operand using this hash-table to eliminate any choice-leaf that has occurred in the other operand.

    Memoization

    Memoization is an optimization technique that can be applied to any pure function that has no side-effects and whose return value depends only on the value of its arguments. The basic idea is to remember function calls. A table is maintained that maps lists of arguments values to previously computed return values for those arguments. When a function is called with a particular list of arguments, that list of arguments is looked up in the table. If an entry is found, then the previously computed value is returned immediately. Otherwise, the value is computed as usual and then stored in the table for future use.

    The functions startTagOpenDeriv, startTagCloseDeriv and endTagDeriv defined above can be memoized efficiently.

    Memoizing textDeriv is suboptimal because although the textDeriv takes the string value of the text node and the context as arguments, in many cases the result does not depends on these arguments. Instead we can distinguish two different cases for the content of an element. One case is that the content contains no elements (i.e. it's empty or consists of just a string). In this case, we can first simplify pattern using a textOnlyDeriv that replaces each Element pattern by NotAllowed. This can be efficiently memoized.

    textOnlyDeriv :: Pattern -> Pattern textOnlyDeriv (After p1 p2) = after (textOnlyDeriv p1) p2 textOnlyDeriv (Choice p1 p2) = choice (textOnlyDeriv p1) (textOnlyDeriv p2) textOnlyDeriv (Group p1 p2) = group (textOnlyDeriv p1) (textOnlyDeriv p2) textOnlyDeriv (Group p1 p2) = interleave (textOnlyDeriv p1) (textOnlyDeriv p2) textOnlyDeriv (OneOrMore p) = oneOrMore (textOnlyDeriv p) textOnlyDeriv (Element _ _) = NotAllowed textOnlyDeriv p = p

    In this case, textOnlyDeriv will always be followed by endTagDeriv, so we can fold the functionality of endTagDeriv into textOnlyDeriv.

    In the other case, the content of the element contains one or more child elements. In this case, any text nodes can match only Text patterns (because of the restrictions in section 7.2 of the RELAX NG specification). The derivative of a Text pattern with respect to a text node does not depend on either the value of the text node or the context. We therefore introduce a mixedTextDeriv function, which can be efficiently memoized, for use in this case.

    mixedTextDeriv :: Pattern -> Pattern mixedTextDeriv (Choice p1 p2) = choice (mixedTextDeriv p1) (mixedTextDeriv p2) mixedTextDeriv (Interleave p1 p2) = choice (interleave (mixedTextDeriv p1) p2) (interleave p1 (mixedTextDeriv p2)) mixedTextDeriv (After p1 p2) = after (mixedTextDeriv p1) p2 mixedTextDeriv (Group p1 p2) = let p = group (mixedTextDeriv p1) p2 in if nullable p1 then choice p (mixedTextDeriv p2) else p mixedTextDeriv (OneOrMore p) = group (mixedTextDeriv p) (choice (OneOrMore p) Empty) mixedTextDeriv Text = Text mixedTextDeriv _ = NotAllowed

    Another important special case of textDeriv that can be memoized efficiently is when we can determine statically that a pattern is consistent with some datatype. More precisely, we can define a pattern p to be consistent with a datatype d if and only if for any two strings s1 s2, and any two contexts c1 c2, if datatypeEqual d s1 c1 s2 c2, then textDeriv c1 p s1 is the same as textDeriv c2 p s2. In this case, we can combine the string and context arguments into a single argument representing the value of the datatype that the string represents in the context; this can be much more efficiently memoized than the general case.

    The attDeriv function can be memoized more efficiently by splitting it into two function. The first function is a startAttributeDeriv function that works like startTagOpenDeriv and depends just on the QName of the attribute. The second stage works in the same way to the case when the children of an element contain a single string.

    Error handling

    So far, the algorithms presented do nothing more than compute whether or not the node is valid with respect to the pattern. However, a user will not appreciate a tool that simply reports that the document is invalid, without giving any indication of where the problem occurs or what the problem is.

    The most important thing is to detect invalidity as soon as possible. If an implementation can do this, then it can tell the user where the problem occurs and it can protect the application from seeing invalid data. If we consider the XML document to be a sequence of SAX-like events, then detecting the error as soon as possible, means that the implementation must detect when an initial sequence s of events is such that there is no valid sequence of events that starts with s.

    This is straightforward with the algorithm above. Detecting the error as soon as possible is equivalent to detecting when the current pattern becomes NotAllowed. Note that this relies on the choice, interleave, group and after functions recognizing the algebraic identities involving NotAllowed. The current pattern immediately before it becomes NotAllowed describes what was expected and can be used to diagnose the error.

    It some scenarios it may be sufficient to produce a single error message for an invalid document, and to cease validation as soon as it is determined that the document is invalid. In other scenarios, it may desirable to attempt to recover from the error and continute validation so as to find subsequent errors in the document. Jing recovers from validation errors as follows:

    References

    Dongwon Lee, Murali Mani, Makoto Murata. Reasoning about XML Schema Languages using Formal Language Theory. 2000. See http://citeseer.nj.nec.com/lee00reasoning.html.

    Janusz A. Brzozowski. Derivatives of Regular Expressions. Journal of the ACM, Volume 11, Issue 4, 1964.

    Mark Hopkins. Regular Expression Package. Posted to comp.compilers, 1994. Available from ftp://iecc.com/pub/file/regex.tar.gz.

    jing-trang-20131210+dfsg+1/doc/derivative.xsl000066400000000000000000000032221225366607500205320ustar00rootroot00000000000000

           

    Table of contents


    jing-trang-20131210+dfsg+1/doc/design.rng000066400000000000000000000005301225366607500176200ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/doc/design.xml000066400000000000000000001222141225366607500176360ustar00rootroot00000000000000 The Design of RELAX NG JamesClark
    Thai Open Source Software Center Ltd Bangkok Thailand jjc@thaiopensource.com
    James Clark has been involved with SGML and XML for more than 10 years, both in contributing to standards and in creating open source software. James was technical lead of the XML WG during the creation of the XML 1.0 Recommendation. He was editor of the XPath and XSLT Recommendations. He was the main author of the DSSSL (ISO 10179) standard. Currently, he is chair of the OASIS RELAX NG TC and editor of the RELAX NG specification. The open source software that James has written includes SGML parsers (sgmls and SP), a DSSSL implementation (Jade), XML parsers (expat and XP), an XPath/XSLT processor (XT) and a RELAX NG validator (Jing). Prior to his involvement with SGML and XML, James wrote the GNU groff typesetting system. James read Mathematics and Philosophy at Merton College, Oxford, where he obtained First Class Honours. James lives in Thailand, where he runs the Thai Open Source Software Center.
    RELAX NG is a new schema language for XML. This paper discusses various aspects of the design of RELAX NG including the treatment of attributes, datatyping, mixed content, unordered content namespaces, cross-references and modularity.
    The latest version of this paper is available at .
    Introduction RELAX NG is a schema language for XML, based on TREX and RELAX . At the time of writing, RELAX NG is being standardized in OASIS by the RELAX NG Technical Committee (TC). A tutorial and language specification have been published by the TC. This paper describes the thinking behind the design of RELAX NG. It represents the personal views of the author and is not the official position of the TC.
    Evolution of DTDs RELAX NG is an evolution and generalization of XML DTDs . It shares the same grammar-based paradigm. Based on experience with SGML and XML, RELAX NG both adds and subtracts features relative to XML DTDs. The evolutionary nature of RELAX NG has a number of advantages. XML DTDs can be automatically converted into RELAX NG . Experts in designing SGML and XML DTDs will find their skills transfer to designing RELAX NG. Design patterns that are used in XML DTDs can be used in RELAX NG. Overall, RELAX NG is much more mature and it is possible to have a higher degree of confidence in its design than it would be if it were based on a completely different paradigm.
    Schema structure A major goal of RELAX NG is that it be easy to learn and easy to use. One aspect of RELAX NG that promotes this is that the schema can follow the structure of the document. Nesting of patterns in the schema can be used to model nesting of elements in the instance. There is no need to flatten the natural hierarchical structure of the document into a list of element declarations, as you would have to do with DTDs (although RELAX NG allows such flattening if the schema author chooses).
    Declarations and definitions An XML DTD consists of a number of top-level declarations. Each declaration associates a name (the left hand side of the declaration) with some kind of object (the right hand side of the declaration). With some kinds of declaration (e.g. ELEMENT, ATTLIST) the name on the left hand side occurs in the instance, for others (parameter entity declarations) the name is purely internal to the DTD. Similarly, W3C XML Schema distinguishes between definitions and declarations. The name of a declaration occurs in an instance, whereas names of definitions are internal to the schema. RELAX NG avoids this complexity. RELAX NG has, in the terminology of W3C XML Schema, only definitions. There is no concept of a declaration. Names on the left hand side of a definition are always internal to the schema. Names occurring in the instance always occur only within the right hand side of a definition. This approach comes from XDuce .
    Composability RELAX NG is designed to be highly composable. A schema language (or indeed a programming language) provides a number of atomic objects and a number of methods of composition. The methods of composition can be used to combine atomic objects into compound objects which can in turn be composed into further compound objects. The composability of the language is the degree to which the various methods of composition can be applied uniformly to all the various objects of the language, both atomic and compound. For example, RELAX NG provides a choice element that can be applied uniformly to elements, attributes, datatypes and enumerated values. This is not mere syntactic overloading. The choice element has a single uniform semantic in all these cases and can have a single implementation. Another example is the grammar element, which is the container for definitions. The grammar element is just another pattern and can be composed in just the same way as other patterns. Composability improves ease of learning and ease of use. Composability also tends to improve the ratio between complexity and power: for a given amount of complexity, a more composable language will be more powerful than a less composable one.
    Closure A property related to composability is closure. RELAX NG is closed under union: for any two RELAX NG schemas, there is a RELAX NG schema for its union. RELAX NG's composability makes the construction of the union trivial: just wrap the two schemas in a choice element. Closure under union implies that the content model of an element can be context dependent. This is a major difference from XML DTDs, which requires an element of the particular name to use the same content model throughout the document. The design of RELAX NG is informed by the theory of finite tree automata ; this makes closure possible and ensures that implementations can be efficient, despite the major increase in expressive power.
    XML syntax RELAX NG uses XML instance syntax to express schemas. Although this makes for a rather verbose schema language, it has some major advantages. Since a user of an XML schema language must necessarily already learn XML instance syntax, using XML instance syntax for the schema language reduces the learning burden on a schema user. It also allows XML tools and technologies to be applied to the schema. For example, a schema can be used to specify the syntax of the schema language. Another important benefit of XML syntax is extensibility. RELAX NG has an open syntax that allows the RELAX NG defined elements and attributes to be annotated with elements and attributes from other namespaces. RELAX NG DTD Compatibility uses this annotation mechanism to extend RELAX NG with a mechanism for declaring default values for attributes. RelaxNGCC uses this annotation mechanism to allow users to embed Java code in RELAX NG schemas, which gets executed as an XML document is parsed against the schema. An unofficial non-XML syntax for RELAX NG has also been developed . The non-XML syntax can be used for authoring RELAX NG schemas by hand and can then be transformed into the standard RELAX NG XML syntax for interchange.
    Attributes One of the questions most frequently asked by newcomers to the SGML and XML world is how to choose whether to use an attribute or element to represent something. Reasonable people differ on the answer to this question. In many cases, the choice is somewhat arbitrary and is largely a matter of the taste of the document designer. RELAX NG therefore aims to treat attributes as uniformly as possible with elements. In this respect RELAX NG is very different from many XML schema languages such as XML DTDs, W3C XML Schema and RELAX, which each provide separate facilities for dealing with elements and with attributes. This aspect of RELAX NG comes from TREX. One inspiration for this was XSLT and XPath, which are two successful technologies that take an approach that is even-handed as between elements and attributes. This uniform treatment is a significant factor in simplifying the language: there is one set of facilities that is applied uniformly to elements and attributes rather than two distinct sets of facilities. The mechanism that RELAX NG uses to give attributes uniform treatment to attributes is to extend DTD-style content models to include attributes as well as elements. The content of an XML element consists a sequence of elements and strings. Accordingly, a model for the content of an XML element can be understood to be denoting a set of such sequences. The XML DTD content model operators (|,*+?) correspond to operations on such sets. For example, the choice operator (|) corresponds to set union. To extend content models to include attributes, we first augment the content of an XML element with its attributes; instead of the content of an element, we use an attribute-set/content pair. The content is a sequence of elements and strings as before. The attribute set is a set of name/value pairs. An extended content model thus denotes a set of attribute-set/content pairs. Each of the content model operators can be applied in a natural way to these sets of pairs. For example, the choice operator corresponds to set union just as before. The sequence operator (,) concatenates the content sequences occurring in its operands, but unions the attribute-sets. This ensures that the extended content models respect the unorderedness of attributes. At first, it might seem that the repetition operators (*+) make no sense for attributes, but in fact, when wildcards are allowed for attribute names, repetition of attributes becomes necessary. Although the theory underlying extended content models is a little tricky, in practice they are both easy to use and very powerful. The extension of content models to handle attributes creates a difficulty for attribute defaulting. For example, if the content model allows either attribute A or attribute B or neither attribute, how would attribute defaulting handle the absence of both attribute A and attribute B? Would defaulting add an attribute A or an attribute B? RELAX NG's solution is simply not to do attribute defaulting. Attribute defaulting is a kind of transformation: a transformation that adds attributes. But it is a very limited kind of transformation. Not only can it do nothing but add attributes, but it can only add an attribute when the value of the attribute to be added does not depend on the context, although it is often necessary for attributes to be defaulted in a context-dependent way, for example by inheritance. Although there is certainly a need for special-purpose transformation languages, it is not clear why this kind of transformation should alone be privileged by being included in a schema language. Omission of attribute defaulting is also consistent with the policy of equal treatment for elements and attributes. W3C XML Schema provides defaulting for both elements and attributes, but its defaulting for elements is quite different from its defaulting for attributes: defaulting for elements adds content to elements that were specified as empty, whereas defaulting for attributes adds attributes that were not specified at all. For compatibility with XML DTDs, RELAX NG DTD Compatibility defines an annotation that can be used to specify default attributes values. However, this can only be used for content models that do not go beyond XML DTDs in their use of attributes.
    Infoset modification The omission of support for default attributes from RELAX NG is part of a general policy in RELAX NG of not modifying or augmenting the infoset . RELAX NG validation does not involve changing the information about the document that is passed to an application. One reason for this is that the processes of validation and infoset modification need to be capable of being performed independently. In some situations, there is a need to ensure that a document is valid with respect to some schema but no need to perform any additional processing at that stage and hence no need for an augmented infoset. In other situations, a document is already known to be valid but an augmented infoset is needed for additional processing. The fact the RELAX NG validation does not involve infoset modification does not imply that applications cannot derive useful information from RELAX NG schemas. For example, it is possible to use a RELAX NG schema to assign types to elements and attributes; Sun's Multi-Schema Validator supports this. Type assignment requires additional restrictions on RELAX NG schemas beyond those imposed by RELAX NG itself. There is a range of possible restrictions that can be imposed to facilitate type assignment: the more severe the restriction, the easier type assignment becomes; assigning types to elements which can contain subelements requires different restrictions than merely assigning datatypes to the string values of element and attributes. By layering type assignment on top of RELAX NG validation, applications that do not require type assignment do not need to pay the cost for a feature that they do not use. It is also more flexible. For example, it allows there to be two schemas for a document: one strict schema that captures as many constraints as possible but does not satisfy the restrictions necessary for type assignment and another looser schema that cannot express all the constraints but which can be used for type assignment. One advantage to not performing type assignment with RELAX NG is that RELAX NG works well with existing APIs such as DOM and SAX. Type assignment would require major changes to report the types assignment to elements and attributes.
    Datatyping XML DTDs have a built-in, limited, rather ad hoc set of datatypes, which can be applied only to the values of attributes and not to the content of elements. RELAX NG differs in two major respects. Firstly, it allows datatypes to be specified uniformly for both attribute values and element content; this is in accordance with the philosophy of uniform treatment for elements and attributes. Secondly, RELAX NG decouples the schema language from the set of datatypes. RELAX NG is not tied to a single set of datatypes. The philosophy of RELAX NG is, like XML, to restrict itself purely to syntax. This restriction allows RELAX NG to be both simple and general. Defining specific datatypes is not simply a matter of syntax but involves semantics as well. The issue of what datatypes are useful is both more application-dependent and more open-ended than the purely syntactic issues that RELAX NG deals with. Instead, RELAX NG introduces the concept of a datatype library, which provides a semantic model for a collection of datatypes. Any collection of datatypes that can fit into the RELAX NG semantic model can potentially be used as a RELAX NG datatype library. In particular, the datatypes defined by W3C XML Schema Part 2 can be used as a datatype library; the RELAX NG TC has published a set of guidelines for this in order to promote interoperability. A vendor-independent Java interface has been developed for datatype libraries . Any collection of datatypes implemented using this interface can be dynamically plugged in to any RELAX NG validator that supports this interface. W3C XML Schema Part 2 defines both a collection of primitive datatypes and methods for deriving datatypes. With RELAX NG, the functionality relating to specific primitive datatypes is factored out into independent datatype libraries. However, the functionality relating to deriving datatypes is included in RELAX NG. W3C XML Schema Part 2 provides three methods for deriving datatypes. Derivation by restriction is provided in RELAX NG by allowing a reference to a datatype in a datatype library to specify a list of named parameters. Derivation by union is provided in RELAX NG by allowing the choice element to be applied to datatypes just as it is to elements or attributes. Derivation by list is provided in RELAX NG by the list element. The list element allows the normal RELAX NG content model operators (group, interleave, choice, oneOrMore, zeroOrMore, optional) to be used for specifying the sequence of tokens comprising the list. It is more powerful than the W3C XML Schema Part 2, which allows only a minimum and maximum length for the number of tokens in the sequence to be specified .
    Mixed content SGML does not restrict the occurrence of #PCDATA in content models. However, SGML suffers from the infamous pernicious mixed content bug, which causes certain content models involving #PCDATA to treat whitespace between tags as significant in surprising ways. This bug in SGML motivated XML to drastically restrict the use of #PCDATA in content models. Unfortunately, this prohibits many perfectly reasonable content models. RELAX NG restores the generality of SGML by removing the restriction on #PCDATA. (In RELAX NG, #PCDATA is represented by a text element.) It solves the pernicious mixed content bug by observing that the pernicious mixed content bug only arises in SGML because SGML parsers need to report whether whitespace is significant and insignificant. RELAX NG does no modify or augment the infoset and it therefore does not need to decide whether whitespace in mixed content is significant. RELAX NG can therefore lift the restriction imposed by XML without reintroducing the problem that motivated the imposition of the restriction.
    Unordered content SGML provides an & operator: A & B matches A followed by B or B followed by A. XML removed the & operator. RELAX NG reintroduces it with a twist. In SGML, a content model of A & B* requires all the B elements to be consecutive: the required A element cannot occur in between two B elements. Usually, users use the & operator because they want to allow child elements to occur in any order, so this restriction is undesirable. In RELAX NG, the corresponding operator has interleaving semantics. It matches any interleaving of a sequence containing a single A element and a sequence containing zero or more B elements; it thus allows the A element to occur anywhere, including between two B elements. XML removed the & operator mainly because of the & operator's reputation for implementation complexity. The most difficult part of implementing the & operator in SGML is detecting whether a content model including & is 1-unambiguous. Unlike SGML, XML and W3C XML Schema, RELAX NG does not restrict content models to be 1-unambiguous, so this implementation difficulty is removed. The classic implementation technique for SGML and XML content models is to construct a Glushkov automaton. The 1-unambiguity restriction is helpful for this technique because it ensures that the Glushkov automaton is deterministic. An interleaving operator causes difficulty with this technique. However, there is an alternative implementation technique available based on derivatives of regular expressions . This handles content models that are not 1-unambiguous without any additional effort and can deal with interleaving without difficulty. RELAX NG imposes restrictions on the use of interleave which are sufficient to ensure that a derivative-based implementation will not exhibit exponential behavior.
    Namespaces The XML Namespaces Recommendation was published after the XML 1.0 Recommendation. XML Namespaces are layered on top of XML 1.0 and do not affect the semantics of XML 1.0 including the semantics of DTD validation. This means that DTD validation is not namespace-aware: it treats prefixes of element and attribute names as significant. On a namespace-aware view, it is the namespace URIs to which the prefixes are bound that should be significant rather than the prefixes themselves. RELAX NG validation is namespace-aware. For many applications of XML, namespaces are critical. However, there are also many other uses of XML, particularly in closed environments, where namespaces are not needed. RELAX NG therefore tries to ensure that none of the complexity related to namespaces affects users that do not make use of the namespaces support. The mechanisms introduced by the XML Namespaces Recommendation are purely syntactic. The XML 1.0 Recommendation provides a syntax for representing a tree of elements and attributes in which each element and attribute is labeled with a simple, unstructured name. The XML Namespaces Recommendation extends this to allow the label of elements and attributes to be qualified with a namespace URI. This is all it does . It makes no guarantees that the namespace URI refers to anything. The namespace URI is just part of the label of an element or attribute. RELAX NG takes this same syntactic view. It makes no assumptions about the usage of XML namespaces that go beyond what is specified in the XML Namespaces Recommendation. This contrasts with the approach of W3C XML Schema, which assumes that a namespace URI is associated with a schema. The advantages of the RELAX NG approach are simplicity and generality. RELAX NG has no problems representing vocabularies such as XSLT and RDF that make atypical use of XML namespaces. The purpose of XML Namespaces is to enable extensibility. Extensions defined by a particular organization can be clearly identified by using a namespace URI controlled by that organization. To support this, a schema language needs to be able to specify that a schema is open to various kinds of extension at various points. For example, a schema language needs to be able to say that an arbitrary attribute is allowed on an element provided the name of the attribute is namespace qualified. RELAX NG provides very general support for this through the idea of a name class. A name class denotes a set of names, where a name is a pair consisting of a namespace URI and a local name. There are three kinds of atomic name class: a single specific name, any name with a particular namespace URI and any name whatsoever. Name classes can be composed using set union and set difference. RDF provides a good example of where this flexibility is needed: in RDF the name of an element specifying a property can be anything with a non-null namespace URI except rdf:Description, rdf:RDF, rdf:ID, rdf:about, rdf:aboutEach, rdf:bagID, rdf:parseType or rdf:resource. An important feature of RELAX NG is that the name of an element is specified independently of its attributes and content. When the name of an element is specified as an open name class, all the normal facilities of RELAX NG remain available for specifying its attributes and content. For example, in XSLT an element such as xsl:if can contain certain specific elements from the XSLT namespace and arbitrary elements from non-XSLT namespaces. These non-XSLT elements specify literal result elements; although the names of these elements can be from any non-XSLT namespace, their contents have the same constraints as elements from the XSLT namespace such as xsl:if. RELAX NG's support for extensibility avoids making any assumptions about what extensibility policies are appropriate for schemas, but instead provides general facilities that are sufficient to describe almost any extensibility policy that a schema author may choose.
    Customization The main mechanism provided by XML DTDs for customization is overriding the parameter entity definitions. RELAX NG also supports definition overriding, but provides two improvements. One is that RELAX NG makes the order of definitions within a grammar insignificant. A definition is not required to come before references to that definition. Overriding definitions are distinguished by being placed within the include element that references the schema containing the overridden definition, in a similar fashion to the internal subset of a DOCTYPE declaration. This gives schema authors the freedom to order their definitions as they see fit. It also makes it explicit when a definition is overriding another definition. The other improvement is that RELAX NG allows multiple definitions to be combined together. This is similar to the way that XML 1.0 DTDs allow multiple attribute list declarations for a single element type. Unlike XML 1.0 DTDs, RELAX NG requires schema authors to indicate explicitly when a definition is to be combined (by using a combine attribute) and allows combination of arbitrary patterns using either the interleave or choice operator rather than restricting the facility to just attributes.
    Inheritance One of the most significant differences between RELAX NG and W3C XML Schema is that RELAX NG does not have any concept of inheritance. The support for inheritance in W3C XML Schema is probably the major contributor to the considerable complexity of W3C XML Schema Part 1. Yet, the inheritance mechanisms in W3C XML Schema do not allow W3C XML Schema to express any constraints that cannot be expressed in RELAX NG. Although W3C XML Schema has a very complex type system with two type hierarchies, one for elements (called substitution groups) and one for complex types, it supports only single inheritance. However, modern object-oriented languages, such as Java and C#, support multiple inheritance (at least for interfaces). Thus, in general the inheritance structure of a class hierarchy cannot be represented in a schema. Inheritance has proven to be very useful in modeling languages such as UML. However, I would argue that trying to make an XML schema language also be a modeling language is not a good idea. An XML schema language has to be concerned with syntactic details, such as whether to use elements or attributes, which are irrelevant to the conceptual model. Instead, I believe it is better to use a standard modeling language such as UML, which provides full multiple inheritance, to do conceptual modeling, and then generate schemas and class definitions from the model . If a schema language is used in this way, then there is no need for it to support inheritance; the role of the schema language is purely to describe the XML syntax used to represent the conceptual model. RELAX NG has the advantage in this role that it provides more flexibility in the choice of syntax. For example, in W3C XML Schema the xsi:type attribute is a special case; it is the only attribute that can affect the content model of an element. In RELAX NG, any attribute can affect the content model in a quite general way. Thus, in situations where W3C XML Schema forces the use of the xsi:type attribute, RELAX NG allows the schema designer to choose the attribute name (or indeed choose to use a subelement instead of an attribute).
    Identity constraints The RELAX NG TC spent a considerable amount of time considering what support RELAX NG should provide for enforcing identity (uniqueness and cross-reference) constraints. In the end, the conclusion was that identity constraints were better separated out into a separate specification. Accordingly, RELAX NG itself provides no support for identity constraints. RELAX NG DTD Compatibility provides support for traditional XML ID/IDREF attributes. There were a number of reasons for preferring separation. One reason is the relative difference in maturity. RELAX NG is based on finite tree automata; this is an area of computer science that has been studied for many years and is accordingly mature and well understood. The use of grammars for specifying document structures is based on more than 15 years of practical experience. By contrast, the area of identity constraints (beyond simple ID/IDREF constraints) is much less mature and is still the subject of active research. Another reason is that it is often desirable to perform grammar processing separately from identity constraint processing. For example, it may be known that a particular document is valid with respect to a grammar but not known that it satisfies identity constraints. The type system of the language that was used to generate a document may well be able to guarantee that it is valid with respect to the grammar; it is unlikely that it will be able to guarantee that it satisfies the identity constraints. A document assembled from a number of components may guaranteed to be valid with respect to a grammar because of the validity of the components, but this will often not be the case with identity constraints. Even when a document is known to satisfy the identity constraints as well as be valid with respect to the grammar, it may be necessary to perform identity constraint processing in order to allow application programs to follow references. Another reason is that no single identity constraint language is suitable for all applications. Different applications have identity constraints of vastly different complexity. Some applications have complex constraints that span multiple documents . Other applications need only a modest increment on the XML ID/IDREF mechanism. A solution that is sufficient for those applications with complex requirements is likely to be overkill for those applications with simpler requirements. W3C XML Schema provides a quite sophisticated identity-constraint mechanism. However, it has something of the feel of a specification within a specification. An element or attribute in the instance that participates in an identity constraint plays one of three roles: it can be a scope in which the constraint is enforced; it can be a target, which is an object which is unique in the scope; or it can be a field, which is part of the key which identifies the target within its scope. In W3C XML Schema, the target and field are identified using an XPath. However, the scope is identified by including the identity constraint specification in the declaration of the scoping element. This leads to the restriction that although identity constraints are hierarchical, there is no way to specify a reference to a key in another part of the hierarchy. A better approach would be to use a path also to specify the scope, thus completely decoupling the specification of identity constraints from the rest of the schema and opening the way to more complete constraints on key references.
    Associating schemas with documents With XML 1.0, the XML document uses a DOCTYPE declaration to identify the DTD with respect to which it is valid. There is no provision for a document to be validated with respect to DTD that is specified independently of the document. This is unsatisfactory for interchange. When a document recipient receives a document from an untrusted sender, the recipient may need to check that the document is valid with respect to a particular DTD. The recipient cannot assume that the DOCTYPE declaration of the document correctly identifies that DTD. The recipient may want to validate against a DTD different from that used by the author: for example, the recipient may validate against a generalized, public DTD, whereas the author may validate against a restrictive, private DTD that is a subset of the public DTD. Unlike XML 1.0, RELAX NG does not tie a document to a single schema. The RELAX NG validation process has two inputs: a document and a schema against which to validate the document. In fact, RELAX NG does not define any mechanism for associating a document with a RELAX NG schema. Although it is useful to be able to specify rules for determining the schema to be used to validate a particular document, this problem is not specific to RELAX NG. Validation is just one of many processes that can be applied to an XML document. For example, a user may wish to perform XInclude processing or XSLT processing. A user may wish to perform validation before or after any of these other processes. The problem of associating a schema with a document is really just a special case of the problem of associating processing with a document. What is needed is a solution that can specify a series of processes to be applied to a document.
    Database NULLs XML users coming from the database world sometimes wish to represent database NULLs explicitly in an XML document. There are two plausible ways that a document might do this. One is to use an attribute to signal that an element has null content. This requires that the schema language be able to specify a choice between data and the presence of a particular attribute. Another way is to use an element to signal that an element has null content. This requires that the schema language be able to specify a choice between data and the presence of a particular element. W3C XML Schema does not meet either of the above requirements; thus without some special treatment for database NULLs, it would be awkward to explicitly represent database NULLs in document. W3C XML Schema provides a special built-in xsi:nil attribute to deal with this. The situation with RELAX NG is different. RELAX NG can handle both of the above requirements. Thus, there is no need for RELAX NG to provide any special facility for database NULLs. If it is desired to standardize a representation of NULL, then this can be done without changing RELAX NG. Indeed, it is possible for RELAX NG explicitly to model the semantics of xsi:nil that are built-in to W3C XML Schema.
    Conclusion RELAX NG is designed to complement the XML 1.0 and XML Namespaces Recommendations. It is easy to learn and use, and has a level of complexity in the implementation and specification that is in the same ballpark as these Recommendations. It has a limited scope chosen on the basis of careful consideration of issues of modularity and layering. In particular, it restricts itself to dealing purely with syntax, and is thus, like XML itself, applicable to a wide range of application domains. It is a conservative, evolutionary refinement of well-proven ideas from SGML and XML DTDs. It is non-intrusive and aims to avoid unnecessarily constraining the freedom of schema authors to design their XML vocabularies as they see fit.
    Murata Makoto and other members of the OASIS RELAX NG TC participated in the design of RELAX NG. Paul V. Biron, Ashok Malhotra, editors. XML Schema Part 2: Datatypes. W3C (World Wide Web Consortium), 2001. See
    . Tim Bray, Dave Hollander, and Andrew Layman, editors. Namespaces in XML. W3C (World Wide Web Consortium), 1999. See . Tim Bray, Jean Paoli, and C. M. Sperberg-McQueen, Eve Maler, editors. Extensible Markup Language (XML) 1.0 Second Edition. W3C (World Wide Web Consortium), 2000. See . Janusz A. Brzozowski. Derivatives of Regular Expressions. Journal of the ACM, Volume 11, Issue 4, 1964. Dave Carlson. Modeling XML Vocabularies with UML. 2001. See . James Clark. DTDinst. Thai Open Source Software Center, 2001. Available from . James Clark. XML Namespaces. 1999. See . James Clark. RELAX NG Non-XML Syntax. Thai Open Source Software Center, 2001. See . James Clark. TREX - Tree Regular Expressions for XML. Thai Open Source Software Center, 2001. See . James Clark, KAWAGUCHI Kohsuke. Datatype interface for RELAX NG. Available from . James Clark, KAWAGUCHI Kohsuke, editors. Guidelines for using W3C XML Schema Datatypes with RELAX NG. OASIS, 2001. See . James Clark, MURATA Makoto, editors. RELAX NG DTD Compatibility. OASIS, 2001. See . James Clark, MURATA Makoto, editors. RELAX NG Specification. OASIS, 2001. See . James Clark, MURATA Makoto, editors. RELAX NG Tutorial. OASIS, 2001. See . H. Comon, M. Dauchet, R. Gilleron, F. Jacquemard, D. Lugiez, S. Tison and M. Tommasi. Tree Automata Techniques and Applications. 1997. Available at . John Cowan, Richard Tobin, editors. XML Information Set. W3C (World Wide Web Consortium), 2001. See . Joe English. How to validate XML. 1999. See . Haruo Hosoya. XDuce: A Typed XML Processing Language. See . KAWAGUCHI Kohsuke. Sun Multi-Schema XML Validator. Available from . MURATA Makoto. RELAX (Regular Language description for XML). INSTAC (Information Technology Research and Standardization Center), 2001. See . Jonathan Marsh, David Orchard, editors. XML Inclusions (XInclude) Version 1.0. W3C (World Wide Web Consortium), 2001. See . Christian Nentwich, Wolfgang Emmerich and Anthony Finkelstein. xlinkit: links that make sense. Department of Computer Science, University College London, 2001. See . Daisuke Okajima. RelaxNGCC (RelaxNG compiler compiler). 2001. See . Henry S. Thompson, David Beech, Murray Maloney, Noah Mendelsohn, editors. XML Schema Part 1: Structures. W3C (World Wide Web Consortium), 2001. See .
    jing-trang-20131210+dfsg+1/doc/design.xsl000066400000000000000000000053331225366607500176460ustar00rootroot00000000000000

    Abstract

    Note:

    <xsl:value-of select="gcapaper/front/title"/>

    ( )

    Table of contents


    Acknowledgements

    References

    section:

    [ ] jing-trang-20131210+dfsg+1/doc/implement.html000066400000000000000000000022461225366607500205250ustar00rootroot00000000000000 Notes on implementing RELAX NG

    Notes on implementing RELAX NG

    This page contains pointers to documents describing various aspects of implementing RELAX NG.

    The following are available:

    • a description of how to implement validation using an algorithm based on the idea of a derivative; this corresponds to the algorithm implemented in Jing
    • notes on how to handle the tricky parts of simplifying the full syntax into simple syntax, specifically how to deal with grammar, define, ref and parentRef
    • a note on how to detect whether two name classes overlap

    For some background on implementing validation of schemas in XML, see Taxonomy of XML Schema Languages using Formal Language Theory.

    James Clark
    jing-trang-20131210+dfsg+1/doc/index.html000066400000000000000000000056171225366607500176470ustar00rootroot00000000000000 RELAX NG

    RELAX NG

    RELAX NG is the name for the unification of two XML schema languages:

    The specification for RELAX NG has been developed by the OASIS RELAX NG TC.

    The following are available:

    • Jing, a validator for RELAX NG implemented in Java. This is written on top of SAX2.
    • Trang, a program for converting between different schema languages, focused on RELAX NG; in particular, it can convert between the compact and XML syntaxes, it can convert between RELAX NG and DTDs, and it can convert from RELAX NG to W3C XML Schema
    • DTDinst, a program for producing an XML instance representation of XML DTDs; this is also used by Trang for converting from XML DTDs into RELAX NG
    • Namespace Routing Language (NRL), a XML language for combining schemas for multiple namespaces. Jing implements this.
    • The Design of RELAX NG, a paper discussing the design of RELAX NG
    • Notes on implementing RELAX NG validators. These describe the implementation techniques used in Jing.
    • A RELAX NG schema for RELAX NG.
    • A RELAX NG implementation of XHTML modularization.
    • A RELAX NG schema for XSLT 1.0 stylesheets.
    • An XSLT stylesheet that converts from RELAX Core into RELAX NG. This should be able to handle any correct RELAX Core module, but it does not implement the RELAX Core semantic of implicitly allowing undeclared attributes. (However, the sample implementation is capable of recovering from such errors.) Handling the RELAX include feature requires an extension over XSLT 1.0; the stylesheet can currently use the extensions implemented in either MSXML or SAXON; it can be easily adapted to any other conforming XSLT processor that supports a result tree fragment to node set conversion function. This stylesheet will not work with XT, since XT does not implement keys. There's also an auxiliary stylesheet that removes some redundancies generated by the previous stylesheet.
    • A RELAX NG schema for RELAX Core, including the schema for datatypes. This was generated using the above stylesheets from the RELAX module for RELAX core, and then hand-edited a bit.
    • A test suite for RELAX NG.
    James Clark
    jing-trang-20131210+dfsg+1/doc/jing-ant.html000066400000000000000000000036711225366607500202450ustar00rootroot00000000000000 Jing task for Ant

    Jing task for Ant

    Ant is a Java based build tool, which is becoming the build tool of choice for Java-based projects. Ant project files are written in XML.

    Ant can be extended with new tasks. The Jing task for Ant allows you to efficiently validate multiple files against multiple RELAX NG patterns and integrate RELAX NG validation with other XML processing.

    This version of the Jing task has bee tested with version 1.7.1 of Ant.

    To use the Jing task, you must include a taskdef in your project file.

    <taskdef name="jing" classname="com.thaiopensource.relaxng.util.JingTask"/>

    The jing task has a required rngfile attribute which specifies the file containing the RELAX NG pattern. The files to be validated can be specified in two ways: the jing element may have a file attribute specifying a single file to be validated; alternatively, the jing element may have one or more fileset child elements specifying sets of files to be validated. For example:

    <project name="example" default="validate" basedir=".">
    
      <taskdef name="jing" classname="com.thaiopensource.relaxng.util.JingTask"/>
    
      <target name="validate">
        <jing rngfile="xslt.rng">
          <fileset dir="xsl" includes="**/*.xsl"/>
        </jing>
      </target>
    
    </project>

    The jing task also has two optional boolean attributes:

    compactsyntax
    if true, uses the compact syntax for the schema; default is false
    checkid
    if true, checks for ID/IDREF/IDREFS compatibility; default is true

    When invoking Ant, you must ensure that jing.jar is in your class path.

    jing-trang-20131210+dfsg+1/doc/jing-bin/000077500000000000000000000000001225366607500173365ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/doc/jing-bin/copying.html000066400000000000000000000051221225366607500216740ustar00rootroot00000000000000 Jing Copying Conditions

    Jing Copying Conditions

    Copyright (c) 2001-2003, 2008 Thai Open Source Software Center Ltd
    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    • Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    Third-party JARs

    This distribution includes some additional JAR files, which have their own copying conditions:

    saxon.jar
    Comes from the Saxon 6.5.5 distribution and is covered by these conditions
    xercesImpl.jar
    xml-apis.jar
    Come from the Xerces2 Java 2.9.1 distribution. The former is covered by the Apache License Version 2.0
    isorelax.jar
    Comes from ISO RELAX 2004/11/11 distribution and is covered by the MIT license
    jing-trang-20131210+dfsg+1/doc/jing-bin/readme.html000066400000000000000000000052631225366607500214670ustar00rootroot00000000000000 Jing version @VERSION@

    Jing version @VERSION@

    Copyright © 2001, 2002, 2003, 2008 Thai Open Source Software Center Ltd. Jing can be freely copied subject to these conditions.

    This directory contains version @VERSION@ of Jing, a validator for RELAX NG and other schema languages.

    The directory bin contains jing.jar, which contains the code for Jing, ready to use with a Java runtime. For more information on how to use Jing, see this document.

    Apart from jing.jar, the bin directory contains some third-party jar files, which are used for XML parsing (under a pre-1.4 JRE that does not provide the Java XML parsing extension) and for validating with schema languages other than RELAX NG:

    saxon.jar
    Comes from the Saxon 6.5.5 distribution. Used for Schematron 1.5 validation.
    xercesImpl.jar
    xml-apis.jar
    Come from the Xerces2 Java 2.9.1 distribution. Used for W3C XML Schema validation and for XML parsing. Xerces2 Java is under the Apache License Version 2.0, which requires the following notice:
       Apache Xerces Java
       Copyright 1999-2007 The Apache Software Foundation
    
       This product includes software developed at
       The Apache Software Foundation (http://www.apache.org/).
    
       Portions of this software were originally based on the following:
         - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.
         - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.
         - voluntary contributions made by Paul Eng on behalf of the 
           Apache Software Foundation that were originally developed at iClick, Inc.,
           software copyright (c) 1999.
    isorelax.jar
    Comes from ISO RELAX 2004/11/11 distribution. Provides a bridge to validators that use the JARV interface.

    The file src.zip contains the Java source code. This is for reference purposes, and doesn't contain the supporting files, such as build scripts and test cases, that are needed for working conveniently with the source code. If you want to make changes to Jing, you should check out the source code and supporting files from the project's Subversion repository.

    jing-trang-20131210+dfsg+1/doc/jing-datatypes.html000066400000000000000000000032131225366607500214510ustar00rootroot00000000000000 Jing support for XML Schema Datatypes

    Jing support for XML Schema Datatypes

    Jing contains a built-in implementation of the W3C XML Schema Part 2 Recommendation. Jing follows the Guidelines for using W3C XML Schema Datatypes with RELAX NG.

    The implementation of the pattern facet (and of some of the more complicated datatypes) requires an implementation of regular expressions as defined in XML Schema Part 2. Jing provides implementations based on:

    • the standard Java java.util.regex package (included in Java in versions 1.4 and later)
    • Xerces2-J

    Jing will automatically use the first of the above implementations for which the necessary classes are available on your CLASSPATH.

    You can interface a different implementation of XML Schema regular expressions by implementing the interface com.thaiopensource.datatype.xsd.RegexEngine. Jing finds an implementation of this interface using the service provider technique: a JAR file containing an implementation of this interface must contain a file META-INF/services/com.thaiopensource.datatype.xsd.RegexEngine that contains the name of class that implements the interface. Jing will automatically find and use the implementation if the JAR file is added to the CLASSPATH.

    jing-trang-20131210+dfsg+1/doc/jing-other.html000066400000000000000000000062731225366607500206050ustar00rootroot00000000000000 Jing support for other schema languages

    Jing support other schema languages

    In addition to RELAX NG (both XML and compact syntax), Jing has support for some other schema languages. This support is less mature than the RELAX NG support. These schema languages all use XML and Jing can autodetect using the namespace URI of the document element. However, if you use the -c option, no autodetection will be performed and the schema will be parsed as RELAX NG compact syntax.

    Jing has support for the following schema languages:

    Schematron 1.5
    Jing's implementation is not based on the reference Schematron 1.5 implementation. It is implemented partly in XSLT and partly in Java. This implementation requires that the Schematron elements be properly namespaced using the namespace URI http://www.ascc.net/xml/schematron. Jing can report correct line numbers both for errors in the instance and errors in the schema (including XPath errors). It can use either Saxon or Xalan as its XSLT engine. Jing is distributed with Saxon, because JDK 1.4 includes an old version of Xalan, which does not work properly for this application, and it is tricky to prevent the JRE using this version. A command-line option of -d enables diagnostics. A command-line option of -p phase specifies the phase to use. Both reports and failed assertions are considered errors. The Schematron schema is subject to rather more rigorous checking (using a RELAX NG schema) than with the reference Schematron implementation.
    W3C XML Schema
    Jing provides support for W3C XML Schema using a wrapper around Xerces2-J. Any xsi:schemaLocation and xsi:noNamespaceSchemaLocation hints in the instance are ignored.
    Namespace Routing Language (NRL)
    The XML Namespaces Recommendation allows an XML document to be composed of elements and attributes from multiple independent namespaces. Each of these namespaces may have its own schema; the schemas for different namespaces may be in different schema languages. NRL is an experimental language for specifying how the schemas for the different namespaces are to be composed in order to allow validation of the complete document. The implementation in Jing fully supports the language described in the specification. Subschemas can be in any of the languages supported by Jing (including, recursively, NRL). Jing does not yet support the schema option for W3C XML Schema subschemas, which would allow more than one schema URI to be specified.
    Modular Namespaces (MNS)
    MNS is the predecessor to NRL, and should be considered obsolescent. MNS support will disappear in a future release.
    James Clark
    jing-trang-20131210+dfsg+1/doc/jing.html000066400000000000000000000174411225366607500174650ustar00rootroot00000000000000 Jing

    Jing

    A RELAX NG validator in Java

    Copyright © 2001, 2002, 2003, 2008 Thai Open Source Software Center Ltd

    See the file copying.html for copying permission.

    Version @VERSION@

    This version of Jing implements

    Jing also has experimental support for schema languages other than RELAX NG; specifically

    A separate document describes this support in more detail.

    Jing has a command-line user interface. It has no graphical user interface.

    Jing is available for download as the file jing-@VERSION@.zip, which contains binaries, source code and documentation. It requires a Java runtime compatible with the Java 2 Platform, Standard Edition (J2SE) version 1.4 (or any later version), such as the Java Runtime Environment (JRE), which can be downloaded here.

    The latest version of Jing will always be available in the Downloads section of the project site.

    Once you have installed a suitable Java runtime, you can run Jing by using the command:

    java -jar jing.jar options schema XMLfile...

    where schema is the name of the file containing the schema, and XMLfile... are the names of one or more XML files to be validated against this schema, and options are zero or more options. If schema is correct, and each XMLfile... is valid with respect to schema, then Jing will generate no output. Otherwise, it will generate one or more error messages.

    The following options are available:

    -c
    The schema uses RELAX NG Compact Syntax.
    -e enc
    Uses the encoding enc to read the schema.
    -f
    Checks that the document is feasibly valid. A document is feasibly valid if it could be transformed into a valid document by inserting any number of attributes and child elements anywhere in the tree. This is equivalent to transforming the schema by wrapping every data, list, element and attribute element in an optional element and then validating against the transformed schema. This option may be useful while a document is still under construction. This option also disables checking that for every IDREF there is a corresponding ID.
    -i
    Disables checking of ID/IDREF/IDREFS. By default, Jing enforces the constraints imposed by RELAX NG DTD Compatibility with respect to ID/IDREF/IDREFS.
    -t
    Prints the time used by Jing for loading the schema and for validation.

    When you use jing.jar with the -jar option, any jar files that have the same names as the jar files included with the Jing download and are in the same directory as jing.jar will be used automatically (i.e. they will be added to the classpath), specifically:

    • xercesImpl.jar
    • xml-apis.jar
    • saxon.jar
    • isorelax.jar

    Note that, when using the -jar option, the JRE will ignore any additional class path entries specified by the -cp or -classpath options or by the CLASSPATH environment variable.

    If you do not want use the -jar option (perhaps because you want to use some other .jar files not included with with Jing), then you must explicitly include all the needed .jar files with a -cp or -classpath option or with the CLASSPATH environment variable, and specify the main class name as com.thaiopensource.relaxng.util.Driver. For example, on Linux you could do you could do:

    java -classpath path-to-dist/jing-@VERSION@/bin/jing.jar com.thaiopensource.relaxng.util.Driver file.rng file.xml
    

    This would use just jing.jar and the standard Java classes.

    Jing uses a vendor-independent pluggable datatypes API that allows datatype libraries to be added at runtime and be interoperable with Java-based RELAX NG implementation that supports the API.

    Jing also includes an implementation of a datatype library for the W3C XML Schema Part 2 datatypes. There is a separate document describing this implementation and how to use it.

    If you wish to use Jing in your programs, you have a choice.

    • You can use Jing's native API.
    • You can use JARV (Java API for RELAX Verifiers). JARV is part of the ISO-RELAX SourceForge project. Jing's implementation uses the 20041111 version. Support for DTD Compatibility validation of ID/IDREF and for validation with languages other than RELAX NG is not currently available via this interface.

    There is a Jing task that allows Jing to be invoked by the Ant build tool.

    Development of Jing, together with Trang, takes place in the jing-trang project, which is hosted on Google Code.

    If you find a bug or would like to request an enhancement, please create a new issue in the Issues section of the project site. You can talk with other users of Jing on the rng-users mailing list.

    If you want to make changes to Jing, you should check out the source code from the project's Subversion repository. (The source code included in the Jing download is for reference purposes, and doesn't contain the supporting files, such as build scripts and test cases, that are needed for working conveniently with the source code.)

    James Clark
    jing-trang-20131210+dfsg+1/doc/mns.html000066400000000000000000000620211225366607500173250ustar00rootroot00000000000000 Modular Namespaces (MNS)

    Modular Namespaces (MNS)

    Author:
        James Clark (Thai Open Source Software Center) <jjc@thaiopensource.com>
    Date:
        2003-01-31

    Copyright © 2003 Thai Open Source Software Center Ltd

    Contents


    Introduction

    The XML Namespaces Recommendation allows an XML document to be composed of elements and attributes from multiple independent namespaces. Each of these namespaces may have its own schema. The problem then arises of how the schemas can be composed in order to allow validation of the complete document.

    In RELAX Namespace, Murata Makoto pioneered the idea of dividing the document into islands, with each island containing a single namespace, and validating each island separately against the schema for its namespace. RELAX Namespace formed the basis for the recently published Committee Draft of Document Schema Definition Languages (DSDL) -- Part 4: Selection of Validation Candidates.

    This document presents a language named Modular Namespaces (MNS), which is an evolution of the ideas in RELAX Namespace and DSDL Part 4. RELAX Namespace was designed to work well with RELAX Core. RELAX Core cannot deal with documents that use multiple namespaces, nor does it provide any namespace-based wildcards. These limitations of RELAX Core are reflected in the design of RELAX Namespace. MNS is designed to be able to take advantage of more recent schema languages, such as RELAX NG, that are not limited in this way.

    A sample implementation of MNS is included in Jing.

    It is hoped that this will be a useful contribution to the future development of DSDL Part 4.

    Basics

    In its simplest form, a MNS schema consists of a mapping from namespace URIs to schema URIs. An MNS schema is written in XML. Here is a RELAX NG compact syntax schema for this simplest form of MNS schema:

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start =
      element rules {
        schemaType?,
        element validate {
          schemaType?,
          attribute ns { xsd:anyURI },
          attribute schema { xsd:anyURI }
        }*
      }
    
    schemaType = attribute schemaType { mediaType }
    mediaType = xsd:string
    

    Validity of an instance with respect to a MNS schema is determined as follows. First, a set of validation subjects is identified. Each validation subject is an element in the instance. Associated with each validation subject is a schema. If all the validation subjects are valid with respect to their associated schemas, then the instance is considered valid with respect to the MNS schema.

    It is important to understand that when a validation subject is validated with respect to its schema, then it is validated along with all its descendants and attributes. One validation subject may have other validation subjects as ancestors. In this case, a validation subject will be validated with respect to more than one schema. Not only will it be validated with respect to its schema, but it will also be validated as part of validation of ancestor validation subjects with respect to their schemas.

    An element is a validation subject if it has no parent or if its namespace URI is different from that of its parent. A validation subject must have a validate rule for its namespace URI: there must be a validate element whose ns attribute is the same as the validate subject's namespace URI. The value of the ns attribute of the validate element can be the empty string to specify the absent namespace URI.

    The associated schema is specified by the schema attribute of the validate element. The schema can be in any language supported by the particular implementation. When the schema is XML, the language of the schema is detected from the namespace URI of the document element. When the schema is not XML, then MNS relies on the MIME type of the result of fetching the URI; the schemaType attribute can be used to specify the MIME type explicitly. A MIME type of application/x-rnc can be used for RELAX NG compact syntax. The schemaType attribute on the rules element specifies the default value of of the schemaType on validate element. Note that the schema attribute may refer to another MNS schema.

    MNS has additional features that provide further control over the selection of validation subjects and their associated schemas.

    Should it be possible to put the schema inline in the MNS wrapped in, say, a schema element? How does this impact extensibility?

    Should MNS have an include element? The ability to recursively reference MNS maybe makes this unnecessary.

    Lax processing

    Sometimes it may be desirable to allow elements from namespaces for which there are no validate rules. This can be done by adding an empty lax element to the rules element:

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start = element rules { schemaType?, (validate* & lax?) }
    
    validate =
      element validate {
        schemaType?,
        attribute ns { xsd:anyURI },
        attribute schema { xsd:anyURI }
      }
    
    lax = element lax { empty }
    schemaType = attribute schemaType { mediaType }
    mediaType = xsd:string
    

    We will refer to an element that could be a validation subject if there is an applicable validate element as a potential validation subject. In the absence of a lax element, there must be an applicable validate element for every potential validation subject; with a lax element, there need not be.

    Attributes

    Attributes can also be validation subjects:

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start = element rules { schemaType?, (validate* & lax?) }
    
    validate =
      element validate|validateAttributes {
        schemaType?,
        attribute ns { xsd:anyURI },
        attribute schema { xsd:anyURI }
      }
    
    lax = element lax { attribute allow { "attributes" | "elements" }? }
    schemaType = attribute schemaType { mediaType }
    mediaType = xsd:string
    

    If an element has attributes that are namespace qualified with a namespace URI other than the namespace URI of the element itself, then the set of all attributes on that element with that namespace URI is a potential validation subject. If there is a validateAttributes element for that namespace URI, then it becomes a validation subject. The associated schema is specified by the schema attribute of the validateAttributes element. Unqualified attributes are never validation subjects.

    Lax processing for elements means that a potential validation subject that is an element need not have an applicable validate element. Lax processing for attributes means that a potential validation subject that is an attribute need not have an applicable validateAttributes element. In the absence of a lax element, neither attributes nor elements are processed laxly. By default, the lax element enables lax processing for both elements and attributes. If allow="attributes" is specified, then lax processing is enabled for attributes only; if allow="elements" is specified, then lax processing is enabled for elements only.

    Normally, schema languages (including RELAX NG) validate an element rather than a set of attributes. To work around this, MNS performs parallel transformations on the set of attributes and on the schema. The set of attributes is transformed by attaching the attributes to an element with a particular namespace name and namespace URI. The schema identified by a validateAttributes element is transformed to match. In the case of RELAX NG, when a validateAttributes element specifies a schema of s, MNS actually uses a schema of:

    element * { external "s" }
    

    Validation subjects with multiple namespaces

    By default, an element is a potential validation subject if its namespace URI is different from its parent. This behavior can be changed by adding one or more cover children to validate elements. With the introduction of cover elements, the rule is that an element is a potential validation subject if it is not covered by an ancestor validation subject. Each validation subject has a set of namespace URIs that it covers. A validation subject always covers it own namespace URI. In addition, it covers the namespace URIs specified by the cover elements in its validate element. One obvious case where it is useful for a schema to cover more than one namespace is when a validate refers recursively to an MNS schema.

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start = element rules { schemaType?, (validate* & lax?) }
    
    validate =
      element validate {
        validateModel,
        element cover { nsAtt }*
      }
      | element validateAttributes { validateModel }
    
    validateModel = nsAtt, attribute schema { xsd:anyURI }, schemaType?
    
    lax = element lax { attribute allow { "attributes" | "elements" }? }
    nsAtt = attribute ns { xsd:anyURI }
    
    schemaType = attribute schemaType { mediaType }
    
    mediaType = xsd:string
    

    The set elements covered by a validation subject is determined from the set of namespace URI that it covers by the following two rules:

    • a validation subject covers itself;
    • an element is covered by a validation subject if its parent element and its namespace URI is covered by that validation subject.

    The rule for attributes is very similar. A set of attributes is a potential validation subject if and only if:

    • the attributes are namespace qualified with a namespace URI different from the namespace URI of the parent element, and
    • the attributes are not covered by an ancestor validation subject.

    Just as with elements, an attribute is covered by an validation subject if its parent element and its namespace URI are covered by that validation subject.

    Note that a validate element is applicable to a potential validation subject only if the namespace URI of the potential validation subject is as specified by the ns attribute. Any cover child elements do not affect this.

    Should there be separate sets of namespaces that cover elements and cover attributes?

    Should it be possible to cover all namespaces except a particular (possibly empty) finite set of namespaces?

    Modes

    The selection of validation subjects and associated schemas may need to be context dependent. For example, not all namespace URIs may be acceptable for the document element, or the document element may need to be validated against a different schema from that used for subtrees with the same namespace URI.

    Context dependence is specified by means of modes.

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start =
      element rules {
        schemaType?,
        attribute startMode { mode }?,
        (validate|lax)*
      }
    
    validate =
      element validate {
        validateModel,
        attribute useMode { mode }?,
        element cover { nsAtt }*
      }
      | element validateAttributes { validateModel }
    
    lax = 
      element lax {
        attribute allow { elementsOrAttributes }?,
        inModesAtt?
      }
    
    validateModel = nsAtt, attribute schema { xsd:anyURI }, inModesAtt?, schemaType?
    
    nsAtt = attribute ns { xsd:anyURI }
    
    schemaType = attribute schemaType { mediaType }
    
    mediaType = xsd:string
    
    inModesAtt = attribute inModes { list { mode+ } }
    
    mode = xsd:NCName | "#default"
    
    elementsOrAttributes =
      list {
        ("elements", "attributes") 
         | ("attributes", "elements") 
         | "elements"
         | "attributes"
         | empty
      }
    

    The selection of validation subjects takes place with respect to a named mode. A mode is named by an NCName. In addition, there is a default mode named #default. The validate and validateAttributes elements have an optional inModes attribute, which specifies the modes in which the elements are applicable. The default value of the inModes attribute is the default mode. It is an error if there is a mode and a namespace URI for which more than one validate or validateAttributes element is applicable. Thus, when an element is selected as a validation subject there is a unique applicable validate element.

    The mode used to select whether a particular element or set of attributes is a validation subject is specified by the useMode attribute of the validate element applicable to the nearest ancestor validation subject. The default value of the useMode attribute is the default mode. If an element or set of attributes has no ancestor validation subject, then the mode used is determined by the startMode attribute on the rules element; the default value of the startMode attribute is also the default mode. Looking at this more procedurally, processing is top-down; the starting mode is specified by the startMode attribute. Within each validation subject element, processing switches to the mode specified by the useMode attribute.

    Whether processing is lax also depends on the mode. The lax element has an inModes attribute that specifies the modes in which they apply. There can be multiple lax elements specifying lax processing for different modes. As usual, the default value of the inModes attribute is the default mode.

    For every mode named in a useMode attribute other than the default mode, there must be at least one validate, validateAttribute or lax element that includes that mode in its inModes attribute. For a mode that allows nothing, either the default mode can be used or a <lax allow="" inModes="m"/> rule can be added. The allowed value of the allow attribute is, in fact, a list of between zero and two distinct tokens from the set elements and attributes.

    Pruning

    We can distinguish between schemas that are open and schemas that are closed. Open schemas allow attributes and elements in other namespaces; closed schemas are not. Sometimes it is necessary to treat a closed schema as open. This can be done by adding a prune attribute to validate. This has the effect of removing all potential validation candidates that are elements or attributes from the subtree before validating the subtree with respect to the schema specified by the validate, according as the value of the prune attribute contains the token elements or attributes.

    attribute prune { elementsOrAttributes }?
    

    More on modes

    Sometimes the processing mode to be used for an element may need to depend on the name of the parent of that element. For example, we might wish to allow elements of a particular namespace only within the XHTML head element and not anywhere else. To do this, one or more context elements are added to the validate element. The content of the context element identifies a context; the useMode attribute identifies a mode to be applied to potential validation subjects in that context. The default value of the useMode attribute is the default mode as usual.

    The context relates to the ancestry of the potential validation subject starting with its parent element and continuing up and including its nearest ancestor validation subject. The context identified by a context element is the union of the contexts identified by each of its children. An element element specifies a parent whose local name is equal to the value of the name attribute and whose namespace is equal to the value of the ns attribute. The namespace must the same as that specified on the validate element or one of its cover elements. The ns attribute is inherited and so it is unnecessary to specify it except when there are cover elements.

    A context of the form:

    <element name="x">
      <element name="y">
        <element name="z"/>
      </element>
    </element>
    

    applies to a potential validation subject with a parent z, a grandparent y and a great grandparent x. A context of the form:

    <root>
      <element name="x"/>
    </root>
    

    applies to a potential validation subject with a parent element x such that that parent element is the nearest ancestor validation subject of that potential validation subject.

    The children of the context elements of a particular validate element must all identify distinct contexts. It is possible for a single potential validation subject to match multiple distinct context children. A context child containing more element elements takes precedence over one containing fewer element elements. Amongst context children containing the same number of element elements, one that has a root element takes precedence over one that does not.

    default namespace = "http://www.thaiopensource.com/ns/mns"
    
    start =
      element rules {
        schemaType?,
        attribute startMode { mode }?,
        (validate|lax)*
      }
    
    validate =
      element validate {
        validateModel,
        useModeAtt?,
        attribute prune { elementsOrAttributes }?,
        element cover { nsAtt }*,
        context*
      }
      | element validateAttributes { validateModel }
    
    context = element context { useModeAtt?, nsAtt?, (rootContext|elementContext)+ }
    
    rootContext = element root { nsAtt?, elementContext }
    
    elementContext =
      element element {
        attribute name { xsd:NCName },
        nsAtt?,
        elementContext?
      }
    
    lax =
      element lax {
        attribute allow { elementsOrAttributes }?,
        inModesAtt?,
      }
    
    validateModel =
      nsAtt,
      attribute schema { xsd:anyURI },
      schemaType?,
      inModesAtt?
    
    nsAtt = attribute ns { xsd:anyURI }
    
    schemaType = attribute schemaType { mediaType }
    
    mediaType = xsd:string
    
    useModeAtt = attribute useMode { mode }
    
    inModesAtt = attribute inModes { list { mode+ } }
    
    mode = xsd:NCName | "#default"
    
    elementsOrAttributes =
      list {
        ("elements", "attributes") 
         | ("attributes", "elements") 
         | "elements"
         | "attributes"
         | empty
      }
    

    Extensibility

    Just as with RELAX NG, foreign elements and attributes can be added to MNS schemas. Thus, the complete MNS schema is as follows:

    namespace local = ""
    default namespace mns = "http://www.thaiopensource.com/ns/mns"
    
    start =
      element rules {
        schemaType?,
        attribute startMode { mode }?,
        ((validate | lax)* & foreign)
      }
    
    validate =
      element validate {
        validateModel,
        useModeAtt?,
        attribute prune { elementsOrAttributes }?,
        ((cover*, context*) & foreign)
      }
      | element validateAttributes { validateModel, foreign }
    
    cover = element cover { nsAtt, foreign }
    
    context = element context {
        useModeAtt?,
        nsAtt?,
        ((rootContext|elementContext)+ & foreign)
      }
    
    rootContext = element root { nsAtt?, (elementContext & foreign) }
    
    elementContext =
      element element {
        nsAtt?,
        attribute name { xsd:NCName },
        (elementContext? & foreign)
      }
    
    lax =
      element lax {
        attribute allow { elementsOrAttributes }?,
        inModesAtt?,
        foreign
      }
    
    validateModel =
      nsAtt,
      attribute schema { xsd:anyURI },
      schemaType?,
      inModesAtt?
    
    nsAtt = attribute ns { xsd:anyURI }
    
    schemaType = attribute schemaType { mediaType }
    
    mediaType = xsd:string
    
    useModeAtt = attribute useMode { mode }
    
    inModesAtt = attribute inModes { list { mode+ } }
    
    mode = xsd:NCName | "#default"
    
    elementsOrAttributes =
      list {
        ("elements", "attributes") 
         | ("attributes", "elements") 
         | "elements"
         | "attributes"
         | empty
      }
    
    foreign =
      (attribute * - (mns:* | local:*) { text }
       | element * - mns:* { anything })*
    
    anything = (text | attribute * { text } | element * { anything })*
    

    Example

    Suppose we want to validate an XHTML document that uses RDF within its head element. The following would do the job:

    <rules xmlns="http://www.thaiopensource.com/ns/mns" startMode="xhtml">
      <validate ns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                schema="rdfxml.rng"
                inModes="rdf"
                useMode="anything"/>
      <validate ns="http://www.w3.org/1999/xhtml"
                schema="xhtml.rng"
                inModes="xhtml"
                prune="elements">
        <context useMode="rdf">
          <element name="head"/>
        </context>
      </validate>
      <lax inModes="anything"/>
    </rules>
    

    Note the following points:

    • We are assuming a XHTML schema that does not allow elements and attributes from other namespaces. We therefore have to prune the XHTML to remove the RDF elements before validating the XHTML.
    • We want the root element to be XHTML not RDF. We therefore use a starting mode that allows only XHTML.
    • We want to allow RDF in the XHTML head element. We therefore specify an appropriate context in the validation element for the XHTML namespace.
    • We do not want to allow RDF anywhere else within the XHTML. Since we have not specified a useMode attribute on the validate element for the XHTML, the useMode attribute will default to the default mode. Since none of our rules apply in the default mode, the default mode will not allow anything.
    • The schema for RDF allows elements and attributes not in the RDF namespace. We do not want any validation of these beyond what is provided by the schema for RDF. We therefore create an anything mode, for which processing is lax and which does not have any validate or validateAttributes rules.

    Comparison with W3C XML Schema

    W3C XML Schema (XSD) includes features for namespace modulariy that are similar in some ways to MNS. Like MNS, XSD validation uses a mapping from namespace URIs to schemas. However, there are important differences.

    • XSD does not mandate a particular way to specify the mapping. Implementations can get the mapping from xsi:schemaLocation attributes in the instance, or it may be supplied by the user. With MNS, the mapping is explicit and implementation independent.
    • XSD requires the schemas for all namespaces to be in a single schema language, namely XSD. MNS allows schema languages to be mixed.
    • In XSD, the mapping from namespace URIs to schemas is context independent and uniform throughout a document. In MNS, the mapping can change with the context.
    • In XSD, a single schema only has a single target namespace. In MNS, a single schema can cover any number of target namespaces.
    • In XSD, schemas must always indicate explicitly where elements and attributes from namespaces other than the target namespace can occur. MNS allows this possibility, but also allows schemas to be retroactively opened up to extension by using the pruning feature.
    jing-trang-20131210+dfsg+1/doc/nameclass.html000066400000000000000000000052031225366607500204750ustar00rootroot00000000000000 RELAX NG name class analysis

    Name class analysis

    A RELAX NG validator has to be able to determine whether two name classes overlap (i.e. whether there is a name that belongs to both name classes). This is needed for implementing sections 7.3 and 7.4 of the spec.

    The basic idea is two test whether any of a representative set of names is a member of both name classes. The representative set of names is chosen such that for any name n that occurs in one or both name classes there is guaranteed to be at least one member r of the representative set of names such that, for each of the two name classes, r is a member of that name class if and only n is also a member of that name class. When constructing a representative set of names for name classes involving anyName or nsName, it is necessary to find a namespace URI or a local name that is not mentioned in either name class. Instead of expending effort of finding such a namespace URI or local name we instead use a string that is not legal as a namespace URI or local name, and hence is guaranteed not to occur in either name class.

    Here's some Haskell code that implements this. This uses datatypes from the description of derivative-based validation.

    overlap :: NameClass -> NameClass -> Bool
    overlap nc1 nc2 =
      any (bothContain nc1 nc2) (representatives nc1 ++ representatives nc2)
    
    bothContain :: NameClass -> NameClass -> QName -> Bool
    bothContain nc1 nc2 qn = contains nc1 qn && contains nc2 qn
    
    representatives :: NameClass -> [QName]
    
    illegalLocalName :: LocalName
    illegalLocalName = ""
    
    illegalUri :: Uri
    illegalUri = "\x1"
    
    representatives AnyName = [QName illegalUri illegalLocalName]
    representatives (AnyNameExcept nc) =
      (QName illegalUri illegalLocalName) : (representatives nc)
    representatives (NsName ns) = [QName ns illegalLocalName]
    representatives (NsNameExcept ns nc) =
      (QName ns illegalLocalName) : (representatives nc)
    representatives (Name ns ln) = [QName ns ln]
    representatives (NameClassChoice nc1 nc2) =
      (representatives nc1) ++ (representatives nc2)
    

    This approach can also be used to determine whether two name classes are equivalent. Two name classes are equivalent if and only if for each member of the representative set of names either both name classes contain that representative name or neither name classe contains it.

    James Clark
    jing-trang-20131210+dfsg+1/doc/nrl.rng000066400000000000000000000052121225366607500171440ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/doc/nrl.xml000066400000000000000000001354251225366607500171700ustar00rootroot00000000000000 Namespace Routing Language (NRL)

    Namespace Routing Language (NRL)

    Author: James Clark <jjc@thaiopensource.com>
    Date: 2003-06-13

    Copyright © Thai Open Source Software Center Ltd

    The XML Namespaces Recommendation allows an XML document to be composed of elements and attributes from multiple independent namespaces. Each of these namespaces may have its own schema; the schemas for different namespaces may be in different schema languages. The problem then arises of how the schemas can be composed in order to allow validation of the complete document. This document proposes the Namespace Routing Language (NRL) as a solution to this problem. NRL is an evolution of the author's earlier Modular Namespaces (MNS) language.

    A sample implementation of NRL is included in Jing.

    Getting started

    In its simplest form, an NRL schema consists of a mapping from namespace URIs to schema URIs. An NRL schema is written in XML. Here is an example:

    We will call a schema referenced by an NRL schema a subschema. In the above example, soap-envelope.xsd is the subschema for the namespace URI http://schemas.xmlsoap.org/soap/envelope/ and xhtml.rng is the subschema for the namespace URI http://www.w3.org/1999/xhtml.

    The absent namespace can be mapped to a schema by using ns="".

    Processing model

    NRL validation has two inputs: a document to be validated and an NRL schema. We will call the document to be validated the instance. NRL validation divides the instance into sections, each of which contains elements from a single namespace, and validates each section separately against the subschema for its namespace.

    Thus, the following instance:

    Document 1

    ...

    Document 2

    ...

    would be divided into three sections, one with the envelope namespace

    and two with the XHTML namespace:

    Document 1

    ...

    Document 2

    ...

    Note that two elements only belong to the same section if they have a common ancestor and if all elements on the path to that common ancestor have the same namespace. Thus, if one of the XHTML documents happened to contain an element from the envelope, it would not be part of the same section as the root element.

    This validation process can be refined in several ways, which are described in the following sections.

    Specifying the schema

    In most cases the schema will be in some namespaced XML vocabulary, and the type of schema can be automatically detected from the namespace URI of the root element. In cases where the schema is not in XML and there is no MIME type information available to determine the type, a schemaType attribute can be used to specify the type. The value of this should be a MIME media type. For RELAX NG Compact Syntax, a value of application/x-rnc should be used.

    With many schema languages, there can be different ways to use a particular schema to validate an instance. For example, Schematron has the notion of a phase; an instance that is valid with respect to a Schematron schema using one phase may not be valid with respect to the same schema in another phase. NRL allows validation to be controlled by specifying a number of options. For example, to specify that validate with respect to xhtml.sch should use the phase named Full, an option could be specified as follows:

    Options may have arguments. Some options do not need arguments. For example, for Schematron there is a http://www.thaiopensource.com/validate/diagnose option. If this option is present, then errors will include Schematron diagnostics; if it is not, then errors will not include diagnostics. With this option, no arg attribute is necessary:

    Options are named by URIs. A number of standard options are defined which all start with the URI http://www.thaiopensource.com/validate/:

    http://www.thaiopensource.com/validate/phase
    Argument is a string, specifying Schematron phase
    http://www.thaiopensource.com/validate/diagnose
    No argument. If present, include Schematron diagnostics in error messages
    http://www.thaiopensource.com/validate/check-id-idref
    No argument. If present, check ID/IDREF in accordance with RELAX NG DTD Compatibility specification.
    http://www.thaiopensource.com/validate/feasible
    No argument. If present, check that the document is feasibly valid. This applies to RELAX NG. A document is feasibly valid if it could be transformed into a valid document by inserting any number of attributes and child elements anywhere in the tree. This is equivalent to transforming the schema by wrapping every data, list, element and attribute element in an optional element and then validating against the transformed schema. This option is useful while a document is still under construction.
    http://www.thaiopensource.com/validate/schema
    Argument is a URI specifying an additional schema to be used for validation. This applies to W3C XML Schema. This option may be specified multiple times, once for each additional schema.

    For convenience, the URI specified by the name attribute may be relative; if it is, it will be resolved relative to the NRL namespace URI. The result is that the standard options above can be specified without the http://www.thaiopensource.com/validate/ prefix. For example,

    Normally, an NRL implementation will make a best-effort attempt to support the specified option and will simply ignore options that it does not understand or cannot support. If it is essential that a particular option is supported, then a mustSupport attribute may be added to the option element:

    If there is a mustSupport attribute and the NRL implementation cannot support the option, it must report an error.

    Concurrent validation

    Multiple validate elements can be specified for a single namespace. The effect is to validate against all of the specified schemas.

    For example, we might have a Schematron schema for XHTML, which makes various checks that cannot be expressed in a grammar. We want to validate against both the Schematron schema and the RELAX NG schema. The NRL schema would be like this:

    Built-in schemas

    Instead of a validate element, you can use an allow element or a reject element. These are equivalent respectively to validating with a schema that allows anything or with a schema that allows nothing.

    For example, the following would allow SVG without attempting to validate it:

    Note that, just as with validate, allow and reject apply to a section not to a whole subtree. Thus, in the above example, if the SVG contained an embedded XHTML section, then that XHTML section would be validated against xhtml.rng.

    Namespace wildcards

    You can use an anyNamespace element instead of a namespace element. This specifies a rule to be used for an element for which there is no applicable namespace rule.

    Namespace wildcards are particularly useful in conjunction with allow and reject. The following will validate strictly, rejecting any namespace for which no subschema is specified:

    In contrast, the following will validate laxly, allowing any namespace for which no subschema is specified:

    The default is to validate strictly. Thus, if there is no anyNamespace rule, then the following rule will be implied:

    Modes

    You can apply different rules in different contexts by using modes. For example, you might want to restrict the namespaces allowed for the root element.

    The rules element for an NRL schema that uses multiple modes does not contain namespace and anyNamespace elements directly. Rather, it contains mode elements that in turn contain namespace and anyNamespace elements. The validate elements can specify a useMode attribute to change the mode in which their child sections are processed. The rules element must have a startMode attribute specifying which mode to use for the root element.

    For example, suppose we want to require that the root element come from http://schemas.xmlsoap.org/soap/envelope/ namespace.

    If a validate element does not specify a useMode attribute, then the mode remains unchanged. Thus, in the above example, child sections inside an XHTML section will be processed in mode body, which does not allow the SOAP namespace; so if the XHTML were to contain a SOAP env:Envelope element, it would be rejected.

    The reject and allow elements can have a useMode attribute as well.

    Related namespaces

    A single subschema may not handle just a single namespace; it may be handle two or more related namespaces. To deal with this possibility, NRL allows the rule for a namespace to specify that elements from that namespace are to be attached to a parent section and be validated together with that parent section.

    Suppose we have RELAX NG schemas for XHTML and for SVG. We could use these directly as subschemas in NRL. But we might prefer instead to use RELAX NG mechanisms to combine these into a single RELAX NG schema. This would allow us conveniently to allow SVG elements only to occur in places where XHTML block and inline elements are allowed and to disallow them in places that make no sense (for example, as children of a ul element). If we have such a combined schema, we could use it as follows:

    This will cause SVG sections occurring within XHTML to be attached to the parent XHTML section and be validated as part of it.

    RDF is another example where attach is necessary. RDF can contain elements from arbitrary namespaces.

    We could use the approach of attaching all namespaces as an alternative solution to the XHTML+SVG example. Instead relying on NRL to reject namespaces other than XHTML and SVG, we can instead attach sections from all namespaces to the XHTML section, and allow the xhtml+svg.rng schema to reject namespaces other than XHTML and SVG.

    Built-in modes

    There is a built-in mode named #attach, which contains just the rule:

    Thus, the last example in the previous section can be simplified to:

    Suppose you are not interested in the namespace-sectioning capabilities of NRL, but you just want to validate a document concurrently against two schemas. The simplest way is like this:

    The useMode="#attach" ensures that the document will be validated as is, rather than divided into sections.

    Similarly, there is a built-in mode named #reject, which contains just the rule:

    and a built-in mode named #allow, which contains just the rule:

    Open schemas

    Up to now, sections validated by one subschema have not participated in the validation of parent sections. Modern schema languages, such as W3C XML Schema and RELAX NG, can use wildcards to allow elements and attributes from any namespace in particular contexts. It is useful to take advantage of this in order to allow one subschema to constrain the contexts in which sections validated by other subschemas can occur. For example, the official schema for http://schemas.xmlsoap.org/soap/envelope/ uses wildcards to specify precisely where elements from other namespaces are allowed: they are allowed as children of the env:Body and env:Header elements but not as children of the env:Envelope element. Our NRL schema bypasses these constraints because the XHTML sections are not seen by the SOAP validation. We can use attach to solve this problem:

    When an XHTML section occurs inside a SOAP section, the XHTML section will participate in two validations:

    • it will be validated independently against the XHTML schema, and
    • it will be attached to the SOAP section and validated together with the SOAP section against the SOAP schema

    Element-name context

    So far we have seen how to make the processing of an element depend on the namespace URIs of its ancestors. NRL also allows the processing to depend on the element names of its ancestors. For example, suppose we wish to allow RDF to occur only as a child of the head element of XHTML. We can do this as follows:

    Any element that takes a useMode attribute can also have one or more context children that override the useMode attribute in specific contexts. The path attribute specifies a test to be applied to the parent element of the section to be processed. The path attribute allows a restricted form of XPath: a list of one or more choices separated by |, where each choice is a list of one or more unqualified names separated by /, optionally preceded by /. It is interpreted like a pattern in XSLT, except that the names are implicitly qualified with the namespace URI of the containing namespace element. When more than one path matches, the most specific is chosen. It is an error to have two or more equally specific paths. The path is tested against a single section not the entire document: a path of /foo means a foo element that is the root of a section; it does not mean a foo element that is the root of the document.

    Attributes

    Up to now, we have considered attributes to be inseparably attached to their parent elements. Although this is the default behaviour is to attach attributes to their parent elements, attributes are in fact considered to be separate sections and can be processed separately. Attributes with the same namespace URI and same parent element are grouped in a single section. Such sections are called attribute sections; sections that contain elements are called element sections.

    A namespace or anyNamespace element can have a match attribute, whose value must be a list of one or two of the tokens attributes and elements. If the value includes the token attributes, the rule matches attribute sections.

    The default behaviours of attaching attributes to their parent elements occurs because the default value of the match attribute is elements and because all of the built-in modes include a rule:

    Most, if not all, XML schema languages do not have any notion of validating a set of attributes; they know only how to validate an XML element. Therefore, before validating an attribute section, NRL transforms it into an XML element by creating a dummy element to hold the attributes. NRL also performs a corresponding transformation on the schema. This is schema-language dependent. For example, in the case of RELAX NG, a schema s is transformed to <element><anyName/> s </element>.

    For example, suppose xmlatts.rng contains a schema for the attributes in the xml: namespace written in RELAX NG:

    preserve default

    An NRL schema could use this as follows:

    Mode inheritance

    One mode can extend another mode. Suppose in our SOAP+XHTML example, we want to allow both SOAP element and XHTML elements to contain RDF. By putting the rule for RDF in its own mode and extending that mode, we can avoid having to specify the rule for RDF twice:

    It is possible to extend a built-in mode. Thus, a mode that validates laxly can be specified simply just by extending #allow. This works because of how wildcards and inheritance interact. Suppose mode x extends mode y; then when using mode x, the following order will be used to search for a matching rule:

    1. a non-wildcard rule in x
    2. a non-wildcard rule in y
    3. a wildcard rule in x
    4. a wildcard rule in y

    The requirement that there is an implicit rule of

    can be restated as a requirement that the default value of the extends attribute is #reject.

    Transparent namespaces

    Many schema languages can deal with the kind of extensibility that involves adding child elements or attributes from different namespaces. A more difficult kind of extensibility is where we need to be able to wrap an extension element around an existing non-extension element. This can arise with namespaces describing templating and versioning. Imagine XHTML inside an XSLT stylesheet: in such a document we might have a ul element containing an xsl:for-each element containing an li element, although the schema for XHTML requires li elements to occur as direct children of ul elements. In such a situation, we need to need to make the XHTML schema unwrap the xsl:for-each element, ignoring its start-tag and end-tag, but not ignoring its content.

    Suppose we have a namespace http://www.example.org/edit containing elements inserted and deleted, which describe edits that have been made to a document, and suppose we want to use these elements inside an XHTML document. The following NRL schema would allow us still to validate the XHTML document.

    When unwrap is applied to an element section e, it ignores the elements in e and their attributes and just processes the child element sections of e; if processing the child element sections causes a section to try to attach to e, it will instead attach to the parent of e. Thus, in the above schema the section from the edit namespace will be ignored, but child sections will be processed according to rules applicable in the xhtml mode. When a edit section has an XHTML child section, then that XHTML child section will be attached to the parent of the edit section (which can only be another XHTML section).

    The above schema does not deal with validating the edit namespace. Let us suppose that inserted and deleted elements cannot nest. Our schema edit.rnc for the edit namespace is just two lines:

    default namespace = "http://www.example.org/edit"
    element inserted|deleted { empty }
    

    The following NRL schema would allow validation of the edit namespace:

    The above schema is still not quite right. Suppose a title element was both inserted and deleted. With the above NRL schema, XHTML validation would see two title elements, which would get an error. We should instead do XHTML validation twice, once including the content of the inserted elements and ignoring the content of the deleted elements and once doing the opposite. We only need to validate the edit elements once. The following NRL schema accomplishes this:

    Related work

    The fundamental idea of dividing the instance into sections, each of which contains elements from a single namespace, and then validating each section separately against the schema for its namespace originated in Murata Makoto's RELAX Namespace. ISO/IEC JTC1/SC34 (the ISO subcommittee responsible for Document Description and Processing Languages) is developing ISO/IEC 19757 Document Schema Definition Languages (DSDL) as a multi-part standard. A Committee Draft (CD) of Part 4: Selection of Validation Candidates, which was based on RELAX Namespace, has been approved. Comments on the CD have been resolved. MNS, the predecessor to NRL, was input to the CD comment resolution process. In response to MNS, Rick Jelliffe produced the Namespace Switchboard, which was also input to the CD comment resolution process. Some of the evolution of NRL from MNS was inspired by the Namespace Switchboard. A Final Committee Draft (FCD) of Part 4 is currently in preparation; NRL will be submitted as input.

    At this stage, no guarantees can be made about how NRL will relate to the FCD. In the opinion of this document's author and of the DSDL Part 4 project editor (Murata Makoto), the functionality is likely to be similar, with the following possible exceptions:

    • There are concerns about Element-name context: some feel it is too complicated; some feel it is too simple.
    • The functionality corresponding to Transparent namespaces, was rejected on the last occasion it was discussed; one reason was the lack of implementation experience. It is hoped that this can be reconsidered in the light of NRL.
    • The functionality provided by the option element in Specifying the schema has not yet been considered for the FCD.

    However, the syntax may well be different. In particular:

    • Names of elements and attributes may be different.
    • Syntactic sugar for modes may be different. The FCD may not provide Mode inheritance. The FCD may use nesting to avoid the need to name modes in some cases.
    • The FCD is expected to provide syntactic sugar for an action equivalent to <attach useMode="x"/>, where x is a built-in mode like #allow except that it allows attributes as well as elements. The idea is to allow subschemas to use empty elements as placeholders.
    • The FCD is expected to provide a schema inclusion mechanism (not just using NRL as a subschema).
    • The FCD is expected to allow inline schemas, for example, by allowing validate to have a schema element containing the schema as an alternative to the schema attribute containing the schema's URL.

    The group working on DSDL (SC34/WG1) welcomes public discussion of DSDL. Comments on NRL would be useful input to the Part 4 FCD preparation process. See the DSDL web site for information on how to make comments.

    Acknowledgements

    Thanks to Murata Makoto and Rick Jelliffe for helpful comments.

    References

    DSDL Web Site, http://www.dsdl.org Committee Draft of Document Schema Definition Languages (DSDL) -- Part 4: Selection of Validation Candidates, http://www.y12.doe.gov/sgml/sc34/document/0363.htm Comment Disposition of Committee Draft Ballot of Document Schema Definition Languages (DSDL) -- Part 4: Selection of Validation Candidates, http://www.y12.doe.gov/sgml/sc34/document/0415.htm Jing, http://www.thaiopensource.com/relaxng/jing.html Namespace Switchboard, http://www.topologi.com/resources/NamespaceSwitchboard.html RELAX Namespace, http://www.y-adagio.com/public/standards/tr_relax_ns/toc.htm RELAX Core, http://www.xml.gr.jp/relax/ RELAX NG, http://relaxng.org RELAX NG Compact Syntax, http://www.oasis-open.org/committees/relax-ng/compact-20021121.html RELAX NG DTD Compatibility, http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html Schematron, http://www.ascc.net/xml/resource/schematron/schematron.html W3C XML Schema, http://www.w3.org/TR/xmlschema-1/ Modular Namespaces (MNS), http://www.thaiopensource.com/relaxng/mns.html

    NRL schema

    NRL elements can be extended with arbitrary attributes provided the attributes are namespace qualified and their namespace is not the NRL namespace; they can also be extended with arbitrary child elements with any namespace (including the absent namespace) other than the NRL namespace. We could provide a RELAX NG schema that fully described NRL, but the extensibility would make the schema harder to understand. So instead we provide a RELAX NG schema (in compact syntax) that does not allow extensibility, and provide an NRL schema to make it extensible.

    Thus, NRL is described by the following NRL schema:

    where nrl.rnc is as follows:

    default namespace = "http://www.thaiopensource.com/validate/nrl"
    
    start =
      element rules {
        schemaType?,
        (rule* | (attribute startMode { modeName }, mode+))
      }
    
    mode =
      element mode {
        attribute name { userModeName },
        attribute extends { modeName }?,
        rule*
      }
    
    rule =
      element namespace {
        attribute ns { xsd:anyURI },
        ruleModel
      }
      | element anyNamespace { ruleModel }
    
    ruleModel = attribute match { elementsOrAttributes }?, actions
    
    elementsOrAttributes =
      list {
        ("elements", "attributes") 
         | ("attributes", "elements") 
         | "elements"
         | "attributes"
      }
    
    actions =
      noResultAction*, (noResultAction|resultAction), noResultAction*
    
    noResultAction =
      element validate {
        attribute schema { xsd:anyURI },
        schemaType?,
        option*,
        modeUsage
      }
      | element allow|reject { modeUsage }
    
    resultAction =
      element attach|unwrap { modeUsage }
    
    option =
      element option {
        attribute name { xsd:anyURI },
        attribute arg { text }?,
        attribute mustSupport { xsd:boolean }?
      }
    
    modeUsage =
      attribute useMode { modeName }?,
      element context {
        attribute path { path },
        attribute useMode { modeName }?
      }*
    
    modeName = userModeName | builtinModeName
    
    userModeName = xsd:NCName
    builtinModeName = "#attach" | "#allow" | "#reject" | "#unwrap"
    
    schemaType = attribute schemaType { mediaType }
    mediaType = xsd:string  # should do better than this
    path =
      xsd:string {
        pattern = "\s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*"
                  ~ "(|\s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*)*"
      }
    

    Formal semantics

    In order to describe the semantics of NRL, it is convenient to construct a new section-based data model. This data model is constructed from the RELAX NG data model. An implementation wouldn't actually have to construct this, but the semantics are simpler to describe in terms of this data model rather than in terms of the RELAX NG data model. Note that the information content is exactly equivalent to the RELAX NG data model.

    There are two kinds of section: attribute sections and element sections. Two attributes belong to the same section iff they have the same parent and the same namespace URI. An element belongs to the same section as its parent iff it has the same namespace URI as its parent. An attribute section is simply a non-empty unordered set of attributes (as in RELAX NG), where each member of the set has the same namespace URI. An element section is a little more complicated. First we need the concept of a node. There are three kinds of node: an element node, a text node and a slot node. An element node has a name, a context (as in RELAX NG), and a list of child nodes. A text node has a string value. A slot node has no additional information; it is merely a placeholder for a element section. A list of child nodes never has two adjacent text nodes and never has two adjacent slot nodes. An element section is a triple <nd, lsa, lle>, where nd is an element node, lsa is a list of unordered sets of attribute sections, and lle is a list of lists of element sections. lsa has one member for each element node in nd. The unordered set of attribute sections that is the n-th member of lsa gives the attributes for the n-th element node in nd (iterating in document order). lle has one member for each slot node in nd. The list of element sections that is the n-th member of lle corresponds to the n-th slot node in nd (iterating in document order).

    An NRL schema consists of a set of modes. A mode consists of a set of rules. A mode maps a section to an action based on the section's namespace URI and on whether the section is an attribute section or an element section. An action can be applied to element sections and attribute sections. An action returns two values, one of which is always error information. When an action is applied to an element section, it returns error information and a (possibly empty) list of element sections. When an action is applied to an attribute section, it returns error information and either an attribute section or an empty list.

    In the NRL syntax, a rule can contain multiple actions. This is represented in the formalization using a Sequence action. The sequence action discards results (other than error information) from the first action. Only two actions can produce results other than error information: attach and unwrap. The NRL syntax allows at most one such action in a rule. When constructing a sequence representing a set of actions in a rule, this action, if any, must be the last action in the sequence.

    Here is a formalization in Haskell:

    type Uri = String
    type LocalName = String
    type QName = (Uri, LocalName)
    type Prefix = String
    type Context = (Uri, [(Prefix, Uri)])
    
    data Node = ElementNode QName Context [Node]
    	  | TextNode String
    	  | SlotNode
    
    type AttributeSection = [(QName, String)]
    
    data ElementSection = ElementSection Node [[AttributeSection]] [[ElementSection]]
    data ElementsOrAttributes = Elements | Attributes
    
    type Mode = ElementsOrAttributes -> Uri -> Action
    
    data Action = Attach Mode
    	    | Reject Mode
    	    | Unwrap Mode
    	    | Allow Mode
    	    | Validate Uri Mode
    	    | Sequence Action Action
    
    data ErrorReport = AttributeError AttributeSection String
    		 | ElementError ElementSection String
    
    type ErrorInfo = [ErrorReport]
    
    data Validated a = Validated ErrorInfo a
    
    applyElementAction :: Action -> ElementSection -> Validated [ElementSection]
    
    applyElementAction (Reject m) e@(ElementSection nd lsa lle) =
       Validated ([ElementError e "namespace rejected"]
                   ++ (errors (plsa m lsa))
                   ++ (errors (plle m lle)))
                 []
    applyElementAction (Attach m) (ElementSection nd lsa lle)
      = listV (elementSectionV nd (plsa m lsa) (plle m lle))
    applyElementAction (Unwrap m) (ElementSection _ _ lle) = ple m (concat lle)
    applyElementAction (Allow m) (ElementSection nd lsa lle)
      = valid2 (\x y -> []) (plsa m lsa) (plle m lle)
    applyElementAction (Validate s m) (ElementSection nd lsa lle)
      = Validated (validate s (elementSectionV nd (plsa m lsa) (plle m lle)))
                  []
    applyElementAction (Sequence a1 a2) e
      = actionSequence (applyElementAction a1 e) (applyElementAction a2 e)
    
    validate :: Uri -> Validated ElementSection -> ErrorInfo
    validate uri (Validated errs e) = errs ++ (validateElement uri e)
    
    elementSectionV :: Node -> Validated [[AttributeSection]] -> Validated [[ElementSection]] -> Validated ElementSection
    elementSectionV nd lsa lle = valid2 (ElementSection nd) lsa lle
    
    applyAttributeAction :: Action -> AttributeSection -> Validated (Maybe AttributeSection)
    applyAttributeAction (Allow m) a = Validated [] Nothing
    applyAttributeAction (Reject m) a = Validated [AttributeError a "namespace rejected"] Nothing
    applyAttributeAction (Attach m) a = Validated [] (Just a)
    applyAttributeAction (Unwrap _) _ = Validated [] Nothing
    applyAttributeAction (Validate s m) a
      = Validated (validateAttribute s a) Nothing
    applyAttributeAction (Sequence a1 a2) a
      = actionSequence (applyAttributeAction a1 a) (applyAttributeAction a2 a)
    
    
    actionSequence :: Validated a -> Validated a -> Validated a
    actionSequence (Validated errs1 _) (Validated errs2 x) = Validated (errs1 ++ errs2) x
    
    
    -- these are provided by an external validation library
    
    validateElement :: Uri -> ElementSection -> ErrorInfo
    validateElement _ _ = []
    
    validateAttribute :: Uri -> AttributeSection -> ErrorInfo
    validateAttribute _ _ = []
    
    -- processing functions
    
    pe :: Mode -> ElementSection -> Validated [ElementSection]
    pe m e = applyElementAction (m Elements (elementSectionNs e)) e
    
    ple :: Mode -> [ElementSection] -> Validated [ElementSection]
    ple m le = concatMapV (pe m) le
    
    plle :: Mode -> [[ElementSection]] -> Validated [[ElementSection]]
    plle m lle = mapV (ple m) lle
    
    pa :: Mode -> AttributeSection -> Validated (Maybe AttributeSection)
    pa m a = applyAttributeAction (m Attributes (attributeSectionNs a)) a
    
    psa :: Mode -> [AttributeSection] -> Validated [AttributeSection]
    psa m sa = dropMapV (pa m) sa
    
    plsa :: Mode -> [[AttributeSection]] -> Validated [[AttributeSection]]
    plsa m lsa = mapV (psa m) lsa
    
    elementSectionNs :: ElementSection -> Uri
    elementSectionNs (ElementSection (ElementNode (ns, _) _ _) _ _) = ns
    
    attributeSectionNs :: AttributeSection -> Uri
    attributeSectionNs (((ns, _),_):_) = ns
    
    -- functions for the Validated type
    
    errors :: Validated a -> ErrorInfo
    errors (Validated e _) = e
    
    valid1 :: (a -> b) -> Validated a -> Validated b
    valid1 f (Validated e x) = Validated e (f x)
    
    valid2 :: (a -> b -> c) -> Validated a -> Validated b -> Validated c
    valid2 f (Validated e x) (Validated e' y) = Validated (e ++ e') (f x y)
    
    listV :: Validated a -> Validated [a]
    listV x = valid1 (\y -> [y]) x
    
    mapV :: (a -> Validated b) -> [a] -> Validated [b]
    
    mapV f [] = Validated [] []
    mapV f (x:xs) = valid2 (\ x xs -> (x:xs)) (f x) (mapV f xs)
    
    concatMapV :: (a -> Validated [b]) -> [a] -> Validated [b]
    concatMapV f xs = valid1 concat (mapV f xs)
    
    dropMapV :: (a -> Validated (Maybe b)) -> [a] -> Validated [b]
    dropMapV f [] = Validated [] []
    dropMapV f (x:xs) = valid2 maybeCons (f x) (dropMapV f xs)
    
    maybeCons :: (Maybe a) -> [a] -> [a]
    maybeCons Nothing x = x
    maybeCons (Just x) xs = (x:xs)
    

    This does not yet deal with element-name context. To deal with this, we would need to change each of the Actions that has a Mode parameter to take a more complex structure.

    jing-trang-20131210+dfsg+1/doc/nrl.xsl000066400000000000000000000146011225366607500171660ustar00rootroot00000000000000

      

      

    Abstract

    Contents


    ' '
        
          
        
      
    < xmlns=" " xmlns: =" " > </ > /> > </ > =" " =" "

    jing-trang-20131210+dfsg+1/doc/pluggable-datatypes.html000066400000000000000000000030131225366607500224620ustar00rootroot00000000000000 RELAX NG Pluggable Datatype Libraries

    RELAX NG Pluggable Datatype Libraries

    A vendor-independent Java interface for RELAX NG datatype libraries has been developed by James Clark and KAWAGUCHI Kohsuke. RELAX NG datatype libraries should be interchangeable between RELAX NG validators that support this interface. The interface is hosted at SourceForge in the relaxng project. There is API documentation.

    In particular, the Jing validator now supports this interface.

    The interface allows validators to find datatype libraries dynamically at run-time. In order for a validator to be able to find a datatype library:

    • the datatype library should be packaged as JAR file
    • the JAR file must be on the Java CLASSPATH
    • the JAR file must include additional metadata in the form of a file META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory, which must contain the name of the class that implements the interface org.relaxng.datatype.DatatypeLibraryFactory

    The main Jing distribution includes a sample in the sample/datatype directory.

    James Clark
    jing-trang-20131210+dfsg+1/doc/regex/000077500000000000000000000000001225366607500167535ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/doc/regex/readme.html000066400000000000000000000050671225366607500211060ustar00rootroot00000000000000 XSD to Java Regular Expression Translator

    XSD to Java Regular Expression Translator

    Copyright © 2002 Thai Open Source Software Center Ltd

    See the file copying.txt for copying permission.

    Version @VERSION@

    The main component of this distribution is code for translating from the regular expression syntax of XML Schema Part 2 into the syntax of regular expressions used by the JDK 1.4 java.util.regex package. Although these two syntaxes are superficially similar, there are numerous differences, many of them rather subtle.

    • xsdregex.jar contains the compiled code
    • the src directory contains the source code
    • there is also API documentation

    There is also some supporting code:

    • a simple API for matching regular expressions
    • implementations of this interface using
      • the Xerces 1 regular expression implementation
      • the Xerces 2 regular expression implementation
      • translation into JDK 1.4 java.util.regex regular expressions
    • testing framework using this interface (in the package com.thaiopensource.datatype.xsd.regex.test and in the test directory)
    • code for dynamically loading the appropriate implementation using the service provider approach

    To compile from source, you will need:

    Compile by applying Ant to the included build.xml file.

    James Clark
    jing-trang-20131210+dfsg+1/doc/simplify.html000066400000000000000000000105051225366607500203640ustar00rootroot00000000000000 Implementing RELAX NG simplification

    Implementing RELAX NG simplification

    Simplifying grammar, define and ref

    This section sketches how to handle the simplification of grammar, define and ref described in sections 4.18 and 4.19 of the RELAX NG specification.

    Initial parse

    The result of the initial parse of the full syntax is a Pattern object representing the schema; this differs from the simple syntax pattern in that it contains an additional kind of Pattern, namely a RefPattern. A RefPattern is a Pattern containing a reference to another Pattern.

    During parsing maintain a current Grammar object. A Grammar object contains

    • a reference to the start pattern
    • a map from NCNames to RefPatterns
    • a reference to a parent grammar

    When you see a <grammar> start-tag, create a new Grammar object that becomes the new current Grammar. Initially the map is empty, the start pattern is null, and the parent Grammar is the old current Grammar.

    When you see a define element, look up the name in the current Grammar's map. If it doesn't exist, add a new RefPattern referring to the body of the definition. If it does exist, then check with the RefPattern's pattern reference is null; it is is null, then change it to refer to the body of the definition; if it's not null, then we have a duplicate definition.

    Handle <start> similarly to <define>.

    When you see a <ref> element, lookup the name in the current Grammar's map. If it doesn't exist, add a new RefPattern with a null pattern reference to the map. In either case, return that RefPattern as the result of parsing the <ref> element.

    When you see a <parentRef> do the same as <ref> except use the parent Grammar's map.

    At the <grammar> end-tag, check that the start of the current grammar is non-null. Also walk the map to check that all RefPatterns have non-null pattern references. Return the start pattern as the result of parsing the <grammar> element.

    Checking for illegal recursion

    The next task is to check that there is no illegal recursion. For this it is convenient to add a checkRecursionDepth field to the PatternRef object. This should be initialized to -1. Define a checkRecursion(int depth) method on Patterns. By default this simply calls checkRecursion with the same argument on all subpatterns. For an ElementPattern it calls checkRecursion(depth + 1). For a PatternRef pattern it does this:

    checkRecursion(int depth) {
      if (checkRecursionDepth == -1) {
        checkRecursionDepth = depth;
        referencedPattern.checkRecursion(depth);
        checkRecursionDepth = -2;
      }
      else if (depth == checkRecursionDepth)
        error("illegal recursion");
    }
    

    To check for illegal recursions, call checkRecursion(0) on the pattern for the schema as a whole.

    Expanding references

    After determining that there is no illegal recursion, the next stage is to eliminate RefPatterns. Do this with an expand() method on Patterns. It is convenient to add a boolean expanded field to ElementPattern; this is initialized to false. For an ElementPattern the code for expand is

    Pattern expand() {
      if (!expanded) {
        expanded = true;
        content = expand(content);
      }
      return this;
    }
    

    For a RefPattern it would be simply

    Pattern expand() {
      return referencedPattern.expand();
    }
    

    For a Text/DataPattern etc it would be simply

    Pattern expand() {
      return this;
    }
    

    For a Choice it would be

    Pattern expand() {
      return makeChoice(operand1.expand(), operand2.expand());
    }
    

    Handling include and combine

    See the following message from Kohsuke Kawaguchi.

    James Clark
    jing-trang-20131210+dfsg+1/dtdinst/000077500000000000000000000000001225366607500165455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/dtdinst/copying.txt000066400000000000000000000030211225366607500207520ustar00rootroot00000000000000Copyright (c) 2001-2003 Thai Open Source Software Center Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jing-trang-20131210+dfsg+1/dtdinst/dtdinst.rnc000066400000000000000000000057261225366607500207340ustar00rootroot00000000000000datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" start = element doctype { decl* } decl = elementDecl | attlistDecl | def | overriddenDef | externalIdRef | includedSection | ignoredSection | internalEntityDecl | externalEntityDecl | notationDecl | processingInstruction | comment def = modelGroupDef | attributeGroupDef | enumGroupDef | datatypeDef | attributeDefaultDef | flagDef | nameSpecDef | externalIdDef | paramDef elementDecl = element element { nameSpec, modelGroup } modelGroupDef = element modelGroup { name, modelGroup } datatypeDef = element datatype { name, datatype } attributeDefaultDef = element attributeDefault { name, attributeDefault } flagDef = element flag { name, flag } nameSpecDef = element nameSpec { name, nameSpec } externalIdDef = element externalId { name, externalId } paramDef = element param { name, text } overriddenDef = element overridden { def | duplicateDef } duplicateDef = element duplicate { name } includedSection = element includedSection { attribute flag { xsd:NCName }?, decl* } ignoredSection = element ignoredSection { attribute flag { xsd:NCName }?, text } externalIdRef = element externalIdRef { name, decl* } internalEntityDecl = element internalEntity { name, text } externalEntityDecl = element externalEntity { name, externalId } notationDecl = element notation { name, externalId } processingInstruction = element processingInstruction { attribute target { xsd:NCName }, text } comment = element comment { text } datatype = element tokenized { attribute name { "NMTOKEN" | "NMTOKENS" | "ENTITY" | "ENTITIES" | "ID" | "IDREF" | "IDREFS" } | (attribute name { "NOTATION" }?, enumGroup) } | element cdata { empty } | element datatypeRef { name } enumGroup = (element enum { xsd:NMTOKEN } | element enumGroupRef { name } )* enumGroupDef = element enumGroup { name, enumGroup } flag = element include { empty } | element ignore { empty } | element flagRef { name } attlistDecl = element attlist { nameSpec, attributeGroup } attributeGroupDef = element attributeGroup { name, attributeGroup } attributeGroup = (element attribute { nameSpec, datatype, attributeDefault } | element attributeGroupRef { name } )* attributeDefault = element implied { empty } | element required { empty } | element default|fixed { text } | element attributeDefaultRef { name } modelGroup = element modelGroupRef { name } | element elementRef { nameSpec } | element oneOrMore { modelGroup } | element zeroOrMore { modelGroup } | element optional { modelGroup } | element pcdata { empty } | element choice { (modelGroup, modelGroup+)? } | element sequence { (modelGroup, modelGroup+)? } externalId = attribute system { xsd:anyURI }?, attribute public { text }?, attribute xml:base { xsd:anyURI }? name = attribute name { xsd:NCName } nameSpec = element name { xsd:Name } | element nameSpecRef { name } jing-trang-20131210+dfsg+1/dtdinst/dtdinst2rng.xsl000066400000000000000000000126431225366607500215450ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/000077500000000000000000000000001225366607500202005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/dtdinst/example/attributeDefault.dtd000066400000000000000000000003021225366607500242000ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/attributeDefault.xml000066400000000000000000000015371225366607500242400ustar00rootroot00000000000000 security div para div para div para jing-trang-20131210+dfsg+1/dtdinst/example/attributeGroup.dtd000066400000000000000000000003111225366607500237100ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/attributeGroup.xml000066400000000000000000000014211225366607500237400ustar00rootroot00000000000000 id class foo bar foo bar bar jing-trang-20131210+dfsg+1/dtdinst/example/datatype.dtd000066400000000000000000000001761225366607500225140ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/datatype.xml000066400000000000000000000007041225366607500225360ustar00rootroot00000000000000 holiday holiday startDate endDate jing-trang-20131210+dfsg+1/dtdinst/example/enumGroup.dtd000066400000000000000000000002501225366607500226530ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/enumGroup.xml000066400000000000000000000011531225366607500227030ustar00rootroot00000000000000 JP TH UK FR IT employee employee country jing-trang-20131210+dfsg+1/dtdinst/example/externalId.dtd000066400000000000000000000000621225366607500227720ustar00rootroot00000000000000 %decls; jing-trang-20131210+dfsg+1/dtdinst/example/externalId.ent000066400000000000000000000000251225366607500230040ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/externalId.xml000066400000000000000000000003511225366607500230200ustar00rootroot00000000000000 doc jing-trang-20131210+dfsg+1/dtdinst/example/flag.dtd000066400000000000000000000002561225366607500216110ustar00rootroot00000000000000 ]]> jing-trang-20131210+dfsg+1/dtdinst/example/flag.xml000066400000000000000000000013121225366607500216300ustar00rootroot00000000000000 big small em para em big small jing-trang-20131210+dfsg+1/dtdinst/example/modelGroup.dtd000066400000000000000000000002271225366607500230130ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/modelGroup.xml000066400000000000000000000012501225366607500230350ustar00rootroot00000000000000 code em para code em jing-trang-20131210+dfsg+1/dtdinst/example/nameSpec.dtd000066400000000000000000000002011225366607500224210ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/nameSpec.xml000066400000000000000000000007511225366607500224600ustar00rootroot00000000000000 para em jing-trang-20131210+dfsg+1/dtdinst/example/overridden.dtd000066400000000000000000000003661225366607500230430ustar00rootroot00000000000000 ]]> jing-trang-20131210+dfsg+1/dtdinst/example/overridden.xml000066400000000000000000000017221225366607500230650ustar00rootroot00000000000000 big small em em big small em para jing-trang-20131210+dfsg+1/dtdinst/example/param.dtd000066400000000000000000000000511225366607500217710ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/dtdinst/example/param.xml000066400000000000000000000002341225366607500220210ustar00rootroot00000000000000 EMPTY EMPTY jing-trang-20131210+dfsg+1/dtdinst/index.html000066400000000000000000000204741225366607500205510ustar00rootroot00000000000000 DTDinst

    DTDinst

    Copyright © 2001-2003, 2008 Thai Open Source Software Center Ltd

    See the file copying.txt for copying permission.

    Version @VERSION@

    DTDinst is a program for converting XML DTDs into an XML instance format.

    Previous versions of DTDinst could also convert XML DTDs into RELAX NG. This functionality has now migrated into Trang, which now shares the DTDinst code.

    The key feature of DTDinst is its handling of parameter entities. It is able to reliably turn parameter entity declarations and references into a variety of higher-level semantic constructs. It can do this even in the presence of arbitrarily deep nesting of parameter entity references within parameter entity declarations. At the same time, it accurately follows XML 1.0 rules on parameter entity expansion, so that any valid XML 1.0 DTD can be handled. If a parameter entity is used in a way that does not correspond to any of the higher-level semantics constructs supported by DTDinst, then references to that parameter entity will be expanded in the DTDinst output.

    Getting DTDinst

    DTDinst is available for download as the file dtdinst-@VERSION@.zip, which contains binaries, source code and documentation. It requires a Java runtime compatible with the Java 2 Platform, Standard Edition (J2SE) version 1.4 (or any later version), such as the Java Runtime Environment (JRE), which can be downloaded here.

    The latest version of DTDinst will always be available in the Downloads section of the project site.

    Running DTDinst

    To run DTDinst, use a command of the form:

    java -jar dtdinst.jar DTD

    The DTD argument can be either a file or a URL.

    DTDinst writes an XML representation of the DTD in DTDinst format to the standard output. For example, the command

    java -jar dtdinst.jar http://www.w3.org/XML/1998/06/xmlspec-v21.dtd >xmlspec.xml

    would write an XML representation of the W3C xmlspec DTD to the file xmlspec.xml.

    DTDinst format

    The DTDinst format is designed to represent the parameterization of the DTD as fully as possible.

    There is a schema for this format in RELAX NG compact syntax; the schema is also available in RELAX NG format.

    Each parameter entity declaration is represented by one of the following elements:

    • modelGroup is used for a parameter entity that represents all or part of the content model of an element (example, DTDinst output)
    • attributeGroup is used for a parameter entity containing zero or more attribute definitions, which can be referenced in an ATTLIST declaration (example, DTDinst output)
    • attributeDefault is used for a parameter entity that represents the default value of an attribute (example, DTDinst output)
    • datatype is used for a parameter entity that represents an attribute type (example, DTDinst output)
    • enumGroup is used for a parameter entity that contains zero or more enumerated values (example, DTDinst output)
    • flag is used for a parameter entity with replacement text INCLUDE or IGNORE, which can be used to control a conditional section (example, DTDinst output)
    • nameSpec is used for a parameter entity that represents the name of an element or attribute (example, DTDinst output)
    • externalId is used for an external parameter entity that does not fall into any of the above categories (example, DTDinst output)
    • param is used for an internal parameter entity that does not fall into any of the above categories (example, DTDinst output)
    • overridden is used for a parameter entity declaration that is overridden by an earlier declaration of the same parameter entity (example, DTDinst output)

    The element used to represent a parameter entity reference depends on the element used to represent the declaration of the parameter entity.

    • If the declaration is represented by a modelGroup, attributeGroup, attributeDefault, datatype, enumGroup, flag or nameSpec element, then the reference will be represented by a modelGroupRef, attributeGroupRef, attributeDefaultRef, datatypeRef, enumGroupRef, flagRef or nameSpecRef element respectively.
    • If the declaration is represented by externalId and the reference occurs at the declaration level (i.e. at a point where a declaration would be allowed), then the reference will be represented by a externalIdRef element containing the declarations from the external entity.
    • Otherwise, the reference will be expanded and there will be no indication that a reference was originally used in the DTD.

    An XSLT stylesheet is available that converts DTDinst format to RELAX NG. It has many more limitations than the converter builtin to DTDinst, but it may be useful as a basis for XSLT-based processing of DTDinst format.

    Sample DTDs

    You may find it interesting to experiment with the following XML DTDs which are available online:

    Limitations

    DTDinst does not attempt to understand the contents of ignored conditional sections: DTDinst format represents the contents of an ignored section as a string. If you wish to preserve information about conditional sections, you should therefore make as many conditional sections as possible be included marked sections rather than ignored marked sections. You can do this by creating a wrapper DTD that declares parameter entities as INCLUDE and then references the real DTD. For example, you might use this wrapper DTD to convert the TEI P4 DTD.

    DTDinst does not attempt to understand the contents of parameter entities that are never referenced.

    Reporting bugs

    Please report bugs by creating a new issue in the Issues section of the project site. Be sure to attach a complete DTD for which DTDinst exhibits the bug.

    James Clark
    jing-trang-20131210+dfsg+1/dtdinst/tei2rng.xsl000066400000000000000000000125161225366607500206540ustar00rootroot00000000000000 true jing-trang-20131210+dfsg+1/dtdinst/teixml.dtd000066400000000000000000000014061225366607500205450ustar00rootroot00000000000000 %tei2.dtd; jing-trang-20131210+dfsg+1/eg/000077500000000000000000000000001225366607500154675ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/eg/relaxCore.rng000066400000000000000000000440041225366607500201250ustar00rootroot00000000000000
    The overall structure of RELAX modules Namespace declarations cannot be controlled by RELAX Core. Wait for RELAX modularization. div elements in modules
    Interface div elements in interfaces
    Include
    Hedge Models This is used to describe element hedge models. It is also used as subordinates of <sequence>, <choice>, and <mixed>. This is used to specify the "occurs" attribute, which is shared by several elements. ? * + with the label attribute with the type attribute
    Rules without embedded tag or attPool elements with the type attribute with embedded tag or attPool elements with the type attribute without embedded tag or attPool elements with a hedge model with embedded tag or attPool elements with a hedge model
    Clauses tag elements embedded in elementRules attPool elements embedded in elementRules true
    jing-trang-20131210+dfsg+1/eg/relaxCoreDatatypes.rng000066400000000000000000000156131225366607500220100ustar00rootroot00000000000000 hex base64 jing-trang-20131210+dfsg+1/eg/relaxng.rng000066400000000000000000000176011225366607500176440ustar00rootroot00000000000000 choice interleave jing-trang-20131210+dfsg+1/eg/testSuite.rng000066400000000000000000000071201225366607500201700ustar00rootroot00000000000000 ([\-A-Za-z0-9:@&=+$,_.!~*'()]|%[0-9a-fA-F][0-9a-fA-F])+ jing-trang-20131210+dfsg+1/eg/xslt.rng000066400000000000000000000640071225366607500172000ustar00rootroot00000000000000 1.0 version version extension-element-prefixes exclude-result-prefixes use-attribute-sets yes no yes no single multiple any alphabetic traditional text number ascending descending upper-first lower-first yes no xml html text yes no yes no yes no #default #default \*|\i\c*:\* 1 .*:.* ([^\{\}]|\{\{|\}\})*\{([^"'\{\}]|"[^"]*"|'[^']*')+\}([^\{\}]|\{\{|\}\}|\{([^"'\{\}]|"[^"]*"|'[^']*')+\})* [^\{\}]*(\{\{|\}\}|\{([^"'\{\}]|"[^"]*"|'[^']*')+\})([^\{\}]|\{\{|\}\}|\{([^"'\{\}]|"[^"]*"|'[^']*')+\})* ([^\{\}]|\{\{|\}\}|\{([^"'\{\}]|"[^"]*"|'[^']*')+\})* jing-trang-20131210+dfsg+1/extapidoc/000077500000000000000000000000001225366607500170545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jaxp/000077500000000000000000000000001225366607500200165ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jaxp/1.1/000077500000000000000000000000001225366607500203155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jaxp/1.1/package-list000066400000000000000000000001761225366607500226100ustar00rootroot00000000000000javax.xml.parsers javax.xml.transform javax.xml.transform.dom javax.xml.transform.sax javax.xml.transform.stream org.w3c.dom jing-trang-20131210+dfsg+1/extapidoc/jdk/000077500000000000000000000000001225366607500176245ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jdk/1.3/000077500000000000000000000000001225366607500201255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jdk/1.3/package-list000066400000000000000000000025151225366607500224170ustar00rootroot00000000000000java.applet java.awt java.awt.color java.awt.datatransfer java.awt.dnd java.awt.event java.awt.font java.awt.geom java.awt.im java.awt.im.spi java.awt.image java.awt.image.renderable java.awt.print java.beans java.beans.beancontext java.io java.lang java.lang.ref java.lang.reflect java.math java.net java.rmi java.rmi.activation java.rmi.dgc java.rmi.registry java.rmi.server java.security java.security.acl java.security.cert java.security.interfaces java.security.spec java.sql java.text java.util java.util.jar java.util.zip javax.accessibility javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi javax.rmi javax.rmi.CORBA javax.sound.midi javax.sound.midi.spi javax.sound.sampled javax.sound.sampled.spi javax.swing javax.swing.border javax.swing.colorchooser javax.swing.event javax.swing.filechooser javax.swing.plaf javax.swing.plaf.basic javax.swing.plaf.metal javax.swing.plaf.multi javax.swing.table javax.swing.text javax.swing.text.html javax.swing.text.html.parser javax.swing.text.rtf javax.swing.tree javax.swing.undo javax.transaction org.omg.CORBA org.omg.CORBA_2_3 org.omg.CORBA_2_3.portable org.omg.CORBA.DynAnyPackage org.omg.CORBA.ORBPackage org.omg.CORBA.portable org.omg.CORBA.TypeCodePackage org.omg.CosNaming org.omg.CosNaming.NamingContextPackage org.omg.SendingContext org.omg.stub.java.rmi jing-trang-20131210+dfsg+1/extapidoc/jdk/1.5/000077500000000000000000000000001225366607500201275ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jdk/1.5/package-list000066400000000000000000000064371225366607500224300ustar00rootroot00000000000000java.applet java.awt java.awt.color java.awt.datatransfer java.awt.dnd java.awt.event java.awt.font java.awt.geom java.awt.im java.awt.im.spi java.awt.image java.awt.image.renderable java.awt.print java.beans java.beans.beancontext java.io java.lang java.lang.annotation java.lang.instrument java.lang.management java.lang.ref java.lang.reflect java.math java.net java.nio java.nio.channels java.nio.channels.spi java.nio.charset java.nio.charset.spi java.rmi java.rmi.activation java.rmi.dgc java.rmi.registry java.rmi.server java.security java.security.acl java.security.cert java.security.interfaces java.security.spec java.sql java.text java.util java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks java.util.jar java.util.logging java.util.prefs java.util.regex java.util.zip javax.accessibility javax.activity javax.crypto javax.crypto.interfaces javax.crypto.spec javax.imageio javax.imageio.event javax.imageio.metadata javax.imageio.plugins.bmp javax.imageio.plugins.jpeg javax.imageio.spi javax.imageio.stream javax.management javax.management.loading javax.management.modelmbean javax.management.monitor javax.management.openmbean javax.management.relation javax.management.remote javax.management.remote.rmi javax.management.timer javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi javax.net javax.net.ssl javax.print javax.print.attribute javax.print.attribute.standard javax.print.event javax.rmi javax.rmi.CORBA javax.rmi.ssl javax.security.auth javax.security.auth.callback javax.security.auth.kerberos javax.security.auth.login javax.security.auth.spi javax.security.auth.x500 javax.security.cert javax.security.sasl javax.sound.midi javax.sound.midi.spi javax.sound.sampled javax.sound.sampled.spi javax.sql javax.sql.rowset javax.sql.rowset.serial javax.sql.rowset.spi javax.swing javax.swing.border javax.swing.colorchooser javax.swing.event javax.swing.filechooser javax.swing.plaf javax.swing.plaf.basic javax.swing.plaf.metal javax.swing.plaf.multi javax.swing.plaf.synth javax.swing.table javax.swing.text javax.swing.text.html javax.swing.text.html.parser javax.swing.text.rtf javax.swing.tree javax.swing.undo javax.transaction javax.transaction.xa javax.xml javax.xml.datatype javax.xml.namespace javax.xml.parsers javax.xml.transform javax.xml.transform.dom javax.xml.transform.sax javax.xml.transform.stream javax.xml.validation javax.xml.xpath org.ietf.jgss org.omg.CORBA org.omg.CORBA.DynAnyPackage org.omg.CORBA.ORBPackage org.omg.CORBA.TypeCodePackage org.omg.CORBA.portable org.omg.CORBA_2_3 org.omg.CORBA_2_3.portable org.omg.CosNaming org.omg.CosNaming.NamingContextExtPackage org.omg.CosNaming.NamingContextPackage org.omg.Dynamic org.omg.DynamicAny org.omg.DynamicAny.DynAnyFactoryPackage org.omg.DynamicAny.DynAnyPackage org.omg.IOP org.omg.IOP.CodecFactoryPackage org.omg.IOP.CodecPackage org.omg.Messaging org.omg.PortableInterceptor org.omg.PortableInterceptor.ORBInitInfoPackage org.omg.PortableServer org.omg.PortableServer.CurrentPackage org.omg.PortableServer.POAManagerPackage org.omg.PortableServer.POAPackage org.omg.PortableServer.ServantLocatorPackage org.omg.PortableServer.portable org.omg.SendingContext org.omg.stub.java.rmi org.w3c.dom org.w3c.dom.bootstrap org.w3c.dom.events org.w3c.dom.ls org.xml.sax org.xml.sax.ext org.xml.sax.helpers jing-trang-20131210+dfsg+1/extapidoc/jdk/1.6/000077500000000000000000000000001225366607500201305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/jdk/1.6/package-list000066400000000000000000000077711225366607500224330ustar00rootroot00000000000000java.applet java.awt java.awt.color java.awt.datatransfer java.awt.dnd java.awt.event java.awt.font java.awt.geom java.awt.im java.awt.im.spi java.awt.image java.awt.image.renderable java.awt.print java.beans java.beans.beancontext java.io java.lang java.lang.annotation java.lang.instrument java.lang.management java.lang.ref java.lang.reflect java.math java.net java.nio java.nio.channels java.nio.channels.spi java.nio.charset java.nio.charset.spi java.rmi java.rmi.activation java.rmi.dgc java.rmi.registry java.rmi.server java.security java.security.acl java.security.cert java.security.interfaces java.security.spec java.sql java.text java.text.spi java.util java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks java.util.jar java.util.logging java.util.prefs java.util.regex java.util.spi java.util.zip javax.accessibility javax.activation javax.activity javax.annotation javax.annotation.processing javax.crypto javax.crypto.interfaces javax.crypto.spec javax.imageio javax.imageio.event javax.imageio.metadata javax.imageio.plugins.bmp javax.imageio.plugins.jpeg javax.imageio.spi javax.imageio.stream javax.jws javax.jws.soap javax.lang.model javax.lang.model.element javax.lang.model.type javax.lang.model.util javax.management javax.management.loading javax.management.modelmbean javax.management.monitor javax.management.openmbean javax.management.relation javax.management.remote javax.management.remote.rmi javax.management.timer javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi javax.net javax.net.ssl javax.print javax.print.attribute javax.print.attribute.standard javax.print.event javax.rmi javax.rmi.CORBA javax.rmi.ssl javax.script javax.security.auth javax.security.auth.callback javax.security.auth.kerberos javax.security.auth.login javax.security.auth.spi javax.security.auth.x500 javax.security.cert javax.security.sasl javax.sound.midi javax.sound.midi.spi javax.sound.sampled javax.sound.sampled.spi javax.sql javax.sql.rowset javax.sql.rowset.serial javax.sql.rowset.spi javax.swing javax.swing.border javax.swing.colorchooser javax.swing.event javax.swing.filechooser javax.swing.plaf javax.swing.plaf.basic javax.swing.plaf.metal javax.swing.plaf.multi javax.swing.plaf.synth javax.swing.table javax.swing.text javax.swing.text.html javax.swing.text.html.parser javax.swing.text.rtf javax.swing.tree javax.swing.undo javax.tools javax.transaction javax.transaction.xa javax.xml javax.xml.bind javax.xml.bind.annotation javax.xml.bind.annotation.adapters javax.xml.bind.attachment javax.xml.bind.helpers javax.xml.bind.util javax.xml.crypto javax.xml.crypto.dom javax.xml.crypto.dsig javax.xml.crypto.dsig.dom javax.xml.crypto.dsig.keyinfo javax.xml.crypto.dsig.spec javax.xml.datatype javax.xml.namespace javax.xml.parsers javax.xml.soap javax.xml.stream javax.xml.stream.events javax.xml.stream.util javax.xml.transform javax.xml.transform.dom javax.xml.transform.sax javax.xml.transform.stax javax.xml.transform.stream javax.xml.validation javax.xml.ws javax.xml.ws.handler javax.xml.ws.handler.soap javax.xml.ws.http javax.xml.ws.soap javax.xml.ws.spi javax.xml.xpath org.ietf.jgss org.omg.CORBA org.omg.CORBA.DynAnyPackage org.omg.CORBA.ORBPackage org.omg.CORBA.TypeCodePackage org.omg.CORBA.portable org.omg.CORBA_2_3 org.omg.CORBA_2_3.portable org.omg.CosNaming org.omg.CosNaming.NamingContextExtPackage org.omg.CosNaming.NamingContextPackage org.omg.Dynamic org.omg.DynamicAny org.omg.DynamicAny.DynAnyFactoryPackage org.omg.DynamicAny.DynAnyPackage org.omg.IOP org.omg.IOP.CodecFactoryPackage org.omg.IOP.CodecPackage org.omg.Messaging org.omg.PortableInterceptor org.omg.PortableInterceptor.ORBInitInfoPackage org.omg.PortableServer org.omg.PortableServer.CurrentPackage org.omg.PortableServer.POAManagerPackage org.omg.PortableServer.POAPackage org.omg.PortableServer.ServantLocatorPackage org.omg.PortableServer.portable org.omg.SendingContext org.omg.stub.java.rmi org.w3c.dom org.w3c.dom.bootstrap org.w3c.dom.events org.w3c.dom.ls org.xml.sax org.xml.sax.ext org.xml.sax.helpers jing-trang-20131210+dfsg+1/extapidoc/sax/000077500000000000000000000000001225366607500176475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/extapidoc/sax/package-list000066400000000000000000000000621225366607500221340ustar00rootroot00000000000000org.xml.sax org.xml.sax.ext org.xml.sax.helpers jing-trang-20131210+dfsg+1/gcj/000077500000000000000000000000001225366607500156375ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/gcj/INSTALL000066400000000000000000000220041225366607500166660ustar00rootroot00000000000000Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for variables by setting them in the environment. You can do that on the command line like this: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. jing-trang-20131210+dfsg+1/gcj/README.redhat8000066400000000000000000000015201225366607500200530ustar00rootroot00000000000000GCJ as shipped in RedHat 8.0 has a bug in the list of libraries that it uses to link with. Amongst other things, this causes any Java program that throws an unhandled exception to hang while printing a stack trace. See . If you are running RedHat 8.0, I recommend you apply the following patch before compiling: --- /usr/lib/gcc-lib/i386-redhat-linux/3.2/libgcj.spec~ 2002-09-04 04:03:39.000000000 +0100 +++ /usr/lib/gcc-lib/i386-redhat-linux/3.2/libgcj.spec 2002-12-10 15:59:39.000000000 +0000 @@ -4,6 +4,6 @@ # to link with libgcj. # %rename lib liborig -*lib: -lgcj -lm -lz -ldl %(libgcc) %(liborig) +*lib: -lgcj -lm -lpthread -lz -ldl %(libgcc) %(liborig) *jc1: -fhash-synchronization -fno-use-divide-subroutine -fuse-boehm-gc -fnon-call-exceptions -fkeep-inline-functions jing-trang-20131210+dfsg+1/gcj/aclocal.m4000066400000000000000000000025171225366607500175040ustar00rootroot00000000000000m4_define([AC_LANG(Java)], [ac_ext=java ac_compile='$GCJ -c $GCJFLAGS conftest.$ac_ext >&AS_MESSAGE_LOG_FD' ac_link='$GCJ --main=conftest -o conftest$ac_exeext $GCJFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&AS_MESSAGE_LOG_FD' ]) AU_DEFUN([AC_LANG_JAVA], [AC_LANG(Java)]) m4_define([_AC_LANG_ABBREV(JAVA)], [java]) m4_define([AC_LANG_SOURCE(Java)], [$1]) m4_define([AC_LANG_PROGRAM(Java)], [$1 public class conftest { static public void main(String[] args) { $2 } }]) AC_DEFUN([AC_LANG_COMPILER(Java)], [AC_REQUIRE([AC_PROG_GCJ])]) AC_DEFUN([AC_PROG_GCJ], [AC_LANG_PUSH(Java)dnl AC_ARG_VAR([GCJ], [Java compiler command]) AC_ARG_VAR([GCJFLAGS], [Java compiler flags]) _AC_ARG_VAR_LDFLAGS()dnl m4_ifval([$1], [AC_CHECK_TOOLS(GCJ, [$1])], [if test -z "$GCJ"; then AC_CHECK_TOOL(GCJ, gcj) fi]) test -z "$GCJ" && AC_MSG_ERROR([GCJ not found in \$PATH]) test "${GCJFLAGS+set}" = set || GCJFLAGS="-g -O2" ]) AC_DEFUN([TRY_ORG_XML_SAX], [AC_TRY_LINK([import org.xml.sax.helpers.XMLReaderFactory; import org.xml.sax.SAXException;], [try { XMLReaderFactory.createXMLReader(); } catch (SAXException e) { }], [$1], [$2])]) AC_DEFUN([GCJ_LIB_SAX], [AC_MSG_CHECKING([what library contains org.xml.sax]) TRY_ORG_XML_SAX([AC_MSG_RESULT([built in])], [LIBS=-l-org-xml-sax TRY_ORG_XML_SAX([AC_MSG_RESULT([-l-org-xml-sax])], [LIBS= AC_MSG_RESULT([none found])])])]) jing-trang-20131210+dfsg+1/gcj/configure.ac000066400000000000000000000001741225366607500201270ustar00rootroot00000000000000AC_INIT(@PROG@, @PROG_VERSION@) AC_PROG_INSTALL AC_PROG_GCJ GCJ_LIB_SAX AC_CONFIG_FILES([Makefile test/Makefile]) AC_OUTPUT jing-trang-20131210+dfsg+1/gcj/dist000077500000000000000000000161761225366607500165430ustar00rootroot00000000000000#!/bin/sh set -e jing_main=com.thaiopensource.relaxng.util.Driver jing_test_main=com.thaiopensource.relaxng.util.TestDriver trang_main=com.thaiopensource.relaxng.translate.Driver trang_test_main=com.thaiopensource.relaxng.translate.test.CompactTestDriver a_jing_file=src/com/thaiopensource/relaxng/util/Driver.java crimson_version=1.1.3 xerces_version=2.3.0 jing_version_properties=src/com/thaiopensource/relaxng/util/resources/Version.properties trang_version_properties=trang/src/com/thaiopensource/relaxng/translate/resources/Version.properties crimson_unwanted=" org/w3c org/xml org/apache/crimson/tree org/apache/crimson/jaxp/DocumentBuilderImpl.java org/apache/crimson/jaxp/DocumentBuilderFactoryImpl.java javax/xml/parsers/DocumentBuilder.java javax/xml/parsers/DocumentBuilderFactory.java META-INF/services/javax.xml.parsers.DocumentBuilderFactory META-INF/services/javax.xml.transform.TransformerFactory META-INF/jaxp-javax.manifest META-INF/manifest.crimson " jing_unwanted=" com/thaiopensource/datatype/xsd/regex/jdk1_4 com/thaiopensource/datatype/xsd/regex/xerces com/thaiopensource/relaxng/jarv com/thaiopensource/relaxng/util/JingTask.java com/thaiopensource/validate/xerces com/thaiopensource/validate/schematron com/thaiopensource/validate/jarv META-INF/services/org.iso_relax.verifier.VerifierFactoryLoader " jing_unwanted_in_trang=" com/thaiopensource/relaxng/impl com/thaiopensource/relaxng/util com/thaiopensource/relaxng/SchemaFactory.java com/thaiopensource/validate " jing_test="dir.xsl exslt.xsl prep.xsl spectest.xml xsdtest.xml xsdtest.xsl mnstest.xml nrltest.xml" if [ -f ../${a_jing_file} ]; then cd .. elif [ ! -f ${a_jing_file} ]; then echo You are in the wrong directory >&2 exit 1 fi if [ $# -gt 0 ]; then jing_build_dir=$1 else jing_build_dir=build fi jing_build_dir=`cd ${jing_build_dir}; pwd` build_dir=${jing_build_dir}/gcj dist_dir=${jing_build_dir}/dist/gcj top_dir=`pwd` rm -fr ${build_dir} test -f ${build_dir} || mkdir -p ${build_dir} . ${jing_version_properties} jing_version=$version . ${trang_version_properties} trang_version=$version jing_dir=${build_dir}/jing-${jing_version} trang_dir=${build_dir}/trang-${trang_version} mkdir -p ${jing_dir} ${trang_dir} (ls src/META-INF/services/*.*; find src -name '*.java' -or -name '*.jj' -or -name '*.properties' -or -name '*.rng') | cpio --quiet -p -m -d ${jing_dir} cd ${jing_dir}/src rm -fr ${jing_unwanted} f=com/thaiopensource/relaxng/util/resources/Messages.properties sed -e 's/java com.thaiopensource.relaxng.util.Driver/jing/' $f >tem mv tem $f echo com.thaiopensource.datatype.xsd.regex.xerces2.RegexEngineImpl >META-INF/services/com.thaiopensource.datatype.xsd.regex.RegexEngine cd ${top_dir} CLASSPATH=lib/JavaCC.zip gij COM.sun.labs.javacc.Main -output_directory=${jing_dir}/src/com/thaiopensource/relaxng/parse/compact ${jing_dir}/src/com/thaiopensource/relaxng/parse/compact/CompactSyntax.jj >/dev/null f=${jing_dir}/src/com/thaiopensource/relaxng/parse/compact/CompactSyntaxTokenManager.java sed -e 's/java.io.IOException/EOFException/g' $f >${build_dir}/tem mv ${build_dir}/tem $f cd ${build_dir} tar xfz ${top_dir}/gcj/crimson-${crimson_version}-src.tar.gz crimson-${crimson_version}/src cd crimson-${crimson_version} patch -p0 <${top_dir}/gcj/crimson.patch cd src rm -fr ${crimson_unwanted} find org javax -type f -not -name '*.java' -not -name '*.properties' | xargs rm -f cd ${top_dir} cp -a ${build_dir}/crimson-${crimson_version}/src/* ${jing_dir}/src rm -fr ${build_dir}/crimson-${crimson_version} cd ${build_dir} xerces_top_dir=xerces-`echo ${xerces_version} | tr . _` xerces_src_dir=${xerces_top_dir}/src tar xfz ${top_dir}/gcj/Xerces-J-src.${xerces_version}.tar.gz ${xerces_src_dir}/org/apache/xerces/impl/xpath/regex cd ${top_dir} cp -a ${build_dir}/${xerces_src_dir}/* ${jing_dir}/src rm -fr ${build_dir}/${xerces_top_dir} cd ${jing_dir} patch -p0 <${top_dir}/gcj/xerces-regex.patch rm -f `find src -name '*~'` cd ${top_dir} cp -a ${jing_dir}/src ${trang_dir} cd dtdinst find src -name '*.java' -or -name '*.properties' | cpio --quiet -p -m -d ${trang_dir} cd ../trang find src -name '*.java' -or -name '*.properties' | cpio --quiet -p -m -d ${trang_dir} cd ${trang_dir}/src rm -fr ${jing_unwanted_in_trang} f=com/thaiopensource/relaxng/translate/resources/Messages.properties sed -e 's/java com.thaiopensource.relaxng.translate.Driver/trang/' $f >tem mv tem $f cd ${top_dir} setup_prog() { cd ${prog_src_dir} sed -e "s/@PROG@/${prog}/" -e "s/@MAIN@/${main}/" -e "s/@TEST_MAIN@/${test_main}/" ${top_dir}/gcj/vars.mk >Makefile.in echo SOURCES=\\ >>Makefile.in find src -name '*.java' | sed -e 's;^; $(srcdir)/;' -e 's/$/ \\/' -e '$s/ \\//' >>Makefile.in echo RESOURCES=\\ >>Makefile.in find src -type f -not -name '*.java' -not -name '*.jj' | sed -e 's;^; ;' -e 's/$/.o/' -e 's/$/ \\/' -e '$s/ \\//' >>Makefile.in echo DIRS=src \\ >>Makefile.in find src/* -type d -not -name '*.java' -not -name '*.jj' | sed -e 's;^; ;' -e 's/$/ \\/' -e '$s/ \\//' >>Makefile.in cat ${top_dir}/gcj/rules.mk >>Makefile.in find src -type f -not -name '*.java' -not -name '*.jj' -exec mv "{}" "{}.resource" ";" sed -e "s/@PROG@/${prog}/" -e "s/@PROG_VERSION@/${prog_version}/" ${top_dir}/gcj/configure.ac >configure.ac cp -a ${top_dir}/gcj/aclocal.m4 . cp -a ${top_dir}/gcj/install-sh . cp -a ${top_dir}/gcj/mkinstalldirs . cp -a ${top_dir}/gcj/INSTALL . sed -e "s/@VERSION@/${prog_version}/" ${top_dir}/gcj/${prog}.1 >${prog}.1 autoconf rm -fr autom4te* sed -e "/^Version:/s/:.*/: ${prog_version}/" ${top_dir}/gcj/${prog}.spec >${prog}.spec cat >copying.txt <>copying.txt cat >>copying.txt <>copying.txt cat >>copying.txt <>copying.txt cp -a ${top_dir}/gcj/README.redhat8 . mkdir test } prog=jing main=${jing_main} test_main=${jing_test_main} prog_version=${jing_version} prog_src_dir=${jing_dir} copying=${top_dir}/copying.txt setup_prog cd test for f in ${jing_test}; do cp -a ${top_dir}/test/$f .; done cp -a ${top_dir}/gcj/test_jing.mk Makefile.in cd ${top_dir} prog=trang main=${trang_main} test_main=${trang_test_main} prog_version=${trang_version} prog_src_dir=${trang_dir} copying=${top_dir}/trang/copying.txt setup_prog sed -e "s/@VERSION@/${trang_version}/g" ${top_dir}/trang/doc/trang-manual.html >trang-manual.html cd test cp -a ${top_dir}/trang/test/compacttest.xml . cp -a ${top_dir}/trang/test/toxsdtest.xml . cp -a ${top_dir}/test/dir.xsl . cp -a ${top_dir}/test/exslt.xsl . cp -a ${top_dir}/trang/test/compactprep.xsl prep.xsl cp -a ${top_dir}/gcj/test_trang.mk Makefile.in cd ${top_dir} test -d ${dist_dir} || mkdir -p ${dist_dir} cd ${dist_dir} abs_dist_dir=`pwd` cd ${top_dir} cd ${jing_dir}/.. tar cfz ${abs_dist_dir}/jing-${jing_version}.tar.gz jing-${jing_version} cd ${top_dir} cd ${trang_dir}/.. tar cfz ${abs_dist_dir}/trang-${trang_version}.tar.gz trang-${trang_version} jing-trang-20131210+dfsg+1/gcj/install-sh000077500000000000000000000127011225366607500176440ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else : fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else : fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else : fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 jing-trang-20131210+dfsg+1/gcj/jing.1000066400000000000000000000032471225366607500166560ustar00rootroot00000000000000.TH jing 1 @VERSION@ .SH NAME jing \- validate an XML document using a RELAX NG schema .SH SYNOPSIS .B jing .RB [ \-cfit ] .RB [ \-e .IR encoding ] .I rng-file .RI [ xml-file ...] .SH DESCRIPTION If .I rng-file is a correct RELAX NG schema and each .I xml-file is a well-formed XML document that is valid with respect to .IR rng-file , then .B jing will be silent and terminate with a status of 0. Otherwise, .B jing will report one or more errors to the standard output and will terminate with a status of 1. Both .I rng-file and .I xml-file can be filenames or URIs. .SH OPTIONS .TP .B \-c Uses the compact syntax for the schema. .TP .BI \-e " enc" Uses the encoding .I enc to read the schema. .TP .BI \-f Checks that the document is feasibly valid. A document is feasibly valid if it could be transformed into a valid document by inserting any number of attributes and child elements anywhere in the tree. This is equivalent to transforming the schema by wrapping every .BR data , .BR list , .B element and .B attribute element in an .B optional element and then validating against the transformed schema. This option may be useful while a document is still under construction. This option also disables checking that for every IDREF there is a corresponding ID. .TP .B \-i Disables checking of ID/IDREF/IDREFS. By default, Jing enforces the constraints imposed by RELAX NG DTD Compatibility with respect to ID/IDREF/IDREFS. .TP .B \-t Prints the time used by Jing for loading the schema and for validation. .SH "SEE ALSO" trang(1) .PP http://relaxng.org .SH AUTHOR James Clark (jjc@jclark.com) .PP This product includes software developed by the Apache Software Foundation (http://www.apache.org/). jing-trang-20131210+dfsg+1/gcj/jing.spec000066400000000000000000000016161225366607500174460ustar00rootroot00000000000000Summary: A RELAX NG Validator. Name: jing Version: Release: 1 URL: http://www.thaiopensource.com/relaxng/ Source: %{name}-%{version}.tar.gz License: BSD Group: Applications/Text BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gcc-java >= 3.2-7 %description Jing is an implementation of RELAX NG, a schema language for XML. RELAX NG has been standardized by OASIS and is in the final stages of standardization by ISO as ISO/IEC 19757-2. Jing validates an XML document against a RELAX NG schema. Jing supports both the original XML syntax for RELAX NG schemas, and the more recent non-XML compact syntax. %prep %setup -q %build %configure GCJFLAGS="${GCJFLAGS:-%optflags}" make %install rm -rf $RPM_BUILD_ROOT %makeinstall %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/jing %{_mandir}/man1/jing.1* %changelog * Sat Feb 22 2003 James Clark - Initial build. jing-trang-20131210+dfsg+1/gcj/mkinstalldirs000077500000000000000000000034111225366607500204440ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." # process command line arguments while test $# -gt 0 ; do case "${1}" in -h | --help | --h* ) # -h for help echo "${usage}" 1>&2; exit 0 ;; -m ) # -m PERM arg shift test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } dirmode="${1}" shift ;; -- ) shift; break ;; # stop option processing -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option * ) break ;; # first non-opt arg esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 3 # End: # mkinstalldirs ends here jing-trang-20131210+dfsg+1/gcj/readme.txt000066400000000000000000000010061225366607500176320ustar00rootroot00000000000000The RPMs require libgcj-3.2. This is included with RedHat 8.0. You can download the libgcj-3.2 RPM from: http://rpmfind.net//linux/RPM/redhat/8.0/i386/libgcj-3.2-7.i386.html However, the libgcj RPM depends on particular versions of libgcc and glibc. So, if you are not running RedHat 8, you might find it easier to rebuild the RPMs from source. You would need gcc-3.2 or later installed with Java enabled. Then you can rebuild the RPMs using: rpmbuild -ta jing-YYYYMMDD.tar.gz rpmbuild -ta trang-YYYYMMDD.tar.gz jing-trang-20131210+dfsg+1/gcj/rpmmacros000066400000000000000000000004401225366607500175630ustar00rootroot00000000000000%_rpmdir %{_jingbuilddir}/dist/gcj %_srcrpmdir %{_jingbuilddir}/dist/gcj %_specdir %{_jingbuilddir}/gcj-rpm %_sourcedir %{_jingbuilddir}/gcj-rpm %_builddir %{_jingbuilddir}/gcj-rpm %_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm %packager James Clark jing-trang-20131210+dfsg+1/gcj/rpmrc000066400000000000000000000003351225366607500167060ustar00rootroot00000000000000include: /usr/lib/rpm/rpmrc macrofiles: /usr/lib/rpm/macros:/usr/lib/rpm/%{_target}/macros:/etc/rpm/macros.specspo:/etc/rpm/macros:/etc/rpm/%{_target}/macros:gcj/rpmmacros optflags: i386 -O2 -march=i386 -mcpu=i686 jing-trang-20131210+dfsg+1/gcj/rules.mk000066400000000000000000000024571225366607500173320ustar00rootroot00000000000000all: $(PROG) test_$(PROG) $(PROG): $(PROG).o $(RESOURCES) $(GCJ) $(GCJFLAGS) $(LDFLAGS) --main=$(MAIN) -o $@ $(PROG).o $(RESOURCES) $(LIBS) test_$(PROG): $(PROG).o $(RESOURCES) $(GCJ) $(GCJFLAGS) $(LDFLAGS) --main=$(TEST_MAIN) -o $@ $(PROG).o $(RESOURCES) $(LIBS) $(PROG).o: $(SOURCES) $(GCJ) $(GCJFLAGS) -c -o $@ $(SOURCES) .resource.o: $(GCJ) $(GCJFLAGS) -c -o $@ --resource=`echo $@ | sed -e 's;src/;;' -e 's/.o$$//'` $< $(RESOURCES): dirstamp dirstamp: for d in $(DIRS); do test -d $$d || mkdir $$d; done @>$@ check: test_$(PROG) cd test; $(MAKE) install: $(PROG) $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir) $(srcdir)/mkinstalldirs $(DESTDIR)$(man1dir) $(INSTALL_PROGRAM) $(PROG) $(DESTDIR)$(bindir)/$(PROG) $(INSTALL_DATA) $(srcdir)/$(PROG).1 $(DESTDIR)$(man1dir)/$(PROG).1 uninstall: -rm -f $(DESTDIR)$(bindir)/$(PROG) -rm -f $(DESTDIR)$(man1dir)/$(PROG).1 clean: -rm -f dirstamp $(PROG) $(PROG).o $(RESOURCES) -rmdir `for d in $(DIRS); do echo $$d; done | sort -r` cd test; $(MAKE) clean $(srcdir)/configure: configure.ac cd $(srcdir) && autoconf Makefile: Makefile.in config.status ./config.status config.status: configure ./config.status --recheck distclean: clean -rm -f config.status config.cache config.log .SUFFIXES: .resource .PHONY: all check distclean clean install uninstall jing-trang-20131210+dfsg+1/gcj/test_jing.mk000066400000000000000000000042401225366607500201560ustar00rootroot00000000000000srcdir=@srcdir@ XSLTPROC=xsltproc check: spec-check mns-check nrl-check xsd-check spec-check: spec-split/stamp ../test_jing spec-test.log spec-split spec-prepped.xml: $(srcdir)/spectest.xml $(srcdir)/prep.xsl $(XSLTPROC) -o $@ --stringparam dir spec-split $(srcdir)/prep.xsl $(srcdir)/spectest.xml 2>/dev/null spec-split/stamp: spec-prepped.xml $(srcdir)/exslt.xsl -mkdir spec-split -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl spec-prepped.xml 2>/dev/null` $(XSLTPROC) $(srcdir)/exslt.xsl spec-prepped.xml 2>/dev/null @>$@ mns-check: mns-split/stamp ../test_jing mns-test.log mns-split mns-prepped.xml: $(srcdir)/mnstest.xml $(srcdir)/prep.xsl $(XSLTPROC) -o $@ --stringparam dir mns-split $(srcdir)/prep.xsl $(srcdir)/mnstest.xml 2>/dev/null mns-split/stamp: mns-prepped.xml $(srcdir)/exslt.xsl -mkdir mns-split -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl mns-prepped.xml 2>/dev/null` $(XSLTPROC) $(srcdir)/exslt.xsl mns-prepped.xml 2>/dev/null @>$@ nrl-check: nrl-split/stamp ../test_jing nrl-test.log nrl-split nrl-prepped.xml: $(srcdir)/nrltest.xml $(srcdir)/prep.xsl $(XSLTPROC) -o $@ --stringparam dir nrl-split $(srcdir)/prep.xsl $(srcdir)/nrltest.xml 2>/dev/null nrl-split/stamp: nrl-prepped.xml $(srcdir)/exslt.xsl -mkdir nrl-split -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl nrl-prepped.xml 2>/dev/null` $(XSLTPROC) $(srcdir)/exslt.xsl nrl-prepped.xml 2>/dev/null @>$@ xsd-check: xsd-split/stamp ../test_jing xsd-test.log xsd-split xsd-test-suite.xml: $(srcdir)/xsdtest.xml $(srcdir)/xsdtest.xsl $(XSLTPROC) -o $@ $(srcdir)/xsdtest.xsl $(srcdir)/xsdtest.xml xsd-prepped.xml: xsd-test-suite.xml $(srcdir)/prep.xsl $(XSLTPROC) -o $@ --stringparam dir xsd-split $(srcdir)/prep.xsl xsd-test-suite.xml 2>/dev/null xsd-split/stamp: xsd-prepped.xml $(srcdir)/exslt.xsl -mkdir xsd-split -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl xsd-prepped.xml ` $(XSLTPROC) $(srcdir)/exslt.xsl xsd-prepped.xml 2>/dev/null @>$@ clean: -rm -fr spec-split spec-prepped.xml -rm -fr xsd-split xsd-prepped.xml xsd-test-suite.xml -rm -fr mns-split mns-prepped.xml mns-test-suite.xml -rm -fr nrl-split nrl-prepped.xml nrl-test-suite.xml .PHONY: clean check spec-check xsd-check mns-check nrl-check jing-trang-20131210+dfsg+1/gcj/test_trang.mk000066400000000000000000000025121225366607500203420ustar00rootroot00000000000000srcdir=@srcdir@ XSLTPROC=xsltproc FIXCR=sed -e "s/`echo x | tr x '\015'`/\\&\#xD;/g" check: compact-check xsd-check compact-check: compact-split/stamp ../test_trang xsd.log compact-split xml xsd-check: xsd-split/stamp ../test_trang compact.log xsd-split xsd compact-prepped.xml: $(srcdir)/compacttest.xml $(srcdir)/prep.xsl $(XSLTPROC) --stringparam dir compact-split $(srcdir)/prep.xsl $(srcdir)/compacttest.xml | $(FIXCR) >$@ compact-split/stamp: compact-prepped.xml $(srcdir)/exslt.xsl $(srcdir)/dir.xsl -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl compact-prepped.xml` $(XSLTPROC) $(srcdir)/exslt.xsl compact-prepped.xml @for f in compact-split/*/xml/c.rng; do \ $(FIXCR) $$f >tem; mv tem $$f; \ done # Work around another bug in xsltproc @f=`grep -l ' foo="val"' compact-split/*/xml/c.rng`; \ if [ -f "$$f" ] ; then \ sed -e 's/ foo=/ rng:foo=/' $$f >tem; mv tem $$f; \ fi @>$@ xsd-prepped.xml: $(srcdir)/toxsdtest.xml $(srcdir)/prep.xsl $(XSLTPROC) -o $@ --stringparam dir xsd-split $(srcdir)/prep.xsl $(srcdir)/toxsdtest.xml xsd-split/stamp: xsd-prepped.xml $(srcdir)/exslt.xsl $(srcdir)/dir.xsl -mkdir `$(XSLTPROC) $(srcdir)/dir.xsl xsd-prepped.xml` $(XSLTPROC) $(srcdir)/exslt.xsl xsd-prepped.xml @>$@ clean: -rm -fr compact-split xsd-split compact-prepped.xml xsd-prepped.xml .PHONY: check xsd-check compact-check clean jing-trang-20131210+dfsg+1/gcj/todo.txt000066400000000000000000000003151225366607500173440ustar00rootroot00000000000000Sign RPM file Detect with -lpthread is needed Instead of removing unneeded sources, omit them from compile list. Include some examples and additional documentation in the dist. Include regex-test in jing. jing-trang-20131210+dfsg+1/gcj/trang.1000066400000000000000000000053441225366607500170420ustar00rootroot00000000000000.TH trang 1 @VERSION@ .SH NAME trang \- convert between different schema languages for XML .SH SYNOPSIS .B trang .RB [ \-I .BR rng | rnc | dtd | xml ] .RB [ \-O .BR rng | rnc | dtd | xsd ] .RB [ \-i .IR input-param ] .RB [ \-o .IR output-param ] .IR input-file " ..." .I output-file .SH DESCRIPTION .B trang takes as input a schema written in any of the following formats: .IP RELAX NG (XML syntax) .IP RELAX NG (compact syntax) .IP XML 1.0 DTD .PP and produces as output a schema written in any of the following formats: .IP RELAX NG (XML syntax) .IP RELAX NG (compact syntax) .IP XML 1.0 DTD .IP W3C XML Schema .PP Trang can also infer a schema from one or more example XML documents. .PP Trang uses an internal representation based on RELAX NG. For each supported input format, there is an input module that converts a schema in that input format into this internal representation. For each supported output format, there is an output module that converts the internal representation into a schema in that output format. Thus, any supported input format can be translated to any supported output format. .PP Trang requires two command-line arguments: the first is the URI or filename of the schema to be translated; the second is the output filename. .PP Trang infers the input and output modules to be used from the extension of input and output filenames as follows: .TP .B .rng RELAX NG (XML syntax) .TP .B .rnc RELAX NG (compact syntax) .TP .B .dtd XML 1.0 DTD .TP .B .xsd W3C XML Schema .TP .B .xml XML documents (used as examples from which to infer a schema) .PP This inference can be overridden using the .B \-I and .B \-O options. .LP When the input is XML documents used as examples to infer a schema, more than one input file may be specified as arguments. All the input files are specified before the output file. .SH OPTIONS .TP .BR "\-I rng" | rnc | dtd | xml Specifies which input module to use. .TP .BR "\-O rng" | rnc | dtd | xsd Specifies which output module to use. .TP .BI \-i " input-param" .TP .BI \-o " output-param" Specifies a parameter for an input .RB ( \-i ) or output .RB ( \-o ) module. The .B \-i and .B \-o options may be used multiple times in order to specify multiple parameters. There are two kinds of parameter: boolean parameters and string-valued parameters. A string-valued parameter is specified using the form .IB name = value\fR. A boolean parameter is specified using the form .I name or .BI no- name\fR. The applicable parameters depend on the particular input and output module. For details, see the HTML documentation. .SH "SEE ALSO" .BR jing (1) .LP Trang Manual .PP http://relaxng.org .SH AUTHOR James Clark (jjc@jclark.com) .PP This product includes software developed by the Apache Software Foundation (http://www.apache.org/). jing-trang-20131210+dfsg+1/gcj/trang.spec000066400000000000000000000032631225366607500176320ustar00rootroot00000000000000Summary: Multi-format schema converter based on RELAX NG. Name: trang Version: Release: 1 URL: http://www.thaiopensource.com/relaxng/ Source: %{name}-%{version}.tar.gz License: BSD Group: Applications/Text BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gcc-java >= 3.2-7 %description Trang converts between different schema languages for XML. It supports the following languages: RELAX NG (both XML and compact syntax), XML 1.0 DTDs, W3C XML Schema. A schema written in any of the supported schema languages can be converted into any of the other supported schema languages, except that W3C XML Schema is supported for output only, not for input. Trang can also infer a schema from one or more example XML documents. Trang is constructed around an RELAX NG object model designed to support schema conversion. For each schema language supported for input, there is an input module that can convert from the schema language into this internal object model. Similarly, for each schema language supported for output, there is an output module that can convert from the internal object model in the schema language. Trang aims to produce human-understandable schemas; it tries for a translation that preserves all aspects of the input schema that may be significant to a human reader, including the definitions, the way the schema is divided into files, annotations and comments. %prep %setup -q %build %configure GCJFLAGS="${GCJFLAGS:-%optflags}" make %install rm -rf $RPM_BUILD_ROOT %makeinstall %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/trang %{_mandir}/man1/trang.1* %doc trang-manual.html %changelog * Sat Feb 22 2003 James Clark - Initial build. jing-trang-20131210+dfsg+1/gcj/vars.mk000066400000000000000000000005351225366607500171460ustar00rootroot00000000000000SHELL=/bin/sh srcdir = @srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = @mandir@ man1dir = $(mandir)/man1 GCJ=@GCJ@ GCJFLAGS=@GCJFLAGS@ LDFLAGS=@LDFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ PROG=@PROG@ MAIN=@MAIN@ TEST_MAIN=@TEST_MAIN@ LIBS=@LIBS@ jing-trang-20131210+dfsg+1/iml.xsl000066400000000000000000000031001225366607500163770ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/jing-trang.ipr000066400000000000000000000701541225366607500176570ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/jing.bat000077500000000000000000000023121225366607500165140ustar00rootroot00000000000000@echo off setlocal set MAIN_CLASS=com.thaiopensource.relaxng.util.Driver set JAR_FILE=jing.jar set JAVA_PROBLEM_EXIT_CODE=1 set JRE_KEY=HKLM\SOFTWARE\JavaSoft\Java Runtime Environment set JAVA_VERSION=unknown if not exist "%JAVA_HOME%\bin\java.exe" ( for /f "tokens=2* skip=2" %%u in ('reg query "%JRE_KEY%" /v CurrentVersion') do for /f "tokens=2* skip=2" %%i in ('reg query "%JRE_KEY%\%%v" /v JavaHome') do ( set JAVA_VERSION=%%v set JAVA_HOME=%%j ) ) 2>nul if exist "%JAVA_HOME%\bin\java.exe" goto found_java echo Could not find a Java Runtime Environment. Download one from http://java.sun.com/javase/downloads/. exit /b %JAVA_PROBLEM_EXIT_CODE% :found_java if not x1.4==x%JAVA_VERSION% if not x1.3==x%JAVA_VERSION% goto java_version_ok echo Version 5.0 or newer of the Java Runtime Environment is required. Download one from http://java.sun.com/javase/downloads/. exit /b %JAVA_PROBLEM_EXIT_CODE% :java_version_ok set JAR_DIR=%~dp0 if exist "%JAR_DIR%%JAR_FILE%" goto found_jar echo Could not find %JAR_FILE%. Must be in the same directory as %~nx0 (%JAR_DIR%). exit /b %JAVA_PROBLEM_EXIT_CODE% :found_jar "%JAVA_HOME%\bin\java.exe" -classpath "%JAR_DIR%%JAR_FILE%" %MAIN_CLASS% %* jing-trang-20131210+dfsg+1/mod/000077500000000000000000000000001225366607500156535ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/000077500000000000000000000000001225366607500172655ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/mod.xml000066400000000000000000000002451225366607500205670ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/catalog/src/000077500000000000000000000000001225366607500200545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/000077500000000000000000000000001225366607500210005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/000077500000000000000000000000001225366607500215565ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/000077500000000000000000000000001225366607500246065ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/000077500000000000000000000000001225366607500264475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalog/000077500000000000000000000000001225366607500300615ustar00rootroot00000000000000CatalogEntityResolver.java000066400000000000000000000023061225366607500351370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import org.apache.xml.resolver.helpers.BootstrapResolver; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; import java.net.URL; /** * An EntityResolver for use when parsing catalogs. */ class CatalogEntityResolver implements EntityResolver { private final EntityResolver entityResolver; CatalogEntityResolver(EntityResolver entityResolver) { this.entityResolver = entityResolver; } public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (BootstrapResolver.xmlCatalogPubId.equals(publicId) || BootstrapResolver.xmlCatalogSysId.equals(systemId)) { URL url = BootstrapResolver.class.getResource("/org/apache/xml/resolver/etc/catalog.dtd"); if (url != null) { InputSource in = new InputSource(url.toString()); // Avoid any weirdness the parser may perform on URLs in.setByteStream(url.openStream()); in.setPublicId(publicId); return in; } } if (entityResolver != null) return entityResolver.resolveEntity(publicId, systemId); return null; } } CatalogResolver.java000066400000000000000000000062171225366607500337470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import com.thaiopensource.resolver.AbstractResolver; import com.thaiopensource.resolver.BasicResolver; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalDTDSubsetIdentifier; import com.thaiopensource.resolver.xml.ExternalEntityIdentifier; import com.thaiopensource.resolver.xml.ExternalIdentifier; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.apache.xml.resolver.Catalog; import java.io.IOException; import java.util.List; /** * A Resolver that uses OASIS XML catalogs. */ public class CatalogResolver extends AbstractResolver { private final Catalog catalog; private boolean catalogLoaded = false; private boolean hadCatalogError = false; // Allow somebody to customize in a different way, but still use our resolve logic. public CatalogResolver(Catalog catalog) { this.catalog = catalog; } public CatalogResolver(List catalogUris, SAXResolver resolver) { this(new OasisCatalog(new SimpleCatalogManager(catalogUris), resolver)); } public CatalogResolver(List catalogUris, Resolver resolver) { this(catalogUris, new SAXResolver(resolver)); } public CatalogResolver(List catalogUris) { this(catalogUris, new SAXResolver()); } public synchronized void resolve(Identifier id, Input input) throws IOException, ResolverException { if (input.isResolved()) return; if (hadCatalogError) return; String absoluteUri = null; try { absoluteUri = BasicResolver.resolveUri(id); if (id.getUriReference().equals(absoluteUri)) absoluteUri = null; } catch (ResolverException e) { // ignore } String resolved = null; boolean isExternalIdentifier = (id instanceof ExternalIdentifier); try { if (!catalogLoaded) { catalogLoaded = true; catalog.loadSystemCatalogs(); } if (absoluteUri != null) resolved = isExternalIdentifier ? catalog.resolveSystem(absoluteUri) : catalog.resolveURI(absoluteUri); if (resolved == null) { if (!isExternalIdentifier) resolved = catalog.resolveURI(id.getUriReference()); else if (id instanceof ExternalEntityIdentifier) { ExternalEntityIdentifier xid = (ExternalEntityIdentifier)id; resolved = catalog.resolveEntity(xid.getEntityName(), xid.getPublicId(), xid.getUriReference()); } else if (id instanceof ExternalDTDSubsetIdentifier) { ExternalDTDSubsetIdentifier xid = (ExternalDTDSubsetIdentifier)id; resolved = catalog.resolveDoctype(xid.getDoctypeName(), xid.getPublicId(), xid.getUriReference()); } else { ExternalIdentifier xid = (ExternalIdentifier)id; resolved = catalog.resolvePublic(xid.getPublicId(), xid.getUriReference()); } } } catch (ResolverIOException e) { hadCatalogError = true; throw e.getResolverException(); } if (resolved != null) input.setUri(resolved); } } OasisCatalog.java000066400000000000000000000042151225366607500332200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.XMLDocumentIdentifier; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.sax.DraconianErrorHandler; import org.apache.xml.resolver.Catalog; import org.apache.xml.resolver.CatalogManager; import org.apache.xml.resolver.readers.OASISXMLCatalogReader; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.transform.sax.SAXSource; import java.io.IOException; import java.net.URL; /** * A catalog with customized parsing of catalog files. In particular, it only supports * OASIS XML Catalogs and it uses a SAXResolver for access to the catalog URIs. */ class OasisCatalog extends Catalog { private final SAXResolver saxResolver; OasisCatalog(CatalogManager catalogManager, SAXResolver saxResolver) { super(catalogManager); this.saxResolver = saxResolver; // don't call setupReaders; since we use our own parseCatalogFile // we'll load the catalogs lazily } protected void parseCatalogFile(String uri) throws IOException { OASISXMLCatalogReader catalogReader = new OASISXMLCatalogReader(); try { SAXSource source = saxResolver.resolve(new XMLDocumentIdentifier(uri, null, OASISXMLCatalogReader.namespaceName)); String systemId = source.getInputSource().getSystemId(); if (systemId == null) systemId = uri; base = new URL(systemId); catalogReader.setCatalog(this); XMLReader xmlReader = source.getXMLReader(); xmlReader.setEntityResolver(new CatalogEntityResolver(xmlReader.getEntityResolver())); xmlReader.setContentHandler(catalogReader); xmlReader.setErrorHandler(new DraconianErrorHandler()); xmlReader.parse(source.getInputSource()); } catch (SAXException e) { Exception wrapped = e.getException(); // this will get unwrapped by CatalogResolver throw new ResolverIOException(wrapped instanceof ResolverException ? (ResolverException)wrapped : new ResolverException(e)); } } } ResolverIOException.java000066400000000000000000000010401225366607500345500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import com.thaiopensource.resolver.ResolverException; import java.io.IOException; /** * A wrapper for a ResolverException to allow it to be passed up by the catalog parser. */ public class ResolverIOException extends IOException { private final ResolverException resolverException; public ResolverIOException(ResolverException resolverException) { this.resolverException = resolverException; } public ResolverException getResolverException() { return resolverException; } } SimpleCatalogManager.java000066400000000000000000000017641225366607500346740ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/main/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import org.apache.xml.resolver.CatalogManager; import java.util.List; import java.util.Vector; /** * A very simple CatalogManager that does not use use property file/system property customization. */ class SimpleCatalogManager extends CatalogManager { private final Vector catalogUris; SimpleCatalogManager(List catalogUris) { this.catalogUris = new Vector(); this.catalogUris.addAll(catalogUris); // disable printing to System.out setVerbosity(0); } public Vector getCatalogFiles() { return catalogUris; } public boolean getRelativeCatalogs() { return false; } public boolean getPreferPublic() { return true; } public boolean getIgnoreMissingProperties() { return true; } public boolean getAllowOasisXMLCatalogPI() { return false; } public boolean getUseStaticCatalog() { return false; } public String getCatalogClassName() { return null; } } jing-trang-20131210+dfsg+1/mod/catalog/src/test/000077500000000000000000000000001225366607500210335ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/000077500000000000000000000000001225366607500216115ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/000077500000000000000000000000001225366607500246415ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/resolver/000077500000000000000000000000001225366607500265025ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/resolver/catalog/000077500000000000000000000000001225366607500301145ustar00rootroot00000000000000CatalogResolverTest.java000066400000000000000000000025371225366607500346430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/resolver/catalogpackage com.thaiopensource.resolver.catalog; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalIdentifier; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.testng.Assert; import org.testng.annotations.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Tests CatalogResolver. */ public class CatalogResolverTest { @Test public void testResolve() throws IOException, ResolverException { List catalogs = new ArrayList(); catalogs.add(resourceUri("catalog.xml")); Resolver resolver = new CatalogResolver(catalogs, new SAXResolver(null)); ExternalIdentifier xid = new ExternalIdentifier("foo.xml", "http://www.example.com/index.html", "The Great Foo"); Input input = new Input(); resolver.resolve(xid, input); Assert.assertEquals(input.getUri(), "http://www.example.com/bar.xml"); } static String resourceUri(String fileName) { String className = CatalogResolverTest.class.getName(); int dotIndex = className.lastIndexOf('.'); String resourceName = className.substring(0, dotIndex + 1).replace('.', '/') + fileName; return CatalogResolverTest.class.getClassLoader().getResource(resourceName).toString(); } } jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/resolver/catalog/catalog.xml000066400000000000000000000004021225366607500322440ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/catalog/src/test/com/thaiopensource/resolver/catalog/catalog2.xml000066400000000000000000000004431225366607500323330ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/convert-from-dtd/000077500000000000000000000000001225366607500210455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/mod.xml000066400000000000000000000002331225366607500223440ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/000077500000000000000000000000001225366607500216345ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/000077500000000000000000000000001225366607500225605ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/000077500000000000000000000000001225366607500233365ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/000077500000000000000000000000001225366607500263665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500300265ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/000077500000000000000000000000001225366607500311655ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtd/000077500000000000000000000000001225366607500317405ustar00rootroot00000000000000Converter.java000066400000000000000000001070051225366607500344760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtdpackage com.thaiopensource.relaxng.input.dtd; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Combine; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.input.CommentTrimmer; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.xml.dtd.om.AttributeDefault; import com.thaiopensource.xml.dtd.om.AttributeGroup; import com.thaiopensource.xml.dtd.om.AttributeGroupMember; import com.thaiopensource.xml.dtd.om.AttributeGroupVisitor; import com.thaiopensource.xml.dtd.om.Datatype; import com.thaiopensource.xml.dtd.om.DatatypeVisitor; import com.thaiopensource.xml.dtd.om.Def; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.om.EnumGroup; import com.thaiopensource.xml.dtd.om.EnumGroupVisitor; import com.thaiopensource.xml.dtd.om.Flag; import com.thaiopensource.xml.dtd.om.ModelGroup; import com.thaiopensource.xml.dtd.om.ModelGroupVisitor; import com.thaiopensource.xml.dtd.om.NameSpec; import com.thaiopensource.xml.dtd.om.TokenizedDatatype; import com.thaiopensource.xml.dtd.om.TopLevel; import com.thaiopensource.xml.dtd.om.TopLevelVisitor; import com.thaiopensource.xml.em.ExternalId; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; public class Converter { static class Options { boolean inlineAttlistDecls; boolean generateStart = true; boolean strictAny; String elementDeclPattern; String attlistDeclPattern; String colonReplacement; String anyName; String annotationPrefix; String defaultNamespace; final Map prefixMap = new HashMap(); } private final Dtd dtd; private final ErrorReporter er; private final SchemaCollection sc = new SchemaCollection(); private final Options options; /** * true if any uses of ANY have been encountered in the DTD */ private boolean hadAny = false; /** * true if any default values have been encountered in the DTD */ private boolean hadDefaultValue = false; /** * Maps each element name to an Integer containing a set of flags. */ private final Map elementNameTable = new HashMap(); /** * Maps each element name to a List of attribute groups of each attlist declaration. */ private final Map> attlistDeclTable = new HashMap>(); /** * Set of strings representing names for which there are definitions in the DTD. */ private final Set definedNames = new HashSet(); /** * Maps prefixes to namespace URIs. */ private final Map prefixTable = new HashMap(); /** * Maps a string representing an element name to the set of names of attributes * that have been declated for that element. */ private final Map> attributeNamesTable = new HashMap>(); /** * Contains the set of attribute names that have already been output in the current scope. */ private Set attributeNames = null; private String defaultNamespace = null; private String annotationPrefix = null; // These variables control the names use for definitions. private String colonReplacement = null; private String elementDeclPattern = null; private String attlistDeclPattern = null; private String anyName = null; /** * Flags for element names used in elementDeclTable. */ private static final int ELEMENT_DECL = 01; private static final int ATTLIST_DECL = 02; private static final int ELEMENT_REF = 04; /** * Characters that will be considered for use as a replacement for colon in * a QName. Also used as separators in constructing names of definitions * corresponding to element declarations and attlist declarations, */ private static final String SEPARATORS = ".-_"; // # is the category; % is the name in the category private static final String DEFAULT_PATTERN = "#.%"; private final String[] ELEMENT_KEYWORDS = { "element", "elem", "e" }; private final String[] ATTLIST_KEYWORDS = { "attlist", "attributes", "attribs", "atts", "a" }; private final String[] ANY_KEYWORDS = { "any", "ANY", "anyElement" }; private static abstract class VisitorBase implements TopLevelVisitor { public void processingInstruction(String target, String value) throws Exception { } public void comment(String value) throws Exception { } public void flagDef(String name, Flag flag) throws Exception { } public void includedSection(Flag flag, TopLevel[] contents) throws Exception { for (int i = 0; i < contents.length; i++) contents[i].accept(this); } public void ignoredSection(Flag flag, String contents) throws Exception { } public void internalEntityDecl(String name, String value) throws Exception { } public void externalEntityDecl(String name, ExternalId externalId) throws Exception { } public void notationDecl(String name, ExternalId externalId) throws Exception { } public void nameSpecDef(String name, NameSpec nameSpec) throws Exception { } public void overriddenDef(Def def, boolean isDuplicate) throws Exception { } public void externalIdDef(String name, ExternalId externalId) throws Exception { } public void externalIdRef(String name, ExternalId externalId, String uri, String encoding, TopLevel[] contents) throws Exception { for (int i = 0; i < contents.length; i++) contents[i].accept(this); } public void paramDef(String name, String value) throws Exception { } public void attributeDefaultDef(String name, AttributeDefault ad) throws Exception { } } private class Analyzer extends VisitorBase implements ModelGroupVisitor, AttributeGroupVisitor { public void elementDecl(NameSpec nameSpec, ModelGroup modelGroup) throws Exception { noteElementName(nameSpec.getValue(), ELEMENT_DECL); modelGroup.accept(this); } public void attlistDecl(NameSpec nameSpec, AttributeGroup attributeGroup) throws Exception { noteElementName(nameSpec.getValue(), ATTLIST_DECL); noteAttlist(nameSpec.getValue(), attributeGroup); attributeGroup.accept(this); } public void modelGroupDef(String name, ModelGroup modelGroup) throws Exception { noteDef(name); modelGroup.accept(this); } public void attributeGroupDef(String name, AttributeGroup attributeGroup) throws Exception { noteDef(name); attributeGroup.accept(this); } public void enumGroupDef(String name, EnumGroup enumGroup) { noteDef(name); } public void datatypeDef(String name, Datatype datatype) { noteDef(name); } public void choice(ModelGroup[] members) throws Exception { for (int i = 0; i < members.length; i++) members[i].accept(this); } public void sequence(ModelGroup[] members) throws Exception { for (int i = 0; i < members.length; i++) members[i].accept(this); } public void oneOrMore(ModelGroup member) throws Exception { member.accept(this); } public void zeroOrMore(ModelGroup member) throws Exception { member.accept(this); } public void optional(ModelGroup member) throws Exception { member.accept(this); } public void modelGroupRef(String name, ModelGroup modelGroup) { } public void elementRef(NameSpec name) { noteElementName(name.getValue(), ELEMENT_REF); } public void pcdata() { } public void any() { hadAny = true; } public void attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) { noteAttribute(nameSpec.getValue(), attributeDefault.getDefaultValue()); } public void attributeGroupRef(String name, AttributeGroup attributeGroup) { } } private class ComponentOutput extends VisitorBase { private final List components; private final Annotated grammar; private List comments = null; ComponentOutput(GrammarPattern grammar) { components = grammar.getComponents(); this.grammar = grammar; } void finish() { if (comments != null) grammar.getFollowingElementAnnotations().addAll(comments); } private void addComponent(Component c) { if (comments != null) { if (components.isEmpty()) grammar.getLeadingComments().addAll(comments); else c.getLeadingComments().addAll(comments); comments = null; } components.add(c); } public void elementDecl(NameSpec nameSpec, ModelGroup modelGroup) throws Exception { GroupPattern gp = new GroupPattern(); if (options.inlineAttlistDecls) { List groups = attlistDeclTable.get(nameSpec.getValue()); if (groups != null) { attributeNames = new HashSet(); AttributeGroupVisitor agv = new AttributeGroupOutput(gp); for (AttributeGroup group : groups) group.accept(agv); } } else gp.getChildren().add(ref(attlistDeclName(nameSpec.getValue()))); Pattern pattern = convert(modelGroup); if (gp.getChildren().size() > 0) { if (pattern instanceof GroupPattern) gp.getChildren().addAll(((GroupPattern)pattern).getChildren()); else gp.getChildren().add(pattern); pattern = gp; } addComponent(new DefineComponent(elementDeclName(nameSpec.getValue()), new ElementPattern(convertQName(nameSpec.getValue(), true), pattern))); if (!options.inlineAttlistDecls && (nameFlags(nameSpec.getValue()) & ATTLIST_DECL) == 0) { DefineComponent dc = new DefineComponent(attlistDeclName(nameSpec.getValue()), new EmptyPattern()); dc.setCombine(Combine.INTERLEAVE); addComponent(dc); } if (anyName != null && options.strictAny) { DefineComponent dc = new DefineComponent(anyName, ref(elementDeclName(nameSpec.getValue()))); dc.setCombine(Combine.CHOICE); addComponent(dc); } } public void attlistDecl(NameSpec nameSpec, AttributeGroup attributeGroup) throws Exception { if (options.inlineAttlistDecls) return; String name = nameSpec.getValue(); attributeNames = attributeNamesTable.get(name); if (attributeNames == null) { attributeNames = new HashSet(); attributeNamesTable.put(name, attributeNames); } Pattern pattern = convert(attributeGroup); if (pattern instanceof EmptyPattern) { // Only keep an empty definition if this is the first attlist for this element, // and all attlists are also empty. In this case, if we didn't keep the // definition, we would have no definition for the attlist. List decls = attlistDeclTable.get(name); if (decls.get(0) != attributeGroup) return; attributeNames = new HashSet(); for (int i = 1, len = decls.size(); i < len; i++) if (!(convert(decls.get(i)) instanceof EmptyPattern)) return; } DefineComponent dc = new DefineComponent(attlistDeclName(name), pattern); dc.setCombine(Combine.INTERLEAVE); addComponent(dc); } public void modelGroupDef(String name, ModelGroup modelGroup) throws Exception { addComponent(new DefineComponent(name, convert(modelGroup))); } public void attributeGroupDef(String name, AttributeGroup attributeGroup) throws Exception { // This takes care of duplicates within the group attributeNames = new HashSet(); Pattern pattern; AttributeGroupMember[] members = attributeGroup.getMembers(); GroupPattern group = new GroupPattern(); AttributeGroupVisitor agv = new AttributeGroupOutput(group); for (int i = 0; i < members.length; i++) members[i].accept(agv); switch (group.getChildren().size()) { case 0: pattern = new EmptyPattern(); break; case 1: pattern = group.getChildren().get(0); break; default: pattern = group; break; } addComponent(new DefineComponent(name, pattern)); } public void enumGroupDef(String name, EnumGroup enumGroup) throws Exception { ChoicePattern choice = new ChoicePattern(); enumGroup.accept(new EnumGroupOutput(choice)); Pattern pattern; switch (choice.getChildren().size()) { case 0: pattern = new NotAllowedPattern(); break; case 1: pattern = choice.getChildren().get(0); break; default: pattern = choice; break; } addComponent(new DefineComponent(name, pattern)); } public void datatypeDef(String name, Datatype datatype) throws Exception { addComponent(new DefineComponent(name, convert(datatype))); } public void comment(String value) { if (comments == null) comments = new Vector(); comments.add(new Comment(CommentTrimmer.trimComment(value))); } public void externalIdRef(String name, ExternalId externalId, String uri, String encoding, TopLevel[] contents) throws Exception { if (uri == null) { // I don't think this can happen super.externalIdRef(name, externalId, uri, encoding, contents); return; } SignificanceDetector sd = new SignificanceDetector(); try { sd.externalIdRef(name, externalId, uri, encoding, contents); if (!sd.significant) return; } catch (Exception e) { throw (RuntimeException)e; } if (sc.getSchemaDocumentMap().get(uri) != null) { // I don't think this can happen because the second and subsequent inclusions // will never pass the SignificanceDetector, but just in case super.externalIdRef(name, externalId, uri, encoding, contents); return; } IncludeComponent ic = new IncludeComponent(uri); ic.setNs(defaultNamespace); addComponent(ic); GrammarPattern included = new GrammarPattern(); ComponentOutput co = new ComponentOutput(included); for (int i = 0; i < contents.length; i++) contents[i].accept(co); co.finish(); sc.getSchemaDocumentMap().put(uri, new SchemaDocument(included, encoding)); } } private class AttributeGroupOutput implements AttributeGroupVisitor { final List group; AttributeGroupOutput(GroupPattern gp) { group = gp.getChildren(); } public void attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) throws Exception { String name = nameSpec.getValue(); if (attributeNames.contains(name)) return; attributeNames.add(name); if (name.equals("xmlns") || name.startsWith("xmlns:")) return; String dv = attributeDefault.getDefaultValue(); String fv = attributeDefault.getFixedValue(); Pattern dt; if (fv != null) { String[] typeName = valueType(datatype); dt = new ValuePattern(typeName[0], typeName[1], fv); } else if (datatype.getType() != Datatype.CDATA) dt = convert(datatype); else dt = new TextPattern(); AttributePattern pattern = new AttributePattern(convertQName(name, false), dt); if (dv != null) { AttributeAnnotation anno = new AttributeAnnotation(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS, "defaultValue", dv); anno.setPrefix(annotationPrefix); pattern.getAttributeAnnotations().add(anno); } if (!attributeDefault.isRequired()) group.add(new OptionalPattern(pattern)); else group.add(pattern); } public void attributeGroupRef(String name, AttributeGroup attributeGroup) throws Exception { DuplicateAttributeDetector detector = new DuplicateAttributeDetector(); attributeGroup.accept(detector); if (detector.containsDuplicate) attributeGroup.accept(this); else { group.add(ref(name)); attributeNames.addAll(detector.names); } } } private class DatatypeOutput implements DatatypeVisitor { Pattern pattern; public void cdataDatatype() { pattern = new DataPattern("", "string"); } public void tokenizedDatatype(String typeName) { pattern = new DataPattern(WellKnownNamespaces.XML_SCHEMA_DATATYPES, typeName); } public void enumDatatype(EnumGroup enumGroup) throws Exception { if (enumGroup.getMembers().length == 0) pattern = new NotAllowedPattern(); else { ChoicePattern tem = new ChoicePattern(); pattern = tem; enumGroup.accept(new EnumGroupOutput(tem)); } } public void notationDatatype(EnumGroup enumGroup) throws Exception { enumDatatype(enumGroup); } public void datatypeRef(String name, Datatype datatype) { pattern = ref(name); } } private class EnumGroupOutput implements EnumGroupVisitor { final private List list; EnumGroupOutput(ChoicePattern choice) { list = choice.getChildren(); } public void enumValue(String value) { list.add(new ValuePattern("", "token", value)); } public void enumGroupRef(String name, EnumGroup enumGroup) { list.add(ref(name)); } } private class ModelGroupOutput implements ModelGroupVisitor { private Pattern pattern; public void choice(ModelGroup[] members) throws Exception { if (members.length == 0) pattern = new NotAllowedPattern(); else if (members.length == 1) members[0].accept(this); else { ChoicePattern tem = new ChoicePattern(); pattern = tem; List children = tem.getChildren(); for (int i = 0; i < members.length; i++) children.add(convert(members[i])); } } public void sequence(ModelGroup[] members) throws Exception { if (members.length == 0) pattern = new EmptyPattern(); else if (members.length == 1) members[0].accept(this); else { GroupPattern tem = new GroupPattern(); pattern = tem; List children = tem.getChildren(); for (int i = 0; i < members.length; i++) children.add(convert(members[i])); } } public void oneOrMore(ModelGroup member) throws Exception { pattern = new OneOrMorePattern(convert(member)); } public void zeroOrMore(ModelGroup member) throws Exception { pattern = new ZeroOrMorePattern(convert(member)); } public void optional(ModelGroup member) throws Exception { pattern = new OptionalPattern(convert(member)); } public void modelGroupRef(String name, ModelGroup modelGroup) { pattern = ref(name); } public void elementRef(NameSpec name) { pattern = ref(elementDeclName(name.getValue())); } public void pcdata() { pattern = new TextPattern(); } public void any() { pattern = ref(anyName); if (options.strictAny) pattern = new ZeroOrMorePattern(pattern); } } private class DuplicateAttributeDetector implements AttributeGroupVisitor { private boolean containsDuplicate = false; private final List names = new Vector(); public void attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) { String name = nameSpec.getValue(); if (attributeNames.contains(name)) containsDuplicate = true; names.add(name); } public void attributeGroupRef(String name, AttributeGroup attributeGroup) throws Exception { attributeGroup.accept(this); } } private class SignificanceDetector extends VisitorBase { boolean significant = false; public void elementDecl(NameSpec nameSpec, ModelGroup modelGroup) throws Exception { significant = true; } public void attlistDecl(NameSpec nameSpec, AttributeGroup attributeGroup) throws Exception { significant = true; } public void modelGroupDef(String name, ModelGroup modelGroup) throws Exception { significant = true; } public void attributeGroupDef(String name, AttributeGroup attributeGroup) throws Exception { significant = true; } public void enumGroupDef(String name, EnumGroup enumGroup) { significant = true; } public void datatypeDef(String name, Datatype datatype) { significant = true; } } public Converter(Dtd dtd, ErrorReporter er, Options options) { this.dtd = dtd; this.er = er; this.options = options; } public SchemaCollection convert() { try { dtd.accept(new Analyzer()); chooseNames(); GrammarPattern grammar = new GrammarPattern(); sc.setMainUri(dtd.getUri()); sc.getSchemaDocumentMap().put(dtd.getUri(), new SchemaDocument(grammar, dtd.getEncoding())); ComponentOutput co = new ComponentOutput(grammar); dtd.accept(co); outputUndefinedElements(grammar.getComponents()); if (options.generateStart) outputStart(grammar.getComponents()); outputAny(grammar.getComponents()); co.finish(); return sc; } catch (Exception e) { throw (RuntimeException)e; } } private void chooseNames() { chooseAny(); chooseColonReplacement(); chooseDeclPatterns(); choosePrefixes(); chooseAnnotationPrefix(); } private void chooseAny() { if (!hadAny) return; if (options.anyName != null) { if (!definedNames.contains(options.anyName)) { anyName = options.anyName; definedNames.add(anyName); return; } warning("cannot_use_any_name"); } for (int n = 0;; n++) { for (int i = 0; i < ANY_KEYWORDS.length; i++) { anyName = repeatChar('_', n) + ANY_KEYWORDS[i]; if (!definedNames.contains(anyName)) { definedNames.add(anyName); return; } } } } private void choosePrefixes() { if (options.defaultNamespace != null) { if (defaultNamespace != null && !defaultNamespace.equals(options.defaultNamespace)) warning("default_namespace_conflict"); defaultNamespace = options.defaultNamespace; } else if (defaultNamespace == null) defaultNamespace = NameClass.INHERIT_NS; for (Map.Entry entry : options.prefixMap.entrySet()) { String prefix = entry.getKey(); String ns = entry.getValue(); String s = prefixTable.get(prefix); if (s == null) warning("irrelevant_prefix", prefix); else { if (!s.equals("") && !s.equals(ns)) warning("prefix_conflict", prefix); prefixTable.put(prefix, ns); } } } private void chooseAnnotationPrefix() { if (!hadDefaultValue) return; if (options.annotationPrefix != null) { if (prefixTable.get(options.annotationPrefix) == null) { annotationPrefix = options.annotationPrefix; return; } warning("cannot_use_annotation_prefix"); } for (int n = 0;; n++) { annotationPrefix = repeatChar('_', n) + "a"; if (prefixTable.get(annotationPrefix) == null) return; } } private void chooseColonReplacement() { if (options.colonReplacement != null) { colonReplacement = options.colonReplacement; if (colonReplacementOk()) return; warning("cannot_use_colon_replacement"); colonReplacement = null; } if (colonReplacementOk()) return; for (int n = 1;; n++) { for (int i = 0; i < SEPARATORS.length(); i++) { colonReplacement = repeatChar(SEPARATORS.charAt(i), n); if (colonReplacementOk()) return; } } } private boolean colonReplacementOk() { Set names = new HashSet(); for (String s : elementNameTable.keySet()) { String name = mungeQName(s); if (names.contains(name)) return false; names.add(name); } return true; } private void chooseDeclPatterns() { if (options.elementDeclPattern != null) { if (patternOk(options.elementDeclPattern, null)) elementDeclPattern = options.elementDeclPattern; else warning("cannot_use_element_decl_pattern"); } if (options.attlistDeclPattern != null) { if (patternOk(options.attlistDeclPattern, elementDeclPattern)) attlistDeclPattern = options.attlistDeclPattern; else warning("cannot_use_attlist_decl_pattern"); } if (elementDeclPattern != null && attlistDeclPattern != null) return; // XXX Try to match length and case of best prefix String pattern = namingPattern(); if (elementDeclPattern == null) { if (patternOk("%", attlistDeclPattern)) elementDeclPattern = "%"; else elementDeclPattern = choosePattern(pattern, ELEMENT_KEYWORDS, attlistDeclPattern); } if (attlistDeclPattern == null) attlistDeclPattern = choosePattern(pattern, ATTLIST_KEYWORDS, elementDeclPattern); } private String choosePattern(String metaPattern, String[] keywords, String otherPattern) { for (;;) { for (int i = 0; i < keywords.length; i++) { String pattern = substitute(metaPattern, '#', keywords[i]); if (patternOk(pattern, otherPattern)) return pattern; } // add another separator metaPattern = (metaPattern.substring(0, 1) + metaPattern.substring(1, 2) + metaPattern.substring(1, 2) + metaPattern.substring(2)); } } private String namingPattern() { Map patternTable = new HashMap(); for (String name : definedNames) { for (int i = 0; i < SEPARATORS.length(); i++) { char sep = SEPARATORS.charAt(i); int k = name.indexOf(sep); if (k > 0) inc(patternTable, name.substring(0, k + 1) + "%"); k = name.lastIndexOf(sep); if (k >= 0 && k < name.length() - 1) inc(patternTable, "%" + name.substring(k)); } } String bestPattern = null; int bestCount = 0; for (Map.Entry entry : patternTable.entrySet()) { int count = entry.getValue(); if (bestPattern == null || count > bestCount) { bestCount = count; bestPattern = entry.getKey(); } } if (bestPattern == null) return DEFAULT_PATTERN; if (bestPattern.charAt(0) == '%') return bestPattern.substring(0, 2) + "#"; else return "#" + bestPattern.substring(bestPattern.length() - 2); } private static void inc(Map table, String str) { Integer n = table.get(str); if (n == null) table.put(str, 1); else table.put(str, n + 1); } private boolean patternOk(String pattern, String otherPattern) { Set usedNames = new HashSet(); for (String s : elementNameTable.keySet()) { String name = mungeQName(s); String declName = substitute(pattern, '%', name); if (definedNames.contains(declName)) return false; if (otherPattern != null) { String otherDeclName = substitute(otherPattern, '%', name); if (usedNames.contains(declName) || usedNames.contains(otherDeclName) || declName.equals(otherDeclName)) return false; usedNames.add(declName); usedNames.add(otherDeclName); } } return true; } private void noteDef(String name) { definedNames.add(name); } private void noteElementName(String name, int flags) { Integer n = elementNameTable.get(name); if (n != null) { flags |= n; if (n == flags) return; } else noteNamePrefix(name); elementNameTable.put(name, flags); } private void noteAttlist(String name, AttributeGroup group) { List groups = attlistDeclTable.get(name); if (groups == null) { groups = new Vector(); attlistDeclTable.put(name, groups); } groups.add(group); } private void noteAttribute(String name, String defaultValue) { if (name.equals("xmlns")) { if (defaultValue != null) { if (defaultNamespace != null && !defaultNamespace.equals(defaultValue)) error("INCONSISTENT_DEFAULT_NAMESPACE"); else defaultNamespace = defaultValue; } } else if (name.startsWith("xmlns:")) { if (defaultValue != null) { String prefix = name.substring(6); String ns = prefixTable.get(prefix); if (ns != null && !ns.equals("") && !ns.equals(defaultValue)) error("INCONSISTENT_PREFIX", prefix); else if (!prefix.equals("xml")) prefixTable.put(prefix, defaultValue); } } else { if (defaultValue != null) hadDefaultValue = true; noteNamePrefix(name); } } private void noteNamePrefix(String name) { int i = name.indexOf(':'); if (i < 0) return; String prefix = name.substring(0, i); if (prefixTable.get(prefix) == null && !prefix.equals("xml")) prefixTable.put(prefix, ""); } private int nameFlags(String name) { Integer n = elementNameTable.get(name); if (n == null) return 0; return n; } private String elementDeclName(String name) { return substitute(elementDeclPattern, '%', mungeQName(name)); } private String attlistDeclName(String name) { return substitute(attlistDeclPattern, '%', mungeQName(name)); } private String mungeQName(String name) { if (colonReplacement == null) { int i = name.indexOf(':'); if (i < 0) return name; return name.substring(i + 1); } return substitute(name, ':', colonReplacement); } private static String repeatChar(char c, int n) { char[] buf = new char[n]; for (int i = 0; i < n; i++) buf[i] = c; return new String(buf); } /* Replace the first occurrence of ch in pattern by value. */ private static String substitute(String pattern, char ch, String value) { int i = pattern.indexOf(ch); if (i < 0) return pattern; StringBuffer buf = new StringBuffer(); buf.append(pattern.substring(0, i)); buf.append(value); buf.append(pattern.substring(i + 1)); return buf.toString(); } private void outputStart(List components) { ChoicePattern choice = new ChoicePattern(); // Use the defined but unreferenced elements. // If there aren't any, use all defined elements. int mask = ELEMENT_REF|ELEMENT_DECL; for (;;) { boolean gotOne = false; for (Map.Entry entry : elementNameTable.entrySet()) { if ((entry.getValue() & mask) == ELEMENT_DECL) { gotOne = true; choice.getChildren().add(ref(elementDeclName(entry.getKey()))); } } if (gotOne) break; if (mask == ELEMENT_DECL) return; mask = ELEMENT_DECL; } components.add(new DefineComponent(DefineComponent.START, choice)); } private void outputAny(List components) { if (!hadAny) return; if (options.strictAny) { DefineComponent dc = new DefineComponent(anyName, new TextPattern()); dc.setCombine(Combine.CHOICE); components.add(dc); } else { // any = (element * { attribute * { text }*, any } | text)* CompositePattern group = new GroupPattern(); group.getChildren().add(new ZeroOrMorePattern(new AttributePattern(new AnyNameNameClass(), new TextPattern()))); group.getChildren().add(ref(anyName)); CompositePattern choice = new ChoicePattern(); choice.getChildren().add(new ElementPattern(new AnyNameNameClass(), group)); choice.getChildren().add(new TextPattern()); components.add(new DefineComponent(anyName, new ZeroOrMorePattern(choice))); } } private void outputUndefinedElements(List components) { List elementNames = new Vector(); elementNames.addAll(elementNameTable.keySet()); Collections.sort(elementNames); for (String elementName : elementNames) { if ((elementNameTable.get(elementName) & ELEMENT_DECL) == 0) { DefineComponent dc = new DefineComponent(elementDeclName(elementName), new NotAllowedPattern()); dc.setCombine(Combine.CHOICE); components.add(dc); } } } static private Pattern ref(String name) { return new RefPattern(name); } private void error(String key) { er.error(key, null); } private void error(String key, String arg) { er.error(key, arg, null); } private void warning(String key) { er.warning(key, null); } private void warning(String key, String arg) { er.warning(key, arg, null); } private static String[] valueType(Datatype datatype) { datatype = datatype.deref(); switch (datatype.getType()) { case Datatype.CDATA: return new String[] { "", "string" }; case Datatype.TOKENIZED: return new String[] { WellKnownNamespaces.XML_SCHEMA_DATATYPES, ((TokenizedDatatype)datatype).getTypeName() }; } return new String[] { "", "token" }; } private Pattern convert(ModelGroup mg) throws Exception { ModelGroupOutput mgo = new ModelGroupOutput(); mg.accept(mgo); return mgo.pattern; } private Pattern convert(Datatype dt) throws Exception { DatatypeOutput dto = new DatatypeOutput(); dt.accept(dto); return dto.pattern; } private Pattern convert(AttributeGroup ag) throws Exception { GroupPattern group = new GroupPattern(); ag.accept(new AttributeGroupOutput(group)); switch (group.getChildren().size()) { case 0: return new EmptyPattern(); case 1: return group.getChildren().get(0); } return group; } private NameClass convertQName(String name, boolean useDefault) { int i = name.indexOf(':'); if (i < 0) return new NameNameClass(useDefault ? defaultNamespace : "", name); String prefix = name.substring(0, i); String localName = name.substring(i + 1); String ns; if (prefix.equals("xml")) ns = WellKnownNamespaces.XML; else { ns = prefixTable.get(prefix); if (ns.equals("")) { error("UNDECLARED_PREFIX", prefix); ns = "##" + prefix; prefixTable.put(prefix, ns); } } NameNameClass nnc = new NameNameClass(ns, localName); nnc.setPrefix(prefix); return nnc; } } DtdInputFormat.java000066400000000000000000000134771225366607500354440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtdpackage com.thaiopensource.relaxng.input.dtd; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.input.InputFormat; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.translate.util.AbsoluteUriParam; import com.thaiopensource.relaxng.translate.util.AbstractParam; import com.thaiopensource.relaxng.translate.util.InvalidParamValueException; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.relaxng.translate.util.NCNameParam; import com.thaiopensource.relaxng.translate.util.NmtokenParam; import com.thaiopensource.relaxng.translate.util.Param; import com.thaiopensource.relaxng.translate.util.ParamFactory; import com.thaiopensource.relaxng.translate.util.ParamProcessor; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.util.Localizer; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.parse.DtdParserImpl; import com.thaiopensource.xml.dtd.parse.ParseException; import com.thaiopensource.xml.em.ResolverUriEntityManager; import com.thaiopensource.xml.util.Naming; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.IOException; import java.util.Map; public class DtdInputFormat implements InputFormat { static private class NamespaceDeclParamFactory implements ParamFactory { private final Map prefixMap; NamespaceDeclParamFactory(Map prefixMap) { this.prefixMap = prefixMap; } public Param createParam(String name) { if (!name.startsWith("xmlns:")) return null; final String prefix = name.substring(6); if (!Naming.isNcname(prefix)) return null; return new AbsoluteUriParam() { public void setAbsoluteUri(String uri) { prefixMap.put(prefix, uri); } }; } } static private abstract class DeclPatternParam extends AbstractParam { private final Localizer localizer; DeclPatternParam(Localizer localizer) { this.localizer = localizer; } public void set(String value) throws InvalidParamValueException { if (value.indexOf('%') < 0) throw new InvalidParamValueException(localizer.message("no_percent")); if (value.lastIndexOf('%') != value.indexOf('%')) throw new InvalidParamValueException(localizer.message("multiple_percent")); if (!Naming.isNcname(value.replace('%', 'x'))) throw new InvalidParamValueException(localizer.message("not_ncname_with_percent")); setDeclPattern(value); } abstract void setDeclPattern(String pattern); } public SchemaCollection load(String uri, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InvalidParamsException, IOException, SAXException { final ErrorReporter er = new ErrorReporter(eh, DtdInputFormat.class); final Converter.Options options = new Converter.Options(); if ("xsd".equals(outputFormat)) { options.inlineAttlistDecls = true; options.generateStart = false; } ParamProcessor pp = new ParamProcessor(); pp.declare("inline-attlist", new AbstractParam() { public void set(boolean value) { options.inlineAttlistDecls = value; } }); pp.declare("xmlns", new AbsoluteUriParam() { public void set(String value) throws InvalidParamValueException { if (value.equals("")) setAbsoluteUri(value); else super.set(value); } protected void setAbsoluteUri(String value) { options.defaultNamespace = value; } }); pp.declare("any-name", new NCNameParam() { protected void setNCName(String value) { options.anyName = value; } }); pp.declare("strict-any", new AbstractParam() { public void set(boolean value) { options.strictAny = value; } }); pp.declare("annotation-prefix", new NCNameParam() { protected void setNCName(String value) { options.annotationPrefix = value; } }); pp.declare("colon-replacement", new NmtokenParam() { protected void setNmtoken(String value) { options.colonReplacement = value; } }); pp.declare("generate-start", new AbstractParam() { public void set(boolean value) { options.generateStart = value; } }); pp.declare("element-define", new DeclPatternParam(er.getLocalizer()) { void setDeclPattern(String pattern) { options.elementDeclPattern = pattern; } }); pp.declare("attlist-define", new DeclPatternParam(er.getLocalizer()) { void setDeclPattern(String pattern) { options.attlistDeclPattern = pattern; } }); pp.setParamFactory(new NamespaceDeclParamFactory(options.prefixMap)); pp.process(params, eh); try { Dtd dtd = new DtdParserImpl().parse(uri, new ResolverUriEntityManager(resolver)); try { return new Converter(dtd, er, options).convert(); } catch (ErrorReporter.WrappedSAXException e) { throw e.getException(); } } catch (ParseException e) { throw new SAXParseException(e.getMessageBody(), null, e.getLocation(), e.getLineNumber(), e.getColumnNumber()); } } } ResolverEntityManager.java000066400000000000000000000053361225366607500370240ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtdpackage com.thaiopensource.relaxng.input.dtd; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalEntityIdentifier; import com.thaiopensource.xml.em.EntityManager; import com.thaiopensource.xml.em.ExternalId; import com.thaiopensource.xml.em.OpenEntity; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; /** * */ public class ResolverEntityManager extends EntityManager { private final Resolver resolver; public ResolverEntityManager(Resolver resolver) { this.resolver = resolver; } public OpenEntity open(String systemId) throws IOException { Input input = new Input(); input.setUri(systemId); try { return open(input); } catch (ResolverException e) { throw toIOException(e); } } public OpenEntity open(ExternalId xid, boolean isParameterEntity, String entityName) throws IOException { Input input = new Input(); if (isParameterEntity) entityName = "%" + entityName; try { resolver.resolve(new ExternalEntityIdentifier(xid.getSystemId(), xid.getBaseUri(), xid.getPublicId(), entityName), input); return open(input); } catch (ResolverException e) { throw toIOException(e); } } private OpenEntity open(Input input) throws ResolverException, IOException { resolver.open(input); if (!input.isOpen()) throw new ResolverException("could not open input"); Reader reader = input.getCharacterStream(); String encoding = input.getEncoding(); String systemId = input.getUri(); if (reader != null) { if (encoding == null) encoding = "UTF-8"; // XXX not sure if it's safe to pass null here return new OpenEntity(reader, systemId, systemId, encoding); } InputStream in = input.getByteStream(); if (encoding != null) return new OpenEntity(new InputStreamReader(in, encoding), systemId, systemId, encoding); return detectEncoding(in, systemId); } private static IOException toIOException(ResolverException e) { String message = e.getMessage(); Throwable cause = e.getCause(); if (message == null) { if (cause instanceof IOException) return (IOException)cause; // Avoid IOException(Throwable) because it's 1.6 return new IOException(cause.getMessage()); } // Avoid IOException(String, Throwable) because it's 1.6 return new IOException(message); } } resources/000077500000000000000000000000001225366607500336735ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtdMessages.properties000066400000000000000000000021771225366607500375670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-dtd/src/main/com/thaiopensource/relaxng/input/dtd/resources# Properties file specifying messages # key=message INCONSISTENT_PREFIX=inconsistent namespace URIs for prefix \"{0}\" INCONSISTENT_DEFAULT_NAMESPACE=inconsistent namespace URIs for default namespace UNDECLARED_PREFIX=no namespace declaration for prefix \"{0}\" no_percent=must contain a percent character multiple_percent=must not contain more than one percent character not_ncname_with_percent=must be a valid NCName after replacement of the percent character by an NCName cannot_use_colon_replacement=cannot use supplied \"colon-replacement\" parameter cannot_use_any_name=cannot use supplied \"any-name\" parameter cannot_use_annotation_prefix=cannot use supplied \"annotation-prefix\" parameter cannot_use_element_decl_pattern=cannot use supplied \"element-define\" parameter cannot_use_attlist_decl_pattern=cannot use supplied \"attlist-define\" parameter default_namespace_conflict=default value for \"xmlns\" in the DTD conflicts with supplied \"xmlns\" parameter prefix_conflict=default value for \"xmlns:{0}\" prefix in the DTD conflicts with supplied \"xmlns:{0}\" parameter irrelevant_prefix=prefix \"{0}\" is not used anywhere in the DTD jing-trang-20131210+dfsg+1/mod/convert-from-dtd/todo.txt000066400000000000000000000010521225366607500225510ustar00rootroot00000000000000Option to map comments into annotations (or maybe should be separate program). Output overridden definitions. Try to preserve marked sections. Annotation for included sections (d:condition="flagName") When inlining attlist decls, comments should be inlined also. Maybe inlining attlist decls should be separate later transformation. Also need to fix XSD output to deal with such comments. Choose start elements based on presence of namespace declarations. An attribute group that contains only namespace declarations should disappear completely. jing-trang-20131210+dfsg+1/mod/convert-from-xml/000077500000000000000000000000001225366607500210725ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/mod.xml000066400000000000000000000002661225366607500223770ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/000077500000000000000000000000001225366607500216615ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/000077500000000000000000000000001225366607500226055ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/000077500000000000000000000000001225366607500233635ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/000077500000000000000000000000001225366607500264135ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500300535ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/relaxng/input/000077500000000000000000000000001225366607500312125ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/relaxng/input/xml/000077500000000000000000000000001225366607500320125ustar00rootroot00000000000000Inferrer.java000066400000000000000000000316631225366607500343630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/relaxng/input/xmlpackage com.thaiopensource.relaxng.input.xml; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.infer.AttributeDecl; import com.thaiopensource.xml.infer.ChoiceParticle; import com.thaiopensource.xml.infer.ElementDecl; import com.thaiopensource.xml.infer.ElementParticle; import com.thaiopensource.xml.infer.EmptyParticle; import com.thaiopensource.xml.infer.InferHandler; import com.thaiopensource.xml.infer.OneOrMoreParticle; import com.thaiopensource.xml.infer.Particle; import com.thaiopensource.xml.infer.ParticleVisitor; import com.thaiopensource.xml.infer.Schema; import com.thaiopensource.xml.infer.SequenceParticle; import com.thaiopensource.xml.infer.TextParticle; import com.thaiopensource.xml.util.Name; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import java.io.IOException; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; class Inferrer { private final Schema schema; private final Set multiplyReferencedElementNames = new HashSet(); private final GrammarPattern grammar; private final ParticleConverter particleConverter = new ParticleConverter(); private final List outputQueue = new Vector(); private final Set queued = new HashSet(); private String prefixSeparator; private static final String SEPARATORS = ".-_"; static class Options { String encoding; Resolver resolver; } private static class PatternComparator implements Comparator { private static final Class[] classOrder = { TextPattern.class, RefPattern.class, ElementPattern.class }; public int compare(Pattern p1, Pattern p2) { if (p1.getClass() != p2.getClass()) return classIndex(p1.getClass()) - classIndex(p2.getClass()); if (p1 instanceof RefPattern) return ((RefPattern)p1).getName().compareTo(((RefPattern)p2).getName()); if (p1 instanceof ElementPattern) return Name.compare(extractElementName(p1), extractElementName(p2)); return 0; } private static Name extractElementName(Object o) { NameNameClass nnc = (NameNameClass)((ElementPattern)o).getNameClass(); return new Name(nnc.getNamespaceUri(), nnc.getLocalName()); } private static int classIndex(Class aClass) { for (int i = 0; i < classOrder.length; i++) if (aClass == classOrder[i]) return i; return classOrder.length; } } private class ParticleConverter extends PatternComparator implements ParticleVisitor { public Object visitElement(ElementParticle p) { Name name = p.getName(); if (multiplyReferencedElementNames.contains(name)) { if (!queued.contains(name)) { queued.add(name); outputQueue.add(name); } return new RefPattern(getDefineName(name)); } else return createElementPattern(name); } public Object visitChoice(ChoiceParticle p) { ChoicePattern cp = new ChoicePattern(); List children = cp.getChildren(); addChoices(children, p.getChild1()); addChoices(children, p.getChild2()); Collections.sort(children, this); for (Iterator iter = children.iterator(); iter.hasNext();) if (iter.next() instanceof EmptyPattern) { iter.remove(); return makeOptional(cp); } return cp; } private Object makeOptional(ChoicePattern cp) { List children = cp.getChildren(); boolean done = false; for (int i = 0, len = children.size(); i < len; i++) { Pattern child = children.get(i); if (child instanceof OneOrMorePattern) { children.set(i, new ZeroOrMorePattern(((OneOrMorePattern)child).getChild())); done = true; } } if (done) return normalize(cp); return new OptionalPattern(normalize(cp)); } private void addChoices(List children, Particle child) { Pattern pattern = convert(child); if (pattern instanceof ChoicePattern) children.addAll(((ChoicePattern)pattern).getChildren()); else children.add(pattern); } public Object visitSequence(SequenceParticle p) { GroupPattern gp = new GroupPattern(); addGroup(gp.getChildren(), p.getChild1()); addGroup(gp.getChildren(), p.getChild2()); return gp; } private void addGroup(List children, Particle child) { Pattern pattern = convert(child); if (pattern instanceof GroupPattern) children.addAll(((GroupPattern)pattern).getChildren()); else children.add(pattern); } public Object visitEmpty(EmptyParticle p) { return new EmptyPattern(); } public Object visitText(TextParticle p) { return new TextPattern(); } public Object visitOneOrMore(OneOrMoreParticle p) { return new OneOrMorePattern(convert(p.getChild())); } public Pattern convert(Particle particle) { return (Pattern)particle.accept(this); } } private class ReferenceFinder implements ParticleVisitor { private final Set referencedElementNames = new HashSet(); public Object visitElement(ElementParticle p) { Name name = p.getName(); if (referencedElementNames.contains(name)) multiplyReferencedElementNames.add(name); else referencedElementNames.add(name); return null; } public Object visitChoice(ChoiceParticle p) { p.getChild1().accept(this); p.getChild2().accept(this); return null; } public Object visitSequence(SequenceParticle p) { p.getChild1().accept(this); p.getChild2().accept(this); return null; } public Object visitEmpty(EmptyParticle p) { return null; } public Object visitText(TextParticle p) { return null; } public Object visitOneOrMore(OneOrMoreParticle p) { return p.getChild().accept(this); } } static SchemaCollection infer(String[] args, Options options, ErrorHandler eh) throws SAXException, IOException { InferHandler handler = new InferHandler(new DatatypeLibraryLoader()); XMLReader xr = new SAXResolver(options.resolver).createXMLReader(); xr.setErrorHandler(eh); xr.setContentHandler(handler); for (int i = 0; i < args.length; i++) { InputSource in = new InputSource(args[i]); if (options.encoding != null) in.setEncoding(options.encoding); xr.parse(in); } SchemaCollection sc = new SchemaCollection(); sc.setMainUri(args[0]); SchemaDocument sd = new SchemaDocument(new Inferrer(handler.getSchema()).grammar); sc.getSchemaDocumentMap().put(sc.getMainUri(), sd); return sc; } private Inferrer(Schema schema) { this.schema = schema; this.grammar = new GrammarPattern(); findMultiplyReferencedElements(); choosePrefixSeparator(); grammar.getComponents().add(new DefineComponent(DefineComponent.START, particleConverter.convert(schema.getStart()))); // Names can get added to outputQueue during this loop, // so don't change this to a for each. for (int i = 0; i < outputQueue.size(); i++) { Name elementName = outputQueue.get(i); grammar.getComponents().add(new DefineComponent(getDefineName(elementName), createElementPattern(elementName))); } } private void findMultiplyReferencedElements() { ReferenceFinder finder = new ReferenceFinder(); schema.getStart().accept(finder); for (ElementDecl decl : schema.getElementDecls().values()) { Particle particle = decl.getContentModel(); if (particle != null) particle.accept(finder); } } private void choosePrefixSeparator() { Map prefixMap = schema.getPrefixMap(); Set namespacesInDefines = new HashSet(); for (Name name : multiplyReferencedElementNames) namespacesInDefines.add(name.getNamespaceUri()); if (namespacesInDefines.size() <= 1) return; // don't need to use prefixes in defines // define additional prefixes if necessary namespacesInDefines.removeAll(prefixMap.keySet()); if (namespacesInDefines.size() > 1) { namespacesInDefines.remove(""); int n = 1; for (String ns : namespacesInDefines) { for (; ;) { String prefix = "ns" + Integer.toString(n++); if (!prefixMap.containsKey(prefix)) { prefixMap.put(ns, prefix); break; } } } } // choose a prefixSeparator that avoids all collisions StringBuffer buf = new StringBuffer(); for (int len = 1;; len++) for (int i = 0; i < SEPARATORS.length(); i++) { char c = SEPARATORS.charAt(i); for (int j = 0; j < len; j++) buf.append(c); prefixSeparator = buf.toString(); if (prefixSeparatorOk()) return; buf.setLength(0); } } private boolean prefixSeparatorOk() { Set names = new HashSet(); for (Name elementName : multiplyReferencedElementNames) { String name = getDefineName(elementName); if (names.contains(name)) return false; names.add(name); } return true; } private Pattern createElementPattern(Name elementName) { ElementDecl elementDecl = schema.getElementDecl(elementName); Pattern contentPattern; Particle particle = elementDecl.getContentModel(); if (particle != null) contentPattern = particleConverter.convert(particle); else contentPattern = makeDatatype(elementDecl.getDatatype()); Map attributeDecls = elementDecl.getAttributeDecls(); if (attributeDecls.size() > 0) { GroupPattern group = new GroupPattern(); List attributeNames = new Vector(); attributeNames.addAll(attributeDecls.keySet()); Collections.sort(attributeNames, new Comparator() { public int compare(Name n1, Name n2) { return Name.compare(n1, n2); } }); for (Name attName : attributeNames) { AttributeDecl att = attributeDecls.get(attName); Pattern tem; if (att.getDatatype() == null) tem = new TextPattern(); else tem = makeDatatype(att.getDatatype()); tem = new AttributePattern(makeNameClass(attName), tem); if (att.isOptional()) tem = new OptionalPattern(tem); group.getChildren().add(tem); } if (contentPattern instanceof GroupPattern) group.getChildren().addAll(((GroupPattern)contentPattern).getChildren()); else if (!(contentPattern instanceof EmptyPattern)) group.getChildren().add(contentPattern); contentPattern = group; } return new ElementPattern(makeNameClass(elementName), contentPattern); } private NameNameClass makeNameClass(Name name) { String ns = name.getNamespaceUri(); NameNameClass nnc = new NameNameClass(ns, name.getLocalName()); if (!ns.equals("")) { String prefix = schema.getPrefixMap().get(ns); if (prefix != null) nnc.setPrefix(prefix); } return nnc; } private static DataPattern makeDatatype(Name datatypeName) { return new DataPattern(datatypeName.getNamespaceUri(), datatypeName.getLocalName()); } private String getDefineName(Name elementName) { if (prefixSeparator != null) { String prefix = schema.getPrefixMap().get(elementName.getNamespaceUri()); if (prefix != null) return prefix + prefixSeparator + elementName.getLocalName(); } return elementName.getLocalName(); } private static Pattern normalize(CompositePattern cp) { if (cp.getChildren().size() == 1) return cp.getChildren().get(0); return cp; } } XmlInputFormat.java000066400000000000000000000024021225366607500355250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-from-xml/src/main/com/thaiopensource/relaxng/input/xmlpackage com.thaiopensource.relaxng.input.xml; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.input.AbstractMultiInputFormat; import com.thaiopensource.relaxng.input.InputFailedException; import com.thaiopensource.relaxng.translate.util.EncodingParam; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.relaxng.translate.util.ParamProcessor; import com.thaiopensource.resolver.Resolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public class XmlInputFormat extends AbstractMultiInputFormat { public SchemaCollection load(String[] uris, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InputFailedException, InvalidParamsException, IOException, SAXException { ParamProcessor pp = new ParamProcessor(); final Inferrer.Options options = new Inferrer.Options(); options.resolver = resolver; pp.declare("encoding", new EncodingParam() { protected void setEncoding(String encoding) { options.encoding = encoding; } }); pp.process(params, eh); return Inferrer.infer(uris, options, eh); } } jing-trang-20131210+dfsg+1/mod/convert-from-xml/todo.txt000066400000000000000000000003741225366607500226040ustar00rootroot00000000000000Choose default namespace. Should we reconsider always inlining elements that are referenced only once? Deal with QName datatype. Type of qualified attribute should be globally consistent. Option to make it more eager to use repeated choice groups. jing-trang-20131210+dfsg+1/mod/convert-to-dtd/000077500000000000000000000000001225366607500205245ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/mod.xml000066400000000000000000000001341225366607500220230ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/000077500000000000000000000000001225366607500213135ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/000077500000000000000000000000001225366607500222375ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/000077500000000000000000000000001225366607500230155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/000077500000000000000000000000001225366607500260455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500275055ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/000077500000000000000000000000001225366607500310455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtd/000077500000000000000000000000001225366607500316205ustar00rootroot00000000000000Analysis.java000066400000000000000000000523321225366607500341740ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassVisitor; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.ParentRefPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.output.common.NameClassSplitter; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.Naming; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; class Analysis { private final NamespaceManager nsm = new NamespaceManager(); private final AttlistMapper am = new AttlistMapper(); private final ErrorReporter er; private final Map contentTypes = new HashMap(); private final Map attributeTypes = new HashMap(); private final Map> attributeAlphabets = new HashMap>(); private final Map> attributeNamespaces = new HashMap>(); private Map defines = null; private final Set attlists = new HashSet(); private final Map parts = new HashMap(); private final Map seenTable = new HashMap(); private final Map elementDecls = new HashMap(); private ContentType startType = ContentType.ERROR; private GrammarPart mainPart; private final SchemaCollection schemas; private GrammarPattern grammarPattern; private final AttributeTyper attributeTyper = new AttributeTyper(); private final AttributeAlphabetComputer attributeAlphabetComputer = new AttributeAlphabetComputer(); private final AttributeNamespacesComputer attributeNamespacesComputer = new AttributeNamespacesComputer(); private final IncludeContentChecker includeContentChecker = new IncludeContentChecker(); private final static Set EMPTY_STRING_SET = Collections.emptySet(); private final static Set EMPTY_NAME_SET = Collections.emptySet(); private class Analyzer implements PatternVisitor, ComponentVisitor, NameClassVisitor { private ElementPattern ancestorPattern; private final Set pendingRefs; public Analyzer() { pendingRefs = new HashSet(); } private Analyzer(ElementPattern ancestorPattern) { this.ancestorPattern = ancestorPattern; pendingRefs = new HashSet(); } private Analyzer(Set pendingRefs) { this.pendingRefs = pendingRefs; } public ContentType visitEmpty(EmptyPattern p) { return ContentType.EMPTY; } public ContentType visitData(DataPattern p) { return ContentType.SIMPLE_TYPE; } public ContentType visitValue(ValuePattern p) { Datatypes.Info info = Datatypes.getInfo(p.getDatatypeLibrary(), p.getType()); if (info.usesTokenEquality() && Naming.isNmtoken(p.getValue())) return ContentType.ENUM; if (info.usesCdataEquality()) return ContentType.VALUE; return ContentType.SIMPLE_TYPE; } public ContentType visitElement(ElementPattern p) { int len; if (seen(p)) len = NameClassSplitter.split(p.getNameClass()).size(); else { new Analyzer(p).analyzeContentType(p.getChild()); List names = noteNames(p.getNameClass(), true); len = names.size(); for (int i = 0; i < len; i++) { NameNameClass nnc = names.get(i); String ns = nnc.getNamespaceUri(); if (ns == NameClass.INHERIT_NS) ns = ""; Name name = new Name(ns, nnc.getLocalName()); ElementPattern prev = elementDecls.get(name); if (prev != null) { er.error("sorry_multiple_element", ns, name.getLocalName(), p.getSourceLocation()); er.error("other_element", prev.getSourceLocation()); } else elementDecls.put(name, p); } } return len == 1 ? ContentType.DIRECT_SINGLE_ELEMENT : ContentType.ELEMENT_CLASS; } public ContentType visitAttribute(AttributePattern p) { noteNames(p.getNameClass(), false); ContentType t = analyzeContentType(p.getChild()); if (t.isA(ContentType.MODEL_GROUP) || t == ContentType.MIXED_ELEMENT_CLASS || t == ContentType.MIXED_MODEL) er.error("bad_attribute_type", p.getSourceLocation()); if (ancestorPattern != null) am.noteAttribute(ancestorPattern); return ContentType.EMPTY; } private List noteNames(NameClass nc, boolean defaultable) { nc.accept(this); List names = NameClassSplitter.split(nc); int len = names.size(); for (int i = 0; i < len; i++) nsm.noteName(names.get(i), defaultable); return names; } public ContentType visitNotAllowed(NotAllowedPattern p) { return ContentType.NOT_ALLOWED; } public ContentType visitText(TextPattern p) { return ContentType.TEXT; } public ContentType visitList(ListPattern p) { return ContentType.SIMPLE_TYPE; } public ContentType visitOneOrMore(OneOrMorePattern p) { return checkContentType("sorry_one_or_more", ContentType.oneOrMore(analyzeContentTypeNullAncestorPattern(p.getChild())), p); } public ContentType visitZeroOrMore(ZeroOrMorePattern p) { return checkContentType("sorry_zero_or_more", ContentType.zeroOrMore(analyzeContentTypeNullAncestorPattern(p.getChild())), p); } public ContentType visitChoice(ChoicePattern p) { List children = p.getChildren(); Iterator iter = children.iterator(); ContentType tem = analyzeContentType(iter.next()); while (iter.hasNext()) tem = checkContentType("sorry_choice", ContentType.choice(tem, analyzeContentType(iter.next())), p); if (getAttributeType(p) == AttributeType.MULTI) { Set attributeNames = new HashSet(); for (Pattern child : children) { Set childAttributeNames = getAttributeAlphabet(child); for (Name name : childAttributeNames) { if (attributeNames.contains(name)) er.error("sorry_choice_attribute_name", name.getNamespaceUri(), name.getLocalName(), p.getSourceLocation()); else attributeNames.add(name); } } } return tem; } public ContentType visitInterleave(InterleavePattern p) { List children = p.getChildren(); ContentType tem = analyzeContentType(children.get(0)); for (int i = 1, len = children.size(); i < len; i++) tem = checkContentType("sorry_interleave", ContentType.interleave(tem, analyzeContentType(children.get(i))), p); return tem; } public ContentType visitGroup(GroupPattern p) { List children = p.getChildren(); ContentType tem = analyzeContentType(children.get(0)); for (int i = 1, len = children.size(); i < len; i++) tem = checkContentType("sorry_group", ContentType.group(tem, analyzeContentType(children.get(i))), p); return tem; } public ContentType visitRef(RefPattern p) { String name = p.getName(); Pattern def = getBody(name); if (def == null) { er.error("undefined_ref", p.getSourceLocation()); return ContentType.ERROR; } if (pendingRefs.contains(name)) { er.error("ref_loop", p.getSourceLocation()); return ContentType.ERROR; } pendingRefs.add(name); ContentType t = ContentType.ref(new Analyzer(pendingRefs).analyzeContentType(def)); pendingRefs.remove(name); if (t.isA(ContentType.EMPTY)) am.noteAttributeGroupRef(ancestorPattern, p.getName()); return ContentType.ref(t); } public ContentType visitParentRef(ParentRefPattern p) { er.error("sorry_parent_ref", p.getSourceLocation()); return null; } public ContentType visitGrammar(GrammarPattern p) { if (defines != null) { er.error("sorry_nested_grammar", p.getSourceLocation()); return ContentType.ERROR; } defines = new HashMap(); try { mainPart = new GrammarPart(er, defines, attlists, schemas, parts, p); } catch (GrammarPart.IncludeLoopException e) { er.error("include_loop", e.getInclude().getSourceLocation()); return ContentType.ERROR; } grammarPattern = p; visitContainer(p); return startType; } public ContentType visitExternalRef(ExternalRefPattern p) { er.error("sorry_external_ref", p.getSourceLocation()); return null; } public ContentType visitMixed(MixedPattern p) { return checkContentType("sorry_mixed", ContentType.mixed(analyzeContentType(p.getChild())), p); } public ContentType visitOptional(OptionalPattern p) { return checkContentType("sorry_optional", ContentType.optional(analyzeContentTypeNullAncestorPattern(p.getChild())), p); } public VoidValue visitContainer(Container c) { List list = c.getComponents(); for (int i = 0, len = list.size(); i < len; i++) list.get(i).accept(this); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { return visitContainer(c); } public VoidValue visitDefine(DefineComponent c) { if (c.getName() == DefineComponent.START) startType = analyzeContentType(c.getBody()); else new Analyzer().analyzeContentType(c.getBody()); if (attlists.contains(c.getName()) && getContentType(c.getBody()) != ContentType.EMPTY) { er.error("not_attlist", c.getName(), c.getSourceLocation()); attlists.remove(c.getName()); } return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { includeContentChecker.visitContainer(c); visitContainer((GrammarPattern)(schemas.getSchemaDocumentMap().get(c.getUri())).getPattern()); return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { List list = nc.getChildren(); for (int i = 0, len = list.size(); i < len; i++) list.get(i).accept(this); return VoidValue.VOID; } public VoidValue visitAnyName(AnyNameNameClass nc) { er.error("sorry_wildcard", nc.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { er.error("sorry_wildcard", nc.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitName(NameNameClass nc) { nsm.noteName(nc, true); return VoidValue.VOID; } ContentType checkContentType(String key, ContentType t, Pattern p) { if (t != null) return t; er.error(key, p.getSourceLocation()); return ContentType.ERROR; } ContentType analyzeContentType(Pattern p) { ContentType t = contentTypes.get(p); if (t == null) { t = p.accept(this); contentTypes.put(p, t); } return t; } ContentType analyzeContentTypeNullAncestorPattern(Pattern p) { return (ancestorPattern == null ? this : new Analyzer(pendingRefs)).analyzeContentType(p); } } class IncludeContentChecker implements ComponentVisitor { public VoidValue visitContainer(Container c) { List list = c.getComponents(); for (int i = 0, len = list.size(); i < len; i++) list.get(i).accept(this); return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { er.error("sorry_include_override", c.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { return visitContainer(c); } public VoidValue visitInclude(IncludeComponent c) { return VoidValue.VOID; } } private class AttributeTyper extends AbstractPatternVisitor { public AttributeType visitPattern(Pattern p) { return AttributeType.EMPTY; } public AttributeType visitMixed(MixedPattern p) { return getAttributeType(p.getChild()); } public AttributeType visitOneOrMore(OneOrMorePattern p) { return getAttributeType(p.getChild()); } public AttributeType visitZeroOrMore(ZeroOrMorePattern p) { return getAttributeType(p.getChild()); } public AttributeType visitOptional(OptionalPattern p) { return getAttributeType(p.getChild()); } public AttributeType visitComposite(CompositePattern p) { List list = p.getChildren(); AttributeType at = getAttributeType(list.get(0)); for (int i = 1, len = list.size(); i < len; i++) at = AttributeType.group(at, getAttributeType(list.get(i))); return at; } public AttributeType visitAttribute(AttributePattern p) { return AttributeType.SINGLE; } public AttributeType visitEmpty(EmptyPattern p) { return AttributeType.MULTI; } public AttributeType visitRef(RefPattern p) { return getAttributeType(getBody(p.getName())); } } private class AttributeAlphabetComputer extends AbstractPatternVisitor> { public Set visitPattern(Pattern p) { return EMPTY_NAME_SET; } public Set visitMixed(MixedPattern p) { return getAttributeAlphabet(p.getChild()); } public Set visitOneOrMore(OneOrMorePattern p) { return getAttributeAlphabet(p.getChild()); } public Set visitZeroOrMore(ZeroOrMorePattern p) { return getAttributeAlphabet(p.getChild()); } public Set visitOptional(OptionalPattern p) { return getAttributeAlphabet(p.getChild()); } public Set visitComposite(CompositePattern p) { List list = p.getChildren(); Set result = new HashSet(); for (int i = 0, len = list.size(); i < len; i++) result.addAll(getAttributeAlphabet(list.get(i))); return result; } public Set visitAttribute(AttributePattern p) { Set result = new HashSet(); List names = NameClassSplitter.split(p.getNameClass()); for (int i = 0, len = names.size(); i < len; i++) { NameNameClass nnc = names.get(i); String ns = nnc.getNamespaceUri(); if (ns == NameClass.INHERIT_NS) ns = ""; result.add(new Name(ns, nnc.getLocalName())); } return result; } public Set visitRef(RefPattern p) { return getAttributeAlphabet(getBody(p.getName())); } } private class AttributeNamespacesComputer extends AbstractPatternVisitor> { public Set visitPattern(Pattern p) { return EMPTY_STRING_SET; } public Set visitMixed(MixedPattern p) { return getAttributeNamespaces(p.getChild()); } public Set visitOneOrMore(OneOrMorePattern p) { return getAttributeNamespaces(p.getChild()); } public Set visitZeroOrMore(ZeroOrMorePattern p) { return getAttributeNamespaces(p.getChild()); } public Set visitOptional(OptionalPattern p) { return getAttributeNamespaces(p.getChild()); } public Set visitComposite(CompositePattern p) { Set result = EMPTY_STRING_SET; boolean newResult = false; for (Pattern child : p.getChildren()) { Set tem = getAttributeNamespaces(child); if (tem != EMPTY_STRING_SET && !result.containsAll(tem)) { if (result == EMPTY_STRING_SET) result = tem; else { if (!newResult) { result = new HashSet(result); newResult = true; } result.addAll(tem); } } } if (newResult) result = Collections.unmodifiableSet(result); return result; } public Set visitAttribute(AttributePattern p) { Set result = null; List names = NameClassSplitter.split(p.getNameClass()); for (NameNameClass name : names) { String ns = name.getNamespaceUri(); if (ns.length() != 0 && ns != NameClass.INHERIT_NS && !ns.equals(WellKnownNamespaces.XML)) { if (result == null) result = new HashSet(); result.add(ns); } } if (result == null) return EMPTY_STRING_SET; return Collections.unmodifiableSet(result); } public Set visitRef(RefPattern p) { return getAttributeNamespaces(getBody(p.getName())); } } private boolean seen(Pattern p) { if (seenTable.get(p) != null) return true; seenTable.put(p, p); return false; } Analysis(SchemaCollection schemas, ErrorReporter er) { this.schemas = schemas; this.er = er; new Analyzer().analyzeContentType(getPattern()); checkAttlists(); if (!er.getHadError()) nsm.assignPrefixes(); } private void checkAttlists() { for (String name : attlists) if (getParamEntityElementName(name) == null) er.error("not_attlist", name, getBody(name).getSourceLocation()); } Pattern getPattern() { return (schemas.getSchemaDocumentMap().get(schemas.getMainUri())).getPattern(); } String getPrefixForNamespaceUri(String ns) { return nsm.getPrefixForNamespaceUri(ns); } String getElementPrefixForNamespaceUri(String ns) { if (ns.equals("") || ns.equals(nsm.getDefaultNamespaceUri()) || ns == NameClass.INHERIT_NS) return null; return nsm.getPrefixForNamespaceUri(ns); } String getParamEntityElementName(String name) { NameNameClass nc = am.getParamEntityElementName(name); if (nc == null) return null; String prefix = getElementPrefixForNamespaceUri(nc.getNamespaceUri()); String localName = nc.getLocalName(); if (prefix == null) return localName; return prefix + ":" + localName; } ContentType getContentType(Pattern p) { return contentTypes.get(p); } AttributeType getAttributeType(Pattern p) { AttributeType at = attributeTypes.get(p); if (at == null) { at = p.accept(attributeTyper); attributeTypes.put(p, at); } return at; } Set getAttributeAlphabet(Pattern p) { Set aa = attributeAlphabets.get(p); if (aa == null) { aa = Collections.unmodifiableSet(p.accept(attributeAlphabetComputer)); attributeAlphabets.put(p, aa); } return aa; } Set getAttributeNamespaces(Pattern p) { Set aa = attributeNamespaces.get(p); if (aa == null) { aa = p.accept(attributeNamespacesComputer); attributeNamespaces.put(p, aa); } return aa; } Pattern getBody(String name) { return defines.get(name); } GrammarPattern getGrammarPattern() { return grammarPattern; } String getMainUri() { return schemas.getMainUri(); } GrammarPart getGrammarPart(String sourceUri) { if (sourceUri.equals(schemas.getMainUri())) return mainPart; else return parts.get(sourceUri); } Pattern getSchema(String sourceUri) { return (schemas.getSchemaDocumentMap().get(sourceUri)).getPattern(); } String getEncoding(String sourceUri) { return (schemas.getSchemaDocumentMap().get(sourceUri)).getEncoding(); } } AttlistMapper.java000066400000000000000000000026721225366607500352040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameNameClass; import java.util.HashMap; import java.util.Map; class AttlistMapper { private final Map elementToAttlistMap = new HashMap(); private final Map paramEntityToElementMap = new HashMap(); void noteAttribute(ElementPattern e) { elementToAttlistMap.put(e, Boolean.FALSE); } void noteAttributeGroupRef(ElementPattern e, String paramEntityName) { if (e != null) { if (elementToAttlistMap.get(e) != null) elementToAttlistMap.put(e, Boolean.FALSE); else elementToAttlistMap.put(e, paramEntityName); } if (e == null || paramEntityToElementMap.get(paramEntityName) != null) paramEntityToElementMap.put(paramEntityName, Boolean.FALSE); else paramEntityToElementMap.put(paramEntityName, e); } NameNameClass getParamEntityElementName(String name) { Object elem = paramEntityToElementMap.get(name); if (elem == null || elem == Boolean.FALSE) return null; Object tem = elementToAttlistMap.get(elem); if (!name.equals(tem)) return null; NameClass nc = ((ElementPattern)elem).getNameClass(); if (!(nc instanceof NameNameClass)) return null; return (NameNameClass)nc; } } AttributeType.java000066400000000000000000000007011225366607500352070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; class AttributeType { private AttributeType() { } static final AttributeType EMPTY = new AttributeType(); static final AttributeType SINGLE = new AttributeType(); static final AttributeType MULTI = new AttributeType(); static AttributeType group(AttributeType at1, AttributeType at2) { if (at1 == EMPTY) return at2; if (at2 == EMPTY) return at1; return MULTI; } } ContentType.java000066400000000000000000000106511225366607500346630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; class ContentType { private final ContentType parent; static final ContentType MIXED_ELEMENT_CLASS = new ContentType(); static final ContentType NOT_ALLOWED = new ContentType(); static final ContentType SIMPLE_TYPE = new ContentType(); static final ContentType SIMPLE_TYPE_CHOICE = new ContentType(SIMPLE_TYPE); static final ContentType VALUE = new ContentType(SIMPLE_TYPE); static final ContentType EMPTY = new ContentType(); static final ContentType TEXT = new ContentType(MIXED_ELEMENT_CLASS); static final ContentType MIXED_MODEL = new ContentType(); static final ContentType INTERLEAVE_MIXED_MODEL = new ContentType(MIXED_MODEL); static final ContentType MODEL_GROUP = new ContentType(); static final ContentType ELEMENT_CLASS = new ContentType(MODEL_GROUP); static final ContentType DIRECT_SINGLE_ELEMENT = new ContentType(ELEMENT_CLASS); static final ContentType ZERO_OR_MORE_ELEMENT_CLASS = new ContentType(MODEL_GROUP); static final ContentType INTERLEAVE_ZERO_OR_MORE_ELEMENT_CLASS = new ContentType(ZERO_OR_MORE_ELEMENT_CLASS); static final ContentType ENUM = new ContentType(SIMPLE_TYPE); static final ContentType ERROR = new ContentType(); private ContentType() { this.parent = null; } private ContentType(ContentType parent) { this.parent = parent; } boolean isA(ContentType t) { if (this == t) return true; if (parent != null && parent.isA(t)) return true; return false; } static ContentType zeroOrMore(ContentType t) { if (t.isA(ELEMENT_CLASS)) return ZERO_OR_MORE_ELEMENT_CLASS; if (t.isA(MIXED_ELEMENT_CLASS)) return MIXED_MODEL; return oneOrMore(t); } static ContentType oneOrMore(ContentType t) { if (t == ERROR) return ERROR; if (t == EMPTY) return EMPTY; if (t.isA(MODEL_GROUP)) return MODEL_GROUP; return null; } static ContentType group(ContentType t1, ContentType t2) { if (t1.isA(MODEL_GROUP) && t2.isA(MODEL_GROUP)) return MODEL_GROUP; return groupOrInterleave(t1, t2); } static ContentType mixed(ContentType t) { if (t.isA(EMPTY)) return TEXT; if (t.isA(ZERO_OR_MORE_ELEMENT_CLASS)) return MIXED_MODEL; return null; } static ContentType interleave(ContentType t1, ContentType t2) { if (t1.isA(ZERO_OR_MORE_ELEMENT_CLASS) && t2.isA(ZERO_OR_MORE_ELEMENT_CLASS)) return INTERLEAVE_ZERO_OR_MORE_ELEMENT_CLASS; if (((t1.isA(MIXED_MODEL) || t1 == TEXT) && t2.isA(ZERO_OR_MORE_ELEMENT_CLASS)) || t1.isA(ZERO_OR_MORE_ELEMENT_CLASS) && (t2.isA(MIXED_MODEL) || t2 == TEXT)) return INTERLEAVE_MIXED_MODEL; return groupOrInterleave(t1, t2); } static private ContentType groupOrInterleave(ContentType t1, ContentType t2) { if (t1 == ERROR || t2 == ERROR) return ERROR; if (t1.isA(EMPTY)) return ref(t2); if (t2.isA(EMPTY)) return ref(t1); return null; } static ContentType optional(ContentType t) { if (t == ERROR) return ERROR; if (t == EMPTY) return EMPTY; if (t.isA(MODEL_GROUP)) return MODEL_GROUP; if (t.isA(MIXED_ELEMENT_CLASS)) return MIXED_ELEMENT_CLASS; if (t == NOT_ALLOWED) return MODEL_GROUP; return null; } static ContentType choice(ContentType t1, ContentType t2) { if (t1 == ERROR || t2 == ERROR) return ERROR; if (t1 == EMPTY && t2 == EMPTY) return EMPTY; if (t1 == NOT_ALLOWED) { if (t2 == NOT_ALLOWED) return NOT_ALLOWED; if (t2.isA(ELEMENT_CLASS)) return ELEMENT_CLASS; if (t2.isA(MIXED_ELEMENT_CLASS)) return MIXED_ELEMENT_CLASS; if (t2.isA(MODEL_GROUP)) return MODEL_GROUP; if (t2.isA(ENUM)) return ENUM; return null; } if (t2 == NOT_ALLOWED) return choice(t2, t1); if (t1.isA(ENUM) && t2.isA(ENUM)) return ENUM; if (t1.isA(SIMPLE_TYPE) && t2.isA(SIMPLE_TYPE)) return SIMPLE_TYPE_CHOICE; if (t1.isA(ELEMENT_CLASS) && t2.isA(ELEMENT_CLASS)) return ELEMENT_CLASS; if (t1.isA(MODEL_GROUP) && t2.isA(MODEL_GROUP)) return MODEL_GROUP; if ((t1.isA(MIXED_ELEMENT_CLASS) && t2.isA(ELEMENT_CLASS)) || (t1.isA(ELEMENT_CLASS) && t2.isA(MIXED_ELEMENT_CLASS))) return MIXED_ELEMENT_CLASS; return null; } static ContentType ref(ContentType t) { if (t.isA(DIRECT_SINGLE_ELEMENT)) return ELEMENT_CLASS; return t; } } Datatypes.java000066400000000000000000000072631225366607500343520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.HashMap; import java.util.Map; public class Datatypes { private static final Map xsdMap = new HashMap(); // exactly equivalent to DTD datatype of same name private static final int COMPATIBLE = 0x0; // closest to CDATA private static final int CDATA = 0x1; // closest to NMTOKEN private static final int NMTOKEN = 0x2; // closest to CDATA private static final int CDATA_EQUALITY = 0x4; // closest to CDATA private static final int TOKEN_EQUALITY = 0x8; // closest CDATA type is exact private static final int EXACT = 0x10; private static final Object[] others = { "", new Info("string", CDATA|EXACT|CDATA_EQUALITY), "", new Info("token", CDATA|EXACT|TOKEN_EQUALITY), WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES, new Info("ID", COMPATIBLE|EXACT|TOKEN_EQUALITY), WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES, new Info("IDREF", COMPATIBLE|EXACT|TOKEN_EQUALITY), WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES, new Info("IDREFS", COMPATIBLE|EXACT|TOKEN_EQUALITY) }; public final static class Info { private final String name; private final int flags; private Info(String name, int flags) { this.name = name; this.flags = flags; } public String closestType() { switch (flags & 0x3) { case COMPATIBLE: return name; case NMTOKEN: return "NMTOKEN"; default: return "CDATA"; } } public boolean isExact() { return (flags & EXACT) != 0; } public boolean usesTokenEquality() { return (flags & TOKEN_EQUALITY) != 0; } public boolean usesCdataEquality() { return (flags & CDATA_EQUALITY) != 0; } } public static Info getInfo(String datatypeLibrary, String localName) { if (datatypeLibrary.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES)) return xsdMap.get(localName); for (int i = 0; i < others.length; i += 2) if (datatypeLibrary.equals(others[i]) && localName.equals(((Info)others[i + 1]).name)) return (Info)others[i + 1]; return null; } private static void xsd(String name, int flags) { xsdMap.put(name, new Info(name, flags)); } static { xsd("ENTITIES", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("ENTITY", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("ID", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("IDREF", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("IDREFS", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("NMTOKEN", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("NMTOKENS", COMPATIBLE|EXACT|TOKEN_EQUALITY); xsd("NOTATION", NMTOKEN); xsd("NCName", NMTOKEN); xsd("QName", NMTOKEN); xsd("anyURI", CDATA|CDATA_EQUALITY); xsd("base64Binary", CDATA); xsd("boolean", NMTOKEN); xsd("byte", CDATA); xsd("date", NMTOKEN); xsd("dateTime", NMTOKEN); xsd("decimal", CDATA); xsd("duration", NMTOKEN); xsd("gDay", NMTOKEN); xsd("gMonth", NMTOKEN); xsd("gMonthDay", NMTOKEN); xsd("gYear", NMTOKEN); xsd("gYearMonth", NMTOKEN); xsd("hexBinary", NMTOKEN); xsd("int", CDATA); xsd("integer", CDATA); xsd("language", CDATA); // XXX xsd("long", CDATA); xsd("negativeInteger", CDATA); xsd("nonNegativeInteger", CDATA); xsd("nonPositiveInteger", CDATA); xsd("normalizedString", CDATA|EXACT|CDATA_EQUALITY); xsd("positiveInteger", CDATA); xsd("short", CDATA); xsd("string", CDATA|EXACT|CDATA_EQUALITY); xsd("time", NMTOKEN); xsd("token", CDATA|EXACT|TOKEN_EQUALITY); xsd("unsignedInt", CDATA); xsd("unsignedLong", CDATA); xsd("unsignedShort", CDATA); } } DtdOutput.java000066400000000000000000001134601225366607500343450ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.AbstractVisitor; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.output.common.NameClassSplitter; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.out.CharRepertoire; import com.thaiopensource.xml.util.Naming; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.io.IOException; import java.io.Writer; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Vector; class DtdOutput { private final boolean warnDatatypes; private final String sourceUri; private Writer writer; private String encoding; private CharRepertoire charRepertoire; private final int indent; private final int lineLength; private final String lineSep; private final StringBuffer buf = new StringBuffer(); private final List elementQueue = new Vector(); private final List requiredParamEntities = new Vector(); private final List externallyRequiredParamEntities = new Vector(); private final Set doneParamEntities = new HashSet(); private final Set doneIncludes = new HashSet(); private final Set pendingIncludes = new HashSet(); private final Analysis analysis; private final GrammarPart part; private final OutputDirectory od; private final ErrorReporter er; private final Set reservedEntityNames; private final PatternVisitor topLevelContentModelOutput = new TopLevelContentModelOutput(); private final AbstractVisitor nestedContentModelOutput = new ContentModelOutput(); private final PatternVisitor expandedContentModelOutput = new ExpandedContentModelOutput(); private final PatternVisitor groupContentModelOutput = new GroupContentModelOutput(); private final PatternVisitor choiceContentModelOutput = new ChoiceContentModelOutput(); private final PatternVisitor occurContentModelOutput = new ParenthesizedContentModelOutput(); private final PatternVisitor innerElementClassOutput = new InnerElementClassOutput(); private final PatternVisitor expandedInnerElementClassOutput = new ExpandedInnerElementClassOutput(); private final AttributeOutput attributeOutput = new AttributeOutput(); private final AttributeOutput optionalAttributeOutput = new OptionalAttributeOutput(); private final PatternVisitor topLevelSimpleTypeOutput = new TopLevelSimpleTypeOutput(); private final PatternVisitor nestedSimpleTypeOutput = new SimpleTypeOutput(); private final PatternVisitor valueOutput = new ValueOutput(); private final GrammarOutput grammarOutput = new GrammarOutput(); static private final String DTD_URI = "http://www.thaiopensource.com/ns/relaxng/dtd"; private DtdOutput(boolean warnDatatypes, String sourceUri, Analysis analysis, Set reservedEntityNames, OutputDirectory od, ErrorReporter er) { this.warnDatatypes = warnDatatypes; this.sourceUri = sourceUri; this.analysis = analysis; this.reservedEntityNames = reservedEntityNames; this.od = od; this.er = er; this.part = analysis.getGrammarPart(sourceUri); try { OutputDirectory.Stream stream = od.open(sourceUri, analysis.getEncoding(sourceUri)); this.encoding = stream.getEncoding(); this.writer = stream.getWriter(); this.charRepertoire = stream.getCharRepertoire(); } catch (IOException e) { throw new WrappedIOException(e); } this.lineSep = od.getLineSeparator(); this.indent = od.getIndent(); this.lineLength = od.getLineLength(); } class ParenthesizedContentModelOutput extends AbstractPatternVisitor { public VoidValue visitPattern(Pattern p) { buf.append('('); p.accept(nestedContentModelOutput); buf.append(')'); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { Pattern def = getBody(p.getName()); if (getContentType(def) == ContentType.DIRECT_SINGLE_ELEMENT) ((ElementPattern)def).getNameClass().accept(nestedContentModelOutput); else visitPattern(p); return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { if (getContentType(p) == ContentType.DIRECT_SINGLE_ELEMENT) { p.getNameClass().accept(nestedContentModelOutput); elementQueue.add(p); } else visitPattern(p); return VoidValue.VOID; } } class ChoiceContentModelOutput extends ParenthesizedContentModelOutput { public VoidValue visitOptional(OptionalPattern p) { p.accept(nestedContentModelOutput); return VoidValue.VOID; } public VoidValue visitOneOrMore(OneOrMorePattern p) { p.accept(nestedContentModelOutput); return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { p.accept(nestedContentModelOutput); return VoidValue.VOID; } } private class GroupContentModelOutput extends ChoiceContentModelOutput { public VoidValue visitGroup(GroupPattern p) { p.accept(nestedContentModelOutput); return VoidValue.VOID; } } class ContentModelOutput extends AbstractVisitor { public VoidValue visitName(NameNameClass nc) { String prefix = analysis.getElementPrefixForNamespaceUri(nc.getNamespaceUri()); if (prefix != null) buf.append(prefix).append(':'); buf.append(nc.getLocalName()); return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { List list = nc.getChildren(); boolean needSep = false; for (int i = 0, len = list.size(); i < len; i++) { if (needSep) buf.append('|'); else needSep = true; list.get(i).accept(this); } return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { p.getNameClass().accept(this); elementQueue.add(p); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { Pattern def = getBody(p.getName()); if (getContentType(def) == ContentType.DIRECT_SINGLE_ELEMENT) ((ElementPattern)def).getNameClass().accept(this); else paramEntityRef(p); return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { p.getChild().accept(occurContentModelOutput); buf.append('*'); return VoidValue.VOID; } public VoidValue visitOneOrMore(OneOrMorePattern p) { p.getChild().accept(occurContentModelOutput); buf.append('+'); return VoidValue.VOID; } public VoidValue visitOptional(OptionalPattern p) { p.getChild().accept(occurContentModelOutput); buf.append('?'); return VoidValue.VOID; } public VoidValue visitText(TextPattern p) { buf.append("#PCDATA"); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { buf.append("#PCDATA"); return VoidValue.VOID; } public VoidValue visitGroup(GroupPattern p) { List list = p.getChildren(); boolean needSep = false; final int len = list.size(); for (int i = 0; i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (!t.isA(ContentType.EMPTY)) { if (needSep) buf.append(','); else needSep = true; member.accept(groupContentModelOutput); } } return VoidValue.VOID; } public VoidValue visitInterleave(InterleavePattern p) { ContentType ct = getContentType(p); if (ct == ContentType.INTERLEAVE_ZERO_OR_MORE_ELEMENT_CLASS || ct == ContentType.INTERLEAVE_MIXED_MODEL) { buf.append('('); p.accept(innerElementClassOutput); buf.append(')'); buf.append('*'); } else { final List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (!t.isA(ContentType.EMPTY)) member.accept(this); } } return VoidValue.VOID; } public VoidValue visitChoice(ChoicePattern p) { List list = p.getChildren(); boolean needSep = false; final int len = list.size(); if (getContentType(p).isA(ContentType.MIXED_ELEMENT_CLASS)) { for (int i = 0; i < len; i++) { Pattern member = list.get(i); if (getContentType(member).isA(ContentType.MIXED_ELEMENT_CLASS)) { member.accept(nestedContentModelOutput); needSep = true; break; } } } for (int i = 0; i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (t != ContentType.NOT_ALLOWED && t != ContentType.EMPTY && !t.isA(ContentType.MIXED_ELEMENT_CLASS)) { if (needSep) buf.append('|'); else needSep = true; member.accept(!t.isA(ContentType.ELEMENT_CLASS) ? choiceContentModelOutput : nestedContentModelOutput); } } for (int i = 0; i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (t == ContentType.NOT_ALLOWED) { if (needSep) buf.append(' '); else needSep = true; member.accept(nestedContentModelOutput); } } return VoidValue.VOID; } public VoidValue visitGrammar(GrammarPattern p) { return getBody(DefineComponent.START).accept(this); } } class TopLevelContentModelOutput extends ContentModelOutput { public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { buf.append('('); p.getChild().accept(nestedContentModelOutput); buf.append(')'); buf.append('*'); return VoidValue.VOID; } public VoidValue visitOneOrMore(OneOrMorePattern p) { buf.append('('); p.getChild().accept(nestedContentModelOutput); buf.append(')'); buf.append('+'); return VoidValue.VOID; } public VoidValue visitOptional(OptionalPattern p) { buf.append('('); p.getChild().accept(nestedContentModelOutput); buf.append(')'); buf.append('?'); return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { buf.append('('); super.visitElement(p); buf.append(')'); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { ContentType t = getContentType(p); if (t.isA(ContentType.MIXED_MODEL)) super.visitRef(p); else { buf.append('('); super.visitRef(p); buf.append(')'); } return VoidValue.VOID; } public VoidValue visitChoice(ChoicePattern p) { buf.append('('); p.accept(nestedContentModelOutput); buf.append(')'); return VoidValue.VOID; } public VoidValue visitText(TextPattern p) { buf.append('('); p.accept(nestedContentModelOutput); buf.append(')'); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { buf.append('('); if (getContentType(p.getChild()) == ContentType.EMPTY) buf.append("#PCDATA)"); else { buf.append("#PCDATA|"); p.getChild().accept(innerElementClassOutput); buf.append(')'); buf.append('*'); } return VoidValue.VOID; } public VoidValue visitGroup(GroupPattern p) { List list = p.getChildren(); Pattern main = null; for (int i = 0, len = list.size(); i < len; i++) { Pattern member = list.get(i); if (!getContentType(member).isA(ContentType.EMPTY)) { if (main == null) main = member; else { buf.append('('); nestedContentModelOutput.visitGroup(p); buf.append(')'); return VoidValue.VOID; } } } if (main != null) main.accept(this); return VoidValue.VOID; } } class ExpandedContentModelOutput extends ContentModelOutput { public VoidValue visitElement(ElementPattern p) { p.getNameClass().accept(this); return VoidValue.VOID; } } class PatternOutput extends AbstractPatternVisitor { public VoidValue visitPattern(Pattern p) { return VoidValue.VOID; } } class InnerElementClassOutput extends PatternOutput { public VoidValue visitRef(RefPattern p) { getBody(p.getName()).accept(expandedInnerElementClassOutput); return VoidValue.VOID; } public VoidValue visitComposite(CompositePattern p) { List list = p.getChildren(); boolean needSep = false; int doneIndex = -1; for (int i = 0, len = list.size(); i < len; i++) { Pattern member = list.get(i); ContentType ct = getContentType(member); if (ct.isA(ContentType.MIXED_MODEL) || ct == ContentType.TEXT) { member.accept(this); needSep = true; doneIndex = i; break; } } for (int i = 0, len = list.size(); i < len; i++) { if (i != doneIndex) { Pattern member = list.get(i); if (getContentType(member) != ContentType.EMPTY) { if (needSep) buf.append('|'); else needSep = true; member.accept(this); } } } return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { p.getChild().accept(nestedContentModelOutput); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { if (getContentType(p.getChild()) == ContentType.EMPTY) buf.append("#PCDATA"); else { buf.append("#PCDATA|"); p.getChild().accept(this); } return VoidValue.VOID; } public VoidValue visitText(TextPattern p) { buf.append("#PCDATA"); return VoidValue.VOID; } } class ExpandedInnerElementClassOutput extends InnerElementClassOutput { public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { p.getChild().accept(expandedContentModelOutput); return VoidValue.VOID; } } class AttributeOutput extends PatternOutput { void output(Pattern p) { if (getAttributeType(p) != AttributeType.EMPTY) p.accept(this); } void newlineIndent() { buf.append(lineSep); for (int i = 0; i < indent; i++) buf.append(' '); } public VoidValue visitComposite(CompositePattern p) { List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) output(list.get(i)); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { output(p.getChild()); return VoidValue.VOID; } public VoidValue visitOneOrMore(OneOrMorePattern p) { output(p.getChild()); return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { if (getAttributeType(p) != AttributeType.SINGLE) er.warning("attribute_occur_approx", p.getSourceLocation()); optionalAttributeOutput.output(p.getChild()); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { ContentType t = getContentType(p); if (t.isA(ContentType.EMPTY) && isRequired()) { if (analysis.getParamEntityElementName(p.getName()) == null) { newlineIndent(); paramEntityRef(p); } } else output(getBody(p.getName())); return VoidValue.VOID; } public VoidValue visitAttribute(AttributePattern p) { ContentType ct = getContentType(p.getChild()); if (ct == ContentType.NOT_ALLOWED) return VoidValue.VOID; List names = NameClassSplitter.split(p.getNameClass()); int len = names.size(); if (len > 1) er.warning("attribute_occur_approx", p.getSourceLocation()); for (int i = 0; i < len; i++) { int start = buf.length(); newlineIndent(); NameNameClass nnc = names.get(i); String ns = nnc.getNamespaceUri(); if (!ns.equals("") && ns != NameClass.INHERIT_NS) { String prefix = analysis.getPrefixForNamespaceUri(ns); buf.append(prefix); buf.append(':'); } buf.append(nnc.getLocalName()); buf.append(' '); if (ct == ContentType.VALUE) p.getChild().accept(valueOutput); else { int typeStart = buf.length(); if (ct.isA(ContentType.SIMPLE_TYPE) || ct == ContentType.TEXT) p.getChild().accept(topLevelSimpleTypeOutput); else if (ct == ContentType.EMPTY) { er.warning("empty_attribute_approx", p.getSourceLocation()); buf.append("CDATA"); } int typeEnd = buf.length(); if (isRequired() && len == 1) buf.append(" #REQUIRED"); else { String dv = getDefaultValue(p); if (dv == null) buf.append(" #IMPLIED"); else { buf.append(' '); attributeValueLiteral(dv); } } int lineStart = start + lineSep.length(); if (buf.length() - lineStart > lineLength && ct.isA(ContentType.ENUM)) { ModelBreaker breaker = new ModelBreaker(buf.substring(lineStart, typeStart), buf.substring(typeStart, typeEnd), buf.substring(typeEnd), lineLength); buf.setLength(start); while (breaker.hasNextLine()) { buf.append(lineSep); buf.append(breaker.nextLine()); } } } } return VoidValue.VOID; } boolean isRequired() { return true; } public VoidValue visitChoice(ChoicePattern p) { if (getAttributeType(p) != AttributeType.EMPTY) er.warning("attribute_occur_approx", p.getSourceLocation()); optionalAttributeOutput.visitComposite(p); return VoidValue.VOID; } public VoidValue visitOptional(OptionalPattern p) { if (getAttributeType(p) != AttributeType.SINGLE) er.warning("attribute_occur_approx", p.getSourceLocation()); optionalAttributeOutput.output(p.getChild()); return VoidValue.VOID; } } class OptionalAttributeOutput extends AttributeOutput { boolean isRequired() { return false; } } class SimpleTypeOutput extends PatternOutput { public VoidValue visitText(TextPattern p) { buf.append("CDATA"); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { buf.append(p.getValue()); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { paramEntityRef(p); return VoidValue.VOID; } public VoidValue visitData(DataPattern p) { Datatypes.Info info = Datatypes.getInfo(p.getDatatypeLibrary(), p.getType()); if (info == null) { er.warning("unrecognized_datatype", p.getSourceLocation()); buf.append("CDATA"); } else { if (warnDatatypes) { if (!info.isExact()) er.warning("datatype_approx", p.getType(), info.closestType(), p.getSourceLocation()); else { for (Param param : p.getParams()) er.warning("ignore_param", param.getName(), p.getType(), p.getSourceLocation()); if (p.getExcept() != null) er.warning("ignore_except", p.getType(), p.getSourceLocation()); } } buf.append(info.closestType()); } return VoidValue.VOID; } public VoidValue visitChoice(ChoicePattern p) { List list = p.getChildren(); boolean needSep = false; final int len = list.size(); for (int i = 0; i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (t != ContentType.NOT_ALLOWED) { if (needSep) buf.append('|'); else needSep = true; member.accept(this); } } for (int i = 0; i < len; i++) { Pattern member = list.get(i); ContentType t = getContentType(member); if (t == ContentType.NOT_ALLOWED) { if (needSep) buf.append(' '); else needSep = true; member.accept(this); } } return VoidValue.VOID; } } class TopLevelSimpleTypeOutput extends SimpleTypeOutput { public VoidValue visitList(ListPattern p) { if (warnDatatypes) er.warning("list_approx", p.getSourceLocation()); buf.append("CDATA"); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { if (getContentType(p) == ContentType.ENUM) { buf.append('('); super.visitValue(p); buf.append(')'); } else { Datatypes.Info info = Datatypes.getInfo(p.getDatatypeLibrary(), p.getType()); if (info == null) { er.warning("unrecognized_datatype", p.getSourceLocation()); buf.append("CDATA"); } else { String type = info.closestType(); if (warnDatatypes) er.warning("value_approx", type, p.getSourceLocation()); buf.append(type); } } return VoidValue.VOID; } public VoidValue visitChoice(ChoicePattern p) { ContentType t = getContentType(p); if (t == ContentType.ENUM) { buf.append('('); nestedSimpleTypeOutput.visitChoice(p); buf.append(')'); } else if (t == ContentType.SIMPLE_TYPE_CHOICE) { if (warnDatatypes) er.warning("datatype_choice_approx", p.getSourceLocation()); buf.append("CDATA"); } else super.visitChoice(p); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { ContentType t = getContentType(p); if (t == ContentType.ENUM) { buf.append('('); super.visitRef(p); buf.append(')'); } else if (t == ContentType.TEXT) buf.append("CDATA"); else super.visitRef(p); return VoidValue.VOID; } } private class ValueOutput extends PatternOutput { public VoidValue visitValue(ValuePattern p) { buf.append("CDATA #FIXED "); attributeValueLiteral(p.getValue()); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { paramEntityRef(p); return VoidValue.VOID; } } class GrammarOutput implements ComponentVisitor { public void visitContainer(Container c) { final List list = c.getComponents(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); } public VoidValue visitDiv(DivComponent c) { outputLeadingComments(c); outputInitialChildComments(c); visitContainer(c); outputFollowingComments(c); return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { if (c.getName() == DefineComponent.START) { outputLeadingComments(c); outputFollowingComments(c); if (analysis.getPattern() == analysis.getGrammarPattern()) c.getBody().accept(nestedContentModelOutput); } else { if (getContentType(c.getBody()) == ContentType.DIRECT_SINGLE_ELEMENT) outputElement((ElementPattern)c.getBody(), c); else if (!doneParamEntities.contains(c.getName())) { doneParamEntities.add(c.getName()); outputParamEntity(c); } } outputQueuedElements(); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { outputInclude(c); return VoidValue.VOID; } } void outputQueuedElements() { for (int i = 0; i < elementQueue.size(); i++) outputElement(elementQueue.get(i), null); elementQueue.clear(); } static void output(boolean warnDatatypes, Analysis analysis, OutputDirectory od, ErrorReporter er) throws IOException { try { new DtdOutput(warnDatatypes, analysis.getMainUri(), analysis, new HashSet(), od, er).topLevelOutput(); } catch (WrappedIOException e) { throw e.cause; } } void topLevelOutput() { GrammarPattern grammarPattern = analysis.getGrammarPattern(); xmlDecl(); Pattern p = analysis.getPattern(); if (p != grammarPattern) { outputLeadingComments(p); p.accept(nestedContentModelOutput); outputQueuedElements(); } if (grammarPattern != null) { outputLeadingComments(grammarPattern); outputInitialChildComments(grammarPattern); grammarOutput.visitContainer(grammarPattern); outputFollowingComments(grammarPattern); } close(); } void subOutput(GrammarPattern grammarPattern) { xmlDecl(); outputLeadingComments(grammarPattern); outputInitialChildComments(grammarPattern); grammarOutput.visitContainer(grammarPattern); outputFollowingComments(grammarPattern); close(); } void xmlDecl() { write(""); outputNewline(); } ContentType getContentType(Pattern p) { return analysis.getContentType(p); } AttributeType getAttributeType(Pattern p) { return analysis.getAttributeType(p); } Pattern getBody(String name) { return analysis.getBody(name); } void paramEntityRef(RefPattern p) { String name = p.getName(); buf.append('%'); buf.append(name); buf.append(';'); requiredParamEntities.add(name); } void attributeValueLiteral(String value) { buf.append('\''); for (int i = 0, len = value.length(); i < len; i++) { char c = value.charAt(i); switch (c) { case '<': buf.append("<"); break; case '&': buf.append("&"); break; case '\'': buf.append("'"); break; case '"': buf.append("""); break; case '\r': buf.append(" "); break; case '\n': buf.append(" "); break; case '\t': buf.append(" "); break; default: buf.append(c); break; } } buf.append('\''); } void outputRequiredComponents() { for (int i=0; i < requiredParamEntities.size(); i++) { String name = requiredParamEntities.get(i); Component c = part.getWhereProvided(name); if (c == null) externallyRequiredParamEntities.add(name); else if (c instanceof DefineComponent) { if (!doneParamEntities.contains(name)) { doneParamEntities.add(name); outputParamEntity((DefineComponent)c); } } else outputInclude((IncludeComponent)c); } requiredParamEntities.clear(); } void outputInclude(IncludeComponent inc) { String href = inc.getUri(); if (doneIncludes.contains(href)) return; if (pendingIncludes.contains(href)) { er.error("sorry_include_depend", inc.getSourceLocation()); return; } pendingIncludes.add(href); DtdOutput sub = new DtdOutput(warnDatatypes, href, analysis, reservedEntityNames, od, er); GrammarPattern g = (GrammarPattern)analysis.getSchema(href); sub.subOutput(g); requiredParamEntities.addAll(sub.externallyRequiredParamEntities); outputRequiredComponents(); outputLeadingComments(inc); String entityName = genEntityName(inc); outputNewline(); write("'); outputNewline(); write('%'); write(entityName); write(';'); outputNewline(); outputFollowingComments(inc); doneIncludes.add(href); pendingIncludes.remove(href); } String genEntityName(IncludeComponent inc) { String entityName = getAttributeAnnotation(inc, DTD_URI, "entityName"); if (entityName != null) { entityName = entityName.trim(); if (!Naming.isNcname(entityName)) { er.warning("entity_name_not_ncname", entityName, inc.getSourceLocation()); entityName = null; } } if (entityName == null) { String uri = inc.getUri(); int slash = uri.lastIndexOf('/'); if (slash >= 0) uri = uri.substring(slash + 1); int dot = uri.lastIndexOf('.'); if (dot > 0) uri = uri.substring(0, dot); if (Naming.isNcname(uri)) entityName = uri; } if (entityName == null) entityName = "ent"; if (!reserveEntityName(entityName)) { for (int i = 1;; i++) { String tem = entityName + Integer.toString(i); if (reserveEntityName(tem)) { entityName = tem; break; } } } return entityName; } private boolean reserveEntityName(String name) { if (reservedEntityNames.contains(name)) return false; reservedEntityNames.add(name); return true; } void outputParamEntity(DefineComponent def) { String name = def.getName(); Pattern body = def.getBody(); ContentType t = getContentType(body); buf.setLength(0); boolean wrap = true; if (t.isA(ContentType.MODEL_GROUP) || t.isA(ContentType.NOT_ALLOWED) || t.isA(ContentType.MIXED_ELEMENT_CLASS)) body.accept(nestedContentModelOutput); else if (t.isA(ContentType.MIXED_MODEL)) body.accept(topLevelContentModelOutput); else if (t.isA(ContentType.EMPTY)) { attributeOutput.output(body); wrap = false; } else if (t.isA(ContentType.ENUM)) body.accept(nestedSimpleTypeOutput); else if (t.isA(ContentType.VALUE)) { body.accept(valueOutput); wrap = false; } else if (t.isA(ContentType.SIMPLE_TYPE)) body.accept(topLevelSimpleTypeOutput); String replacement = buf.toString(); outputRequiredComponents(); outputLeadingComments(def); String elementName = analysis.getParamEntityElementName(name); if (elementName != null) { if (replacement.length() > 0) { outputNewline(); write("'); outputNewline(); } } else { doneParamEntities.add(name); outputNewline(); String prefix = ""; if (!wrap) { write(prefix); write(replacement); write(suffix); outputNewline(); } else outputModelBreak(prefix, replacement, suffix); } outputFollowingComments(def); } private void outputModelBreak(String prefix, String replacement, String suffix) { for (ModelBreaker breaker = new ModelBreaker(prefix, replacement, suffix, lineLength); breaker.hasNextLine();) { write(breaker.nextLine()); outputNewline(); } } void outputElement(ElementPattern p, Annotated def) { buf.setLength(0); Pattern content = p.getChild(); ContentType ct = getContentType(content); if (ct == ContentType.EMPTY) ; else if (ct == ContentType.MIXED_ELEMENT_CLASS) { er.warning("mixed_choice_approx", p.getSourceLocation()); buf.append("("); content.accept(nestedContentModelOutput); buf.append(")*"); } else if (ct.isA(ContentType.SIMPLE_TYPE)) { if (warnDatatypes) er.warning("data_content_approx", p.getSourceLocation()); buf.append("(#PCDATA)"); } else if (ct == ContentType.NOT_ALLOWED) return; // leave it undefined else content.accept(topLevelContentModelOutput); String contentModel = buf.length() == 0 ? "EMPTY" : buf.toString(); buf.setLength(0); attributeOutput.output(content); String atts = buf.toString(); outputRequiredComponents(); if (def != null) outputLeadingComments(def); outputLeadingComments(p); List names = NameClassSplitter.split(p.getNameClass()); for (NameNameClass name : names) { final String ns = name.getNamespaceUri(); String qName = name.getLocalName(); final String prefix = analysis.getElementPrefixForNamespaceUri(ns); if (prefix != null) qName = prefix + ":" + qName; outputNewline(); outputModelBreak(""); boolean needXmlns; if (ns == NameClass.INHERIT_NS) needXmlns = false; else if (prefix == null) needXmlns = true; else needXmlns = !analysis.getAttributeNamespaces(content).contains(ns); if (atts.length() != 0 || needXmlns) { write("'); outputNewline(); } } if (def != null) outputFollowingComments(def); } void outputAttributeNamespaces(Pattern p) { Set namespaces = analysis.getAttributeNamespaces(p); for (String ns : namespaces) { String prefix = analysis.getPrefixForNamespaceUri(ns); outputNewline(); outputIndent(); write("xmlns:"); write(prefix); write(" CDATA #FIXED "); buf.setLength(0); attributeValueLiteral(ns); write(buf.toString()); } } void outputLeadingComments(Annotated a) { outputComments(a.getLeadingComments()); } void outputInitialChildComments(Annotated a) { outputComments(a.getChildElementAnnotations()); } void outputFollowingComments(Annotated a) { outputComments(a.getFollowingElementAnnotations()); } void outputComments(List list) { for (AnnotationChild child : list) if (child instanceof Comment) outputComment(((Comment)child).getValue()); } void outputComment(String value) { outputNewline(); write(""); outputNewline(); } void outputIndent() { for (int i = 0; i < indent; i++) write(' '); } void outputNewline() { write(lineSep); } static class WrappedIOException extends RuntimeException { final IOException cause; WrappedIOException(IOException cause) { this.cause = cause; } public Throwable getCause() { return cause; } } void write(String s) { try { writer.write(s); } catch (IOException e) { throw new WrappedIOException(e); } } void write(char c) { try { writer.write(c); } catch (IOException e) { throw new WrappedIOException(e); } } void close() { try { writer.close(); } catch (IOException e) { throw new WrappedIOException(e); } } private static String getDefaultValue(AttributePattern p) { return getAttributeAnnotation(p, WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS, "defaultValue"); } private static String getAttributeAnnotation(Annotated p, String ns, String localName) { List list = p.getAttributeAnnotations(); for (int i = 0, len = list.size(); i < len; i++) { AttributeAnnotation att = list.get(i); if (att.getLocalName().equals(localName) && att.getNamespaceUri().equals(ns)) return att.getValue(); } return null; } } DtdOutputFormat.java000066400000000000000000000025021225366607500355100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.output.OutputFormat; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.OutputFailedException; import com.thaiopensource.relaxng.output.OutputDirectoryParamProcessor; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public class DtdOutputFormat implements OutputFormat { public void output(SchemaCollection sc, final OutputDirectory od, String[] params, String inputFormat, ErrorHandler eh) throws SAXException, IOException, OutputFailedException, InvalidParamsException { new OutputDirectoryParamProcessor(od).process(params, eh); Simplifier.simplify(sc); try { ErrorReporter er = new ErrorReporter(eh, DtdOutputFormat.class); Analysis analysis = new Analysis(sc, er); if (!er.getHadError()) DtdOutput.output(!inputFormat.equals("xml"), analysis, od, er); if (er.getHadError()) throw new OutputFailedException(); } catch (ErrorReporter.WrappedSAXException e) { throw e.getException(); } } } GrammarPart.java000066400000000000000000000111631225366607500346230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.Combine; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.output.common.ErrorReporter; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; class GrammarPart implements ComponentVisitor { private final ErrorReporter er; private final Map defines; private final Set attlists; private final Set implicitlyCombinedDefines; private final Map combineTypes; private final SchemaCollection schemas; private final Map parts; // maps name to component that provides it private final Map whereProvided = new HashMap(); private final Set pendingIncludes; public static class IncludeLoopException extends RuntimeException { private final IncludeComponent include; public IncludeLoopException(IncludeComponent include) { this.include = include; } public IncludeComponent getInclude() { return include; } } GrammarPart(ErrorReporter er, Map defines, Set attlists, SchemaCollection schemas, Map parts, GrammarPattern p) { this.er = er; this.defines = defines; this.attlists = attlists; this.schemas = schemas; this.parts = parts; this.pendingIncludes = new HashSet(); this.implicitlyCombinedDefines = new HashSet(); this.combineTypes = new HashMap(); visitContainer(p); } private GrammarPart(GrammarPart part, GrammarPattern p) { er = part.er; defines = part.defines; schemas = part.schemas; parts = part.parts; attlists = part.attlists; pendingIncludes = part.pendingIncludes; implicitlyCombinedDefines = part.implicitlyCombinedDefines; combineTypes = part.combineTypes; visitContainer(p); } Set providedSet() { return whereProvided.keySet(); } public VoidValue visitContainer(Container c) { List list = c.getComponents(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { return visitContainer(c); } public VoidValue visitDefine(DefineComponent c) { String name = c.getName(); Combine combine = c.getCombine(); if (combine == null) { if (implicitlyCombinedDefines.contains(name)) er.error("multiple_no_combine", name, c.getSourceLocation()); else implicitlyCombinedDefines.add(name); } else { Combine oldCombine = combineTypes.get(name); if (oldCombine != null) { if (oldCombine != combine) er.error("inconsistent_combine", c.getSourceLocation()); } else combineTypes.put(name, combine); } Pattern oldDef = defines.get(name); if (oldDef != null) { if (combine == Combine.CHOICE) er.error("sorry_combine_choice", c.getSourceLocation()); else if (combine == Combine.INTERLEAVE) { InterleavePattern ip = new InterleavePattern(); ip.getChildren().add(oldDef); ip.getChildren().add(c.getBody()); ip.setSourceLocation(c.getSourceLocation()); defines.put(name, ip); attlists.add(name); } } else { defines.put(name, c.getBody()); whereProvided.put(name, c); } return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { String uri = c.getUri(); if (pendingIncludes.contains(uri)) throw new IncludeLoopException(c); pendingIncludes.add(uri); GrammarPattern p = (GrammarPattern)(schemas.getSchemaDocumentMap().get(uri)).getPattern(); GrammarPart part = new GrammarPart(this, p); parts.put(uri, part); for (String name : part.providedSet()) whereProvided.put(name, c); pendingIncludes.remove(uri); return VoidValue.VOID; } Component getWhereProvided(String paramEntityName) { return whereProvided.get(paramEntityName); } } ModelBreaker.java000066400000000000000000000111631225366607500347420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import java.util.NoSuchElementException; class ModelBreaker { private boolean done = false; private BreakIterator iter; private final String prefix; private final String model; private final String suffix; private final int maxLineLength; private int modelPos; private ModelBreaker nested = null; private static class BreakIterator { private final String model; private int pos = 0; private final int length; BreakIterator(String model) { this.model = model; this.length = model.length(); } int getPos() { return pos; } boolean advance() { boolean advanced = false; int level = 0; for (; pos < length; pos++) { switch (model.charAt(pos)) { case '(': level++; break; case ')': level--; break; case ',': if (level != 0) break; if (++pos != length) return true; break; case '|': if (level != 0 || !advanced) break; return true; case ' ': if (level != 0 || !advanced) break; return true; } advanced = true; } return false; } } ModelBreaker(String prefix, String model, String suffix, int maxLineLength) { if (isSingleGroup(model)) { int open = model.indexOf('(') + 1; this.prefix = prefix + model.substring(0, open); this.model = model.substring(open); } else { this.prefix = prefix; this.model = model; } this.suffix = suffix; this.maxLineLength = maxLineLength; this.modelPos = 0; } boolean hasNextLine() { if (nested != null && nested.hasNextLine()) return true; return !done; } String nextLine() { if (nested != null && nested.hasNextLine()) return nested.nextLine(); if (done) throw new NoSuchElementException(); int avail = maxLineLength - prefix.length(); int breakPos; boolean tooBig = false; if ((model.length() - modelPos) + suffix.length() > avail) { if (iter == null) iter = new BreakIterator(model); breakPos = -1; do { int pos = iter.getPos(); if (pos >= model.length()) break; int w = pos - modelPos; if (w > 0) { if (w > avail) { if (breakPos == -1) { breakPos = pos; tooBig = true; } break; } breakPos = pos; } } while (iter.advance()); if (breakPos == -1) { tooBig = true; breakPos = model.length(); } } else breakPos = model.length(); int nextModelPos; if (breakPos < model.length() && model.charAt(breakPos) == ' ') nextModelPos = breakPos + 1; else nextModelPos = breakPos; StringBuffer buf = new StringBuffer(); if (modelPos == 0) buf.append(prefix); else { for (int i = 0, len = prefix.length(); i < len; i++) buf.append(' '); } if (tooBig && (modelPos != 0 || breakPos != model.length())) { String nestSuffix; if (breakPos == model.length()) { done = true; nestSuffix = suffix; } else nestSuffix = ""; nested = new ModelBreaker(buf.toString(), model.substring(modelPos, breakPos), nestSuffix, maxLineLength); modelPos = nextModelPos; return nested.nextLine(); } buf.append(model.substring(modelPos, breakPos)); if (nextModelPos == model.length()) { done = true; buf.append(suffix); } modelPos = nextModelPos; return buf.toString(); } private static boolean isSingleGroup(String model) { int length = model.length(); if (length == 0) return false; int i = 0; if (model.charAt(0) == '|') i++; if (model.charAt(i) != '(') return false; loop: while (length > i) { switch (model.charAt(length - 1)) { case '*': case '+': case '?': case ',': case '|': case ')': length--; break; default: break loop; } } int level = 0; for (++i; i < length; i++) switch (model.charAt(i)) { case '(': level++; break; case ')': if (level == 0) return false; level--; break; } return true; } static public void main(String[] args) throws NumberFormatException { for (ModelBreaker breaker = new ModelBreaker(args[0], args[1], args[2], Integer.parseInt(args[3])); breaker.hasNextLine();) System.err.println(breaker.nextLine()); } } NamespaceManager.java000066400000000000000000000040221225366607500355710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; class NamespaceManager { // map namespace URIs to non-empty prefix private final Map namespaceUriMap = new HashMap(); private String defaultNamespaceUri = null; private final Set usedPrefixes = new HashSet(); private final Set unassignedNamespaceUris = new HashSet(); NamespaceManager() { usedPrefixes.add("xml"); namespaceUriMap.put(WellKnownNamespaces.XML, "xml"); } String getPrefixForNamespaceUri(String ns) { return namespaceUriMap.get(ns); } String getDefaultNamespaceUri() { return defaultNamespaceUri; } void assignPrefixes() { if (defaultNamespaceUri == null) defaultNamespaceUri = ""; int n = 0; for (String ns : unassignedNamespaceUris) { for (; ;) { ++n; String prefix = "ns" + Integer.toString(n); if (!usedPrefixes.contains(prefix)) { namespaceUriMap.put(ns, prefix); break; } } } } void noteName(NameNameClass nc, boolean defaultable) { String ns = nc.getNamespaceUri(); if (ns.equals("") || ns == NameClass.INHERIT_NS) { if (defaultable) defaultNamespaceUri = ""; return; } String assignedPrefix = namespaceUriMap.get(ns); if (assignedPrefix != null) return; String prefix = nc.getPrefix(); if (prefix == null) { if (defaultNamespaceUri == null && defaultable) defaultNamespaceUri = ns; unassignedNamespaceUris.add(ns); } else { if (usedPrefixes.contains(prefix)) unassignedNamespaceUris.add(ns); else { usedPrefixes.add(prefix); namespaceUriMap.put(ns, prefix); unassignedNamespaceUris.remove(ns); } } } } Simplifier.java000066400000000000000000000106531225366607500345140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdpackage com.thaiopensource.relaxng.output.dtd; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import java.util.Iterator; import java.util.List; class Simplifier extends AbstractPatternVisitor implements ComponentVisitor { public static void simplify(SchemaCollection sc) { Simplifier simplifier = new Simplifier(); for (SchemaDocument sd : sc.getSchemaDocumentMap().values()) sd.setPattern(sd.getPattern().accept(simplifier)); } private Simplifier() { } public Pattern visitGrammar(GrammarPattern p) { visitContainer(p); return p; } public VoidValue visitContainer(Container c) { for (Component component : c.getComponents()) component.accept(this); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { return visitContainer(c); } public VoidValue visitDiv(DivComponent c) { return visitContainer(c); } public VoidValue visitDefine(DefineComponent c) { c.setBody(c.getBody().accept(this)); return VoidValue.VOID; } public Pattern visitChoice(ChoicePattern p) { boolean hadEmpty = false; List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) list.set(i, list.get(i).accept(this)); for (Iterator iter = list.iterator(); iter.hasNext();) { Pattern child = iter.next(); if (child instanceof NotAllowedPattern) iter.remove(); else if (child instanceof EmptyPattern) { hadEmpty = true; iter.remove(); } } if (list.size() == 0) return copy(new NotAllowedPattern(), p); Pattern tem; if (list.size() == 1) tem = list.get(0); else tem = p; if (hadEmpty && !(tem instanceof OptionalPattern) && !(tem instanceof ZeroOrMorePattern)) { if (tem instanceof OneOrMorePattern) tem = new ZeroOrMorePattern(((OneOrMorePattern)tem).getChild()); else tem = new OptionalPattern(tem); copy(tem, p); } return tem; } public Pattern visitComposite(CompositePattern p) { List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) list.set(i, list.get(i).accept(this)); for (Iterator iter = list.iterator(); iter.hasNext();) { Pattern child = iter.next(); if (child instanceof EmptyPattern) iter.remove(); } if (list.size() == 0) return copy(new EmptyPattern(), p); if (list.size() == 1) return p.getChildren().get(0); return p; } public Pattern visitInterleave(InterleavePattern p) { boolean hadText = false; for (Iterator iter = p.getChildren().iterator(); iter.hasNext();) { Pattern child = iter.next(); if (child instanceof TextPattern) { iter.remove(); hadText = true; } } if (!hadText) return visitComposite(p); return copy(new MixedPattern(visitComposite(p)), p); } public Pattern visitUnary(UnaryPattern p) { p.setChild(p.getChild().accept(this)); return p; } private static T copy(T to, T from) { to.setSourceLocation(from.getSourceLocation()); return to; } public Pattern visitPattern(Pattern p) { return p; } } resources/000077500000000000000000000000001225366607500335535ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtdMessages.properties000066400000000000000000000044321225366607500374430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-dtd/src/main/com/thaiopensource/relaxng/output/dtd/resourcesdatatype_approx=approximating datatype \"{0}\" by \"{1}\" value_approx=approximating value by \"{0}\" data_content_approx=approximating datatype in content by \"#PCDATA\" datatype_choice_approx=approximating choice of datatypes by \"CDATA\" empty_attribute_approx=approximating empty attribute by \"CDATA\" mixed_choice_approx=approximating mixed choice by repeated mixed choice list_approx=approximating \"list\" by \"CDATA\" attribute_occur_approx=approximating attribute occurrence include_loop=include loop ref_loop=illegal recursive reference bad_attribute_type=illegal content for \"attribute\" content sorry_choice=sorry, cannot handle this kind of \"choice\" sorry_external_ref=sorry, \"externalRef\" is not supported sorry_group=sorry, cannot handle this kind of \"group\" sorry_include_depend=sorry, include depend sorry_interleave=sorry, cannot handle this kind of \"interleave\" sorry_mixed=sorry, cannot handle this kind of \"mixed\" multiple_no_combine=multiple definitions of \"{0}\" without a \"combine\" attribute inconsistent_combine=inconsistent values for the \"combine\" attribute sorry_combine_choice=sorry, combining definitions with combine=\"choice\" is not supported sorry_nested_grammar=sorry, nested grammars are not supported sorry_one_or_more=sorry, cannot handle this kind of \"oneOrMore\" sorry_optional=sorry, cannot handle this kind of \"optional\" sorry_parent_ref=sorry, \"parent\" is not supported sorry_wildcard=sorry, wildcards are not supported sorry_zero_or_more=sorry, cannot handle this kind of \"zeroOrMore\" undefined_ref=reference to undefined pattern unrecognized_datatype=unrecognized datatype sorry_include_override=sorry, cannot handle overrides inside \"include\" sorry_multiple_element=sorry, not handled: duplicate declaration of element \"{1}\" from namespace \"{0}\" other_element=other element declaration is here sorry_choice_attribute_name=sorry, ambiguous attribute choice not handled (attribute \"{1}\" from namespace \"{0}\") not_attlist=\"{0}\" does not correspond to an ATTLIST declarations and so cannot be combined with \"interleave\" ignore_param=ignoring parameter \"{0}\" of datatype \"{1}\" ignore_except=ignoring exception applying to datatype \"{0}\" entity_name_not_ncname=value of entityName annotation attribute \"{0}\" is not allowed as an XML entity namejing-trang-20131210+dfsg+1/mod/convert-to-dtd/todo.txt000066400000000000000000000024561225366607500222410ustar00rootroot00000000000000Generate comments from a:documentation elements Avoid warning for content that is data of type string Option to generate namespace declarations only on start elements Generate parameter entities to allow change of namespace prefix Support nested grammars Check for non-deterministic content models Option to protect attlist/element declarations with marked section Allow mixed(repeat(NOT_ALLOWED)) Prettier formatting of ATTLISTs Order requiredParamEntities by definition order Customizable indent and line length Approximate by NMTOKENS when possible Have a top-level annotation indicating a redefinition point (as in DocBook) Recognize definitions being used as INCLUDE/IGNORE (as in TEI) Give warnings for definitions that had to be expanded Closer approximation of choice of datatypes Approximate when single element restriction is violated Allow choice of attributes and data Try to push namespace declarations down into appropriate attribute groups Support for ANY used as a model-group hook Approximate wildcards intelligently Handle interleave of zero or more element class with model group Turn elements with content into EMPTY. Deal with characters outside repertoire of character encoding. Investigate using compact syntax pretty-printer for formatting content models. jing-trang-20131210+dfsg+1/mod/convert-to-xsd/000077500000000000000000000000001225366607500205475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/mod.xml000066400000000000000000000003201225366607500220430ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/000077500000000000000000000000001225366607500213365ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/000077500000000000000000000000001225366607500222625ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/000077500000000000000000000000001225366607500230405ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/000077500000000000000000000000001225366607500260705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500275305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/000077500000000000000000000000001225366607500310705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/000077500000000000000000000000001225366607500316665ustar00rootroot00000000000000AbstractElementTypeSelector.java000066400000000000000000000136611225366607500401010ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup; import com.thaiopensource.relaxng.output.xsd.basic.ComplexType; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeNotAllowedContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeSimpleContent; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRef; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction; import com.thaiopensource.xml.util.Name; import java.util.HashMap; import java.util.List; import java.util.Map; class AbstractElementTypeSelector { private final Schema schema; private final NamespaceManager nsm; private final ComplexTypeSelector complexTypeSelector; private final Map abstractElementComplexTypeMap = new HashMap(); private final ComplexType urType = new ComplexTypeNotAllowedContent(); AbstractElementTypeSelector(Schema schema, NamespaceManager nsm, ComplexTypeSelector complexTypeSelector) { this.schema = schema; this.nsm = nsm; this.complexTypeSelector = complexTypeSelector; } ComplexType getAbstractElementType(Name name) { ComplexType ct = abstractElementComplexTypeMap.get(name); if (ct == null) { ct = computeAbstractElementType(name); if (ct == null) ct = urType; abstractElementComplexTypeMap.put(name, ct); } if (ct == urType) return null; return ct; } private ComplexType computeAbstractElementType(Name name) { List members = nsm.getAbstractElementSubstitutionGroupMembers(name); if (members == null) return null; ComplexType commonType = null; for (Name member : members) { ComplexType ct = getElementType(member, nsm); if (ct == null) return null; if (commonType == null) commonType = ct; else { commonType = commonBaseType(commonType, ct); if (commonType == null) return null; } } return commonType; } private ComplexType commonBaseType(ComplexType ct1, ComplexType ct2) { if (ct1.equals(ct2)) return ct1; if (isValidlyDerived(ct1, ct2)) return ct2; if (isValidlyDerived(ct2, ct1)) return ct1; return null; } private boolean isValidlyDerived(ComplexType ct1, ComplexType ct2) { if (ct1 instanceof ComplexTypeComplexContent && ct2 instanceof ComplexTypeComplexContent) return isComplexContentValidlyDerived((ComplexTypeComplexContent)ct1, (ComplexTypeComplexContent)ct2); if (ct1 instanceof ComplexTypeSimpleContent && ct2 instanceof ComplexTypeSimpleContent) return isSimpleContentValidlyDerived((ComplexTypeSimpleContent)ct1, (ComplexTypeSimpleContent)ct2); return false; } private boolean isComplexContentValidlyDerived(ComplexTypeComplexContent ct1, ComplexTypeComplexContent ct2) { ComplexTypeComplexContentExtension ex = complexTypeSelector.transformComplexContent(ct2); String base = ex.getBase(); if (base == null || ex.getParticle() != null || !ex.getAttributeUses().equals(AttributeGroup.EMPTY) || ex.isMixed()) return false; Particle particle = ct1.getParticle(); for (;;) { String tem = complexTypeSelector.particleBase(particle); if (base.equals(tem)) return true; if (tem == null) break; if (!complexTypeSelector.isComplexType(tem)) break; particle = schema.getGroup(tem).getParticle(); } return false; } private boolean isSimpleContentValidlyDerived(ComplexTypeSimpleContent ct1, ComplexTypeSimpleContent ct2) { ComplexTypeSimpleContentExtension ex = complexTypeSelector.transformSimpleContent(ct2); if (!ex.getAttributeUses().equals(AttributeGroup.EMPTY)) return false; String base = ex.getBase(); if (base == null) return isSimpleTypeValidlyDerived(ct1.getSimpleType(), ex.getSimpleType()); else return isSimpleTypeValidlyDerivedFromName(ct1.getSimpleType(), base); } private boolean isSimpleTypeValidlyDerived(SimpleType st1, SimpleType st2) { // XXX take advantage of cos-st-derived-ok 2.2.4 (SQC seems to have bugs here) if (st2.getAnnotation() != null) return false; if (st2 instanceof SimpleTypeRef) return isSimpleTypeValidlyDerivedFromName(st1, ((SimpleTypeRef)st2).getName()); if (st2 instanceof SimpleTypeRestriction) { SimpleTypeRestriction restriction = (SimpleTypeRestriction)st2; if (restriction.getFacets().size() > 0) return false; return isSimpleTypeValidlyDerivedFromBuiltin(st1, restriction.getName()); } return false; } private boolean isSimpleTypeValidlyDerivedFromName(SimpleType st, String typeName) { while (st instanceof SimpleTypeRef) { String tem = ((SimpleTypeRef)st).getName(); if (tem.equals(typeName)) return true; st = schema.getSimpleType(tem).getSimpleType(); } return false; } private boolean isSimpleTypeValidlyDerivedFromBuiltin(SimpleType st, String builtinTypeName) { while (st instanceof SimpleTypeRef) st = schema.getSimpleType(((SimpleTypeRef)st).getName()).getSimpleType(); if (!(st instanceof SimpleTypeRestriction)) return false; String tem = ((SimpleTypeRestriction)st).getName(); do { if (tem.equals(builtinTypeName)) return true; tem = BuiltinSimpleTypeHierarchy.getParentType(tem); } while (tem != null); return false; } private ComplexType getElementType(Name name, NamespaceManager nsm) { Element element = nsm.getGlobalElement(name); if (element != null) return element.getComplexType(); return getAbstractElementType(name); } } BasicBuilder.java000066400000000000000000000764741225366607500350240ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.TextAnnotation; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.output.common.NameClassSplitter; import com.thaiopensource.relaxng.output.xsd.basic.Annotation; import com.thaiopensource.relaxng.output.xsd.basic.Attribute; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUseChoice; import com.thaiopensource.relaxng.output.xsd.basic.ComplexType; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeNotAllowedContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeSimpleContent; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.Facet; import com.thaiopensource.relaxng.output.xsd.basic.GroupRef; import com.thaiopensource.relaxng.output.xsd.basic.Occurs; import com.thaiopensource.relaxng.output.xsd.basic.OptionalAttribute; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll; import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice; import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat; import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeList; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRef; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion; import com.thaiopensource.relaxng.output.xsd.basic.Wildcard; import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute; import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; public class BasicBuilder { private final PatternVisitor simpleTypeBuilder = new SimpleTypeBuilder(); private final PatternVisitor attributeUseBuilder = new AttributeUseBuilder(); private final PatternVisitor optionalAttributeUseBuilder = new OptionalAttributeUseBuilder(); private final PatternVisitor particleBuilder = new ParticleBuilder(); private final PatternVisitor occursCalculator = new OccursCalculator(); private final ComponentVisitor schemaBuilder; private final ErrorReporter er; private final String inheritedNamespace; private final Schema schema; private final SchemaInfo si; private final Guide guide; /** * Preconditions for calling visit methods in this class are that the child type * - contains DATA * - does not contains ELEMENT * - does not contain TEXT */ private class SimpleTypeBuilder extends AbstractPatternVisitor { public SimpleType visitData(DataPattern p) { String library = p.getDatatypeLibrary(); String type = p.getType(); List facets = new Vector(); SourceLocation location = p.getSourceLocation(); if (!library.equals("") && !library.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES)) { type = "string"; er.warning("unsupported_datatype_library", library, location); } else { if (type.equals("NOTATION")) type = "QName"; for (Param param : p.getParams()) facets.add(new Facet(param.getSourceLocation(), makeAnnotation(param), param.getName(), param.getValue())); } return new SimpleTypeRestriction(location, makeAnnotation(p), type, facets); } public SimpleType visitValue(ValuePattern p) { String library = p.getDatatypeLibrary(); String type = p.getType(); List facets = new Vector(); SourceLocation location = p.getSourceLocation(); if (!library.equals("") && !library.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES)) { type = "string"; er.warning("unsupported_datatype_library", library, location); } else { if (type.equals("NOTATION")) type = "QName"; String prefix = null; String namespace = null; Iterator> bindings = p.getPrefixMap().entrySet().iterator(); if (bindings.hasNext()) { Map.Entry binding = bindings.next(); prefix = binding.getKey(); namespace = resolveNamespace(binding.getValue()); } facets.add(new Facet(location, makeAnnotation(p), "enumeration", p.getValue(), prefix, namespace)); } return new SimpleTypeRestriction(location, null, type, facets); } public SimpleType visitComposite(CompositePattern p) { List result = new Vector(); for (Pattern child : p.getChildren()) { if (si.getChildType(child).contains(ChildType.DATA)) result.add(child.accept(this)); } if (result.size() == 1) return result.get(0); else return new SimpleTypeUnion(p.getSourceLocation(), makeAnnotation(p), result); } public SimpleType visitUnary(UnaryPattern p) { return p.getChild().accept(this); } public SimpleType visitList(ListPattern p) { SourceLocation location = p.getSourceLocation(); Pattern child = p.getChild(); ChildType childType = si.getChildType(child); if (childType.equals(ChildType.EMPTY)) return makeEmptySimpleType(location); boolean bad = false; if (childType.contains(ChildType.ELEMENT)) { er.warning("list_contains_element", location); bad = true; } if (childType.contains(ChildType.ATTRIBUTE)) { er.warning("list_contains_attribute", location); bad = true; } if (childType.contains(ChildType.TEXT)) { er.warning("list_contains_text", location); bad = true; } if (bad) return makeStringType(location); // the type isn't NOT_ALLOWED, because the list would have type NOT_ALLOWED if it was // the type isn't EMPTY (checked above) // the type does not contain TEXT, ELEMENT or ATTRIBUTE (checked above) // therefore the type must contain DATA // so the preconditions for calling accept(this) are met return new SimpleTypeList(location, makeAnnotation(p), child.accept(this), child.accept(occursCalculator)); } public SimpleType visitRef(RefPattern p) { return new SimpleTypeRef(p.getSourceLocation(), makeAnnotation(p), p.getName()); } public SimpleType visitPattern(Pattern p) { // TODO throw an error return null; } } class OccursCalculator extends AbstractPatternVisitor { public Occurs visitOptional(OptionalPattern p) { return new Occurs(0, p.getChild().accept(this).getMax()); } public Occurs visitZeroOrMore(ZeroOrMorePattern p) { return new Occurs(0, Occurs.UNBOUNDED); } public Occurs visitOneOrMore(OneOrMorePattern p) { return new Occurs(p.getChild().accept(this).getMin(), Occurs.UNBOUNDED); } public Occurs visitData(DataPattern p) { return Occurs.EXACTLY_ONE; } public Occurs visitValue(ValuePattern p) { return Occurs.EXACTLY_ONE; } public Occurs visitEmpty(EmptyPattern p) { return new Occurs(0, 0); } private Occurs sum(CompositePattern p) { Occurs occ = new Occurs(0, 0); List children = p.getChildren(); for (int i = 0, len = children.size(); i < len; i++) occ = Occurs.add(occ, children.get(i).accept(this)); return occ; } public Occurs visitInterleave(InterleavePattern p) { return sum(p); } public Occurs visitGroup(GroupPattern p) { return sum(p); } public Occurs visitChoice(ChoicePattern p) { List children = p.getChildren(); Occurs occ = children.get(0).accept(this); for (int i = 1, len = children.size(); i < len; i++) { Occurs tem = children.get(i).accept(this); occ = new Occurs(Math.min(occ.getMin(), tem.getMin()), Math.max(occ.getMax(), tem.getMax())); } return occ; } public Occurs visitRef(RefPattern p) { return si.getBody(p).accept(this); } public Occurs visitPattern(Pattern p) { return null; } } /** * Precondition for calling visit methods in this class is that the child type * contains ELEMENT. */ class ParticleBuilder extends AbstractPatternVisitor { public Particle visitElement(ElementPattern p) { ComplexType type; Pattern child = p.getChild(); ChildType ct = si.getChildType(child); AttributeUse attributeUses; if (ct.contains(ChildType.ATTRIBUTE)) attributeUses = child.accept(attributeUseBuilder); else attributeUses = AttributeGroup.EMPTY; Particle particle = null; boolean mixed = false; if (ct.contains(ChildType.ELEMENT)) { if (ct.contains(ChildType.DATA)) mixed = true; // TODO give an error particle = child.accept(particleBuilder); } if (ct.contains(ChildType.TEXT)) mixed = true; if (particle == null && mixed && attributeUses.equals(AttributeGroup.EMPTY)) type = new ComplexTypeSimpleContent(attributeUses, makeStringType(p.getSourceLocation())); else if (ct.contains(ChildType.DATA) && !mixed && particle == null) { SimpleType simpleType = child.accept(simpleTypeBuilder); if (ct.contains(ChildType.EMPTY)) simpleType = makeUnionWithEmptySimpleType(simpleType, p.getSourceLocation()); type = new ComplexTypeSimpleContent(attributeUses, simpleType); } else if (ct.equals(ChildType.NOT_ALLOWED)) type = new ComplexTypeNotAllowedContent(); else type = new ComplexTypeComplexContent(attributeUses, particle, mixed); List names = NameClassSplitter.split(p.getNameClass()); Wildcard[] wc = splitElementWildcard(WildcardBuilder.createWildcard(p.getNameClass(), inheritedNamespace)); Annotation annotation = makeAnnotation(p); Annotation elementAnnotation = names.size() + wc.length == 1 ? annotation : null; List result = new Vector(); for (NameNameClass name : names) result.add(new Element(p.getSourceLocation(), elementAnnotation, makeName(name), type)); for (int i = 0; i < wc.length; i++) result.add(new WildcardElement(p.getSourceLocation(), elementAnnotation, wc[i])); if (result.size() == 1) return result.get(0); return new ParticleChoice(p.getSourceLocation(), annotation, result); } public Particle visitOneOrMore(OneOrMorePattern p) { return new ParticleRepeat(p.getSourceLocation(), makeAnnotation(p), p.getChild().accept(this), Occurs.ONE_OR_MORE); } public Particle visitZeroOrMore(ZeroOrMorePattern p) { return new ParticleRepeat(p.getSourceLocation(), makeAnnotation(p), p.getChild().accept(this), Occurs.ZERO_OR_MORE); } public Particle visitOptional(OptionalPattern p) { return new ParticleRepeat(p.getSourceLocation(), makeAnnotation(p), p.getChild().accept(this), Occurs.OPTIONAL); } public Particle visitChoice(ChoicePattern p) { List children = new Vector(); boolean optional = false; for (Pattern pattern : p.getChildren()) { ChildType ct = si.getChildType(pattern); if (ct.contains(ChildType.ELEMENT)) children.add(pattern.accept(this)); else if (!ct.equals(ChildType.NOT_ALLOWED)) optional = true; } Annotation annotation = makeAnnotation(p); Particle result; if (children.size() == 1 && annotation == null) result = children.get(0); else result = new ParticleChoice(p.getSourceLocation(), annotation, children); if (optional) return new ParticleRepeat(p.getSourceLocation(), null, result, Occurs.OPTIONAL); return result; } public Particle visitGroup(GroupPattern p) { Annotation annotation = makeAnnotation(p); List children = buildChildren(p); if (children.size() == 1 && annotation == null) return children.get(0); else return new ParticleSequence(p.getSourceLocation(), annotation, children); } public Particle visitInterleave(InterleavePattern p) { Annotation annotation = makeAnnotation(p); List children = buildChildren(p); if (children.size() == 1 && annotation == null) return children.get(0); else return new ParticleAll(p.getSourceLocation(), annotation, children); } private List buildChildren(CompositePattern p) { List result = new Vector(); for (Pattern pattern : p.getChildren()) { if (si.getChildType(pattern).contains(ChildType.ELEMENT)) result.add(pattern.accept(this)); } return result; } public Particle visitMixed(MixedPattern p) { return p.getChild().accept(this); } public Particle visitRef(RefPattern p) { return new GroupRef(p.getSourceLocation(), makeAnnotation(p), p.getName()); } public Particle visitPattern(Pattern p) { return null; } } /** * Precondition for visitMethods is that the childType contains ATTRIBUTE */ class OptionalAttributeUseBuilder extends AbstractPatternVisitor { public AttributeUse visitAttribute(AttributePattern p) { SourceLocation location = p.getSourceLocation(); Pattern child = p.getChild(); ChildType ct = si.getChildType(child); SimpleType value; if (ct.contains(ChildType.DATA) && !ct.contains(ChildType.TEXT)) { value = child.accept(simpleTypeBuilder); if (ct.contains(ChildType.EMPTY)) value = makeUnionWithEmptySimpleType(value, location); } else if (ct.contains(ChildType.EMPTY) && !ct.contains(ChildType.TEXT)) value = makeEmptySimpleType(location); else value = null; List names = NameClassSplitter.split(p.getNameClass()); Wildcard wc = WildcardBuilder.createWildcard(p.getNameClass(), inheritedNamespace); List choices = new Vector(); Annotation annotation = makeAnnotation(p); boolean singleChoice = names.size() + (wc != null ? 1 : 0) == 1; Annotation attributeAnnotation = singleChoice ? annotation : null; for (NameNameClass name : names) { Attribute att = new Attribute(location, attributeAnnotation, makeName((name)), value); if (!singleChoice || isOptional()) choices.add(new OptionalAttribute(att.getLocation(), null, att, p.getAttributeAnnotation(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS, "defaultValue"))); else choices.add(att); } if (wc != null) { if (!allowsAnyString(child)) er.warning("wildcard_attribute_value", p.getSourceLocation()); if (!isOptional()) er.warning("wildcard_attribute_optional", p.getSourceLocation()); choices.add(new WildcardAttribute(p.getSourceLocation(), attributeAnnotation, wc)); } if (choices.size() == 1) return choices.get(0); return new AttributeGroup(p.getSourceLocation(), annotation, choices); } boolean isOptional() { return true; } public AttributeUse visitOneOrMore(OneOrMorePattern p) { return p.getChild().accept(this); } public AttributeUse visitMixed(MixedPattern p) { return p.getChild().accept(this); } public AttributeUse visitZeroOrMore(ZeroOrMorePattern p) { return p.getChild().accept(optionalAttributeUseBuilder); } public AttributeUse visitOptional(OptionalPattern p) { return p.getChild().accept(optionalAttributeUseBuilder); } public AttributeUse visitRef(RefPattern p) { AttributeUse ref = new AttributeGroupRef(p.getSourceLocation(), makeAnnotation(p), p.getName()); if (!isOptional()) return ref; List choices = new Vector(); choices.add(ref); choices.add(AttributeGroup.EMPTY); return new AttributeUseChoice(p.getSourceLocation(), null, choices); } public AttributeUse visitComposite(CompositePattern p) { List uses = new Vector(); for (Pattern child : p.getChildren()) { if (si.getChildType(child).contains(ChildType.ATTRIBUTE)) uses.add(child.accept(this)); } if (uses.size() == 0) return AttributeGroup.EMPTY; if (uses.size() == 1) return uses.get(0); if (isOptional()) er.warning("optional_attribute_group", p.getSourceLocation()); return new AttributeGroup(p.getSourceLocation(), null, uses); } public AttributeUse visitChoice(ChoicePattern p) { PatternVisitor childVisitor = this; for (Pattern child : p.getChildren()) { if (!si.getChildType(child).contains(ChildType.ATTRIBUTE)) { childVisitor = optionalAttributeUseBuilder; break; } } boolean hasChildren = false; List uses = new Vector(); for (Pattern child : p.getChildren()) { ChildType ct = si.getChildType(child); if (ct.contains(ChildType.ATTRIBUTE)) { AttributeUse use = child.accept(childVisitor); if (uses.size() != 1 || !use.equals(uses.get(0))) uses.add(use); } if (ct.contains(ChildType.ELEMENT) || ct.contains(ChildType.DATA) || ct.contains(ChildType.TEXT)) hasChildren = true; } if (hasChildren) er.warning("attribute_child_choice", p.getSourceLocation()); if (uses.size() == 1) return uses.get(0); return new AttributeUseChoice(p.getSourceLocation(), null, uses); } public AttributeUse visitPattern(Pattern p) { return null; } } class AttributeUseBuilder extends OptionalAttributeUseBuilder { boolean isOptional() { return false; } } class SchemaBuilder implements ComponentVisitor { boolean groupEnableAbstractElements; SchemaBuilder(boolean groupEnableAbstractElements) { this.groupEnableAbstractElements = groupEnableAbstractElements; } public VoidValue visitDefine(DefineComponent c) { addLeadingComments(c); String name = c.getName(); SourceLocation location = c.getSourceLocation(); Annotation annotation = makeAnnotation(c); if (name == DefineComponent.START) { if (!si.isIgnored(c)) { Pattern body = c.getBody(); ChildType ct = si.getChildType(body); if (ct.contains(ChildType.ELEMENT)) schema.addRoot(body.accept(particleBuilder), location, annotation); } } else { Pattern body = si.getBody(c); if (body != null) { ChildType ct = si.getChildType(body); if (ct.contains(ChildType.ELEMENT)) { guide.setGroupEnableAbstractElement(name, getGroupEnableAbstractElements(c, groupEnableAbstractElements)); schema.defineGroup(name, body.accept(particleBuilder), location, annotation); } else if (ct.contains(ChildType.DATA) && !ct.contains(ChildType.TEXT)) schema.defineSimpleType(name, body.accept(simpleTypeBuilder), location, annotation); if (ct.contains(ChildType.ATTRIBUTE)) schema.defineAttributeGroup(name, body.accept(attributeUseBuilder), location, annotation); } } addTrailingComments(c); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { addLeadingComments(c); addInitialChildComments(c); boolean saveGroupEnableAbstractElements = groupEnableAbstractElements; groupEnableAbstractElements = getGroupEnableAbstractElements(c, groupEnableAbstractElements); c.componentsAccept(this); groupEnableAbstractElements = saveGroupEnableAbstractElements; addTrailingComments(c); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { addLeadingComments(c); addInitialChildComments(c); boolean saveGroupEnableAbstractElements = groupEnableAbstractElements; groupEnableAbstractElements = getGroupEnableAbstractElements(c, groupEnableAbstractElements); c.componentsAccept(this); String uri = c.getUri(); Schema sub = schema.addInclude(uri, si.getEncoding(uri), c.getSourceLocation(), makeAnnotation(c)); GrammarPattern includedGrammar = si.getSchema(uri); new BasicBuilder(er, si, guide, sub, resolveNamespace(c.getNs()), includedGrammar, groupEnableAbstractElements).processGrammar(includedGrammar); groupEnableAbstractElements = saveGroupEnableAbstractElements; addTrailingComments(c); return VoidValue.VOID; } } private BasicBuilder(ErrorReporter er, SchemaInfo si, Guide guide, Schema schema, String inheritedNamespace, Annotated annotated, boolean groupEnableAbstractElements) { this.er = er; this.si = si; this.guide = guide; this.schema = schema; this.inheritedNamespace = inheritedNamespace; this.schemaBuilder = new SchemaBuilder(getGroupEnableAbstractElements(annotated, groupEnableAbstractElements)); } static Schema buildBasicSchema(SchemaInfo si, Guide guide, ErrorReporter er) { GrammarPattern grammar = si.getGrammar(); Schema schema = new Schema(grammar.getSourceLocation(), makeAnnotation(grammar), si.getMainUri(), si.getEncoding(si.getMainUri())); new BasicBuilder(er, si, guide, schema, "", grammar, guide.getDefaultGroupEnableAbstractElements()).processGrammar(grammar); return schema; } private void processGrammar(GrammarPattern grammar) { copyComments(grammar.getLeadingComments(), schema.getLeadingComments()); addInitialChildComments(grammar); grammar.componentsAccept(schemaBuilder); copyComments(grammar.getFollowingElementAnnotations(), schema.getTrailingComments()); } private static SimpleType makeUnionWithEmptySimpleType(SimpleType type, SourceLocation location) { List list = new Vector(); list.add(type); list.add(makeEmptySimpleType(location)); return new SimpleTypeUnion(location, null, list); } private static SimpleType makeEmptySimpleType(SourceLocation location) { List facets = new Vector(); facets.add(new Facet(location, null, "length", "0")); return new SimpleTypeRestriction(location, null, "token", facets); } private static SimpleType makeStringType(SourceLocation sourceLocation) { List facets = Collections.emptyList(); return new SimpleTypeRestriction(sourceLocation, null, "string", facets); } private Name makeName(NameNameClass nc) { return new Name(resolveNamespace(nc.getNamespaceUri()), nc.getLocalName()); } private String resolveNamespace(String ns) { return resolveNamespace(ns, inheritedNamespace); } private static String resolveNamespace(String ns, String inheritedNamespace) { if (ns == NameNameClass.INHERIT_NS) return inheritedNamespace; return ns; } private static Wildcard[] splitElementWildcard(Wildcard wc) { if (wc == null) return new Wildcard[0]; if (wc.isPositive() || wc.getNamespaces().contains("") || wc.getNamespaces().size() != 1) return new Wildcard[] { wc }; Set positiveNamespaces = new HashSet(); positiveNamespaces.add(""); Set negativeNamespaces = new HashSet(); negativeNamespaces.add(wc.getNamespaces().iterator().next()); negativeNamespaces.add(""); Set positiveExcludeNames = new HashSet(); Set negativeExcludeNames = new HashSet(); for (Name name : wc.getExcludedNames()) (name.getNamespaceUri().equals("") ? positiveExcludeNames : negativeExcludeNames).add(name); return new Wildcard[] { new Wildcard(false, negativeNamespaces, negativeExcludeNames), new Wildcard(true, positiveNamespaces, positiveExcludeNames) }; } private boolean allowsAnyString(Pattern p) { while (p instanceof RefPattern) p = si.getBody((RefPattern)p); if (p instanceof TextPattern) return true; if (!(p instanceof DataPattern)) return false; DataPattern dp = (DataPattern)p; if (dp.getParams().size() != 0) return false; String lib = dp.getDatatypeLibrary(); if (lib.equals("")) return true; if (!lib.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES)) return false; String type = dp.getType(); return type.equals("string") || type.equals("token") || type.equals("normalizedString"); } private static Annotation makeAnnotation(Annotated annotated) { List elements = (annotated.mayContainText() ? annotated.getFollowingElementAnnotations() : annotated.getChildElementAnnotations()); for (AnnotationChild child : elements) { // child might be a Comment if (child instanceof ElementAnnotation) { ElementAnnotation element = (ElementAnnotation)child; if (element.getNamespaceUri().equals(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS) && element.getLocalName().equals("documentation")) { String value = getAtomicValue(element); if (value == null) break; return new Annotation(value); } } } return null; } private static String getAtomicValue(ElementAnnotation elem) { String value = null; StringBuffer buf = null; List children = elem.getChildren(); for (int i = 0, len = children.size(); i < len; i++) { Object obj = children.get(i); if (obj instanceof TextAnnotation) { String tem = ((TextAnnotation)obj).getValue(); if (buf != null) buf.append(tem); else if (value == null) value = tem; else { buf = new StringBuffer(value); buf.append(tem); value = null; } } else if (obj instanceof ElementAnnotation) return null; } if (buf != null) return buf.toString(); if (value != null) return value; return ""; } static private final String GUIDE_NAMESPACE = "http://www.thaiopensource.com/ns/relaxng/xsd"; private static boolean getGroupEnableAbstractElements(Annotated annotated, boolean current) { String value = annotated.getAttributeAnnotation(GUIDE_NAMESPACE, "enableAbstractElements"); if (value != null) { value = value.trim(); if (value.equals("true")) current = true; else if (value.equals("false")) current = false; } return current; } private void addLeadingComments(Annotated annotated) { addComments(annotated.getLeadingComments()); } private void addInitialChildComments(Annotated annotated) { addComments(annotated.getChildElementAnnotations()); } private void addTrailingComments(Annotated annotated) { addComments(annotated.getFollowingElementAnnotations()); } private void addComments(List list) { for (AnnotationChild child : list) { if (child instanceof Comment) { Comment comment = (Comment)child; schema.addComment(comment.getValue(), comment.getSourceLocation()); } } } private static void copyComments(List fromList, List toList) { for (AnnotationChild child : fromList) { if (child instanceof Comment) { Comment comment = (Comment)child; toList.add(new com.thaiopensource.relaxng.output.xsd.basic.Comment(comment.getSourceLocation(), comment.getValue())); } } } } BasicOutput.java000066400000000000000000001110131225366607500347110ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.output.common.XmlWriter; import com.thaiopensource.relaxng.output.xsd.basic.AbstractAttributeUseVisitor; import com.thaiopensource.relaxng.output.xsd.basic.AbstractSchemaVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Annotated; import com.thaiopensource.relaxng.output.xsd.basic.Annotation; import com.thaiopensource.relaxng.output.xsd.basic.Attribute; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUseVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Comment; import com.thaiopensource.relaxng.output.xsd.basic.ComplexType; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeNotAllowedContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeSimpleContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.Facet; import com.thaiopensource.relaxng.output.xsd.basic.GroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.GroupRef; import com.thaiopensource.relaxng.output.xsd.basic.Occurs; import com.thaiopensource.relaxng.output.xsd.basic.OptionalAttribute; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll; import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice; import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat; import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence; import com.thaiopensource.relaxng.output.xsd.basic.ParticleVisitor; import com.thaiopensource.relaxng.output.xsd.basic.RootDeclaration; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SchemaVisitor; import com.thaiopensource.relaxng.output.xsd.basic.SchemaWalker; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeDefinition; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeList; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRef; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Structure; import com.thaiopensource.relaxng.output.xsd.basic.StructureVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Wildcard; import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute; import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; public class BasicOutput { static class Options { String anyProcessContents = "skip"; String anyAttributeProcessContents = "skip"; } private final XmlWriter xw; private final Schema schema; private final SimpleTypeOutput simpleTypeOutput = new SimpleTypeOutput(); private final ComplexTypeOutput complexTypeOutput = new ComplexTypeOutput(); private final AttributeUseOutput attributeUseOutput = new AttributeUseOutput(); private final AttributeUseVisitor attributeWildcardOutput = new AttributeWildcardOutput(); private final ParticleOutput particleOutput = new ParticleOutput(); private final ParticleVisitor globalElementOutput = new GlobalElementOutput(); private final GlobalAttributeOutput globalAttributeOutput = new GlobalAttributeOutput(); private final SchemaVisitor schemaOutput = new SchemaOutput(); private final StructureVisitor movedStructureOutput = new MovedStructureOutput(); private final SimpleTypeVisitor simpleTypeNamer = new SimpleTypeNamer(); private final NamespaceManager nsm; private final PrefixManager pm; private final String targetNamespace; private final OutputDirectory od; private final String sourceUri; private final ComplexTypeSelector complexTypeSelector; private final AbstractElementTypeSelector abstractElementTypeSelector; private final Set globalElementsDefined; private final Set globalAttributesDefined; private final String xsPrefix; private final Options options; class SimpleTypeOutput implements SimpleTypeVisitor { public VoidValue visitRestriction(SimpleTypeRestriction t) { boolean hadPatternFacet = false; for (Facet facet : t.getFacets()) { if (facet.getName().equals("pattern")) { if (!hadPatternFacet) hadPatternFacet = true; else { xw.startElement(xs("restriction")); xw.startElement(xs("simpleType")); } } } xw.startElement(xs("restriction")); xw.attribute("base", xs(t.getName())); hadPatternFacet = false; for (Facet facet : t.getFacets()) { if (facet.getName().equals("pattern")) { if (!hadPatternFacet) { hadPatternFacet = true; outputFacet(facet); } } else outputFacet(facet); } xw.endElement(); hadPatternFacet = false; for (Facet facet : t.getFacets()) { if (facet.getName().equals("pattern")) { if (!hadPatternFacet) hadPatternFacet = true; else { xw.endElement(); outputFacet(facet); xw.endElement(); } } } return null; } private void outputFacet(Facet facet) { xw.startElement(xs(facet.getName())); xw.attribute("value", facet.getValue()); String prefix = facet.getPrefix(); if (prefix != null && !prefix.equals(topLevelPrefix(facet.getNamespace()))) xw.attribute(prefix.equals("") ? "xmlns" : "xmlns:" + prefix, facet.getNamespace()); outputAnnotation(facet); xw.endElement(); } public VoidValue visitRef(SimpleTypeRef t) { xw.startElement(xs("restriction")); xw.attribute("base", qualifyRef(schema.getSimpleType(t.getName()).getParentSchema().getUri(), t.getName())); xw.endElement(); return null; } public VoidValue visitUnion(SimpleTypeUnion t) { xw.startElement(xs("union")); StringBuffer buf = new StringBuffer(); for (SimpleType child : t.getChildren()) { String typeName = child.accept(simpleTypeNamer); if (typeName != null) { if (buf.length() != 0) buf.append(' '); buf.append(typeName); } } if (buf.length() != 0) xw.attribute("memberTypes", buf.toString()); outputAnnotation(t); for (SimpleType child : t.getChildren()) { if (child.accept(simpleTypeNamer) == null) outputWrap(child, null); } xw.endElement(); return null; } public VoidValue visitList(SimpleTypeList t) { Occurs occ = t.getOccurs(); if (!occ.equals(Occurs.ZERO_OR_MORE)) { xw.startElement(xs("restriction")); xw.startElement(xs("simpleType")); } xw.startElement(xs("list")); outputWrap(t.getItemType(), "itemType", t); xw.endElement(); if (!occ.equals(Occurs.ZERO_OR_MORE)) { xw.endElement(); if (occ.getMin() == occ.getMax()) { xw.startElement(xs("length")); xw.attribute("value", Integer.toString(occ.getMin())); xw.endElement(); } else { if (occ.getMin() != 0) { xw.startElement(xs("minLength")); xw.attribute("value", Integer.toString(occ.getMin())); xw.endElement(); } if (occ.getMax() != Occurs.UNBOUNDED) { xw.startElement(xs("maxLength")); xw.attribute("value", Integer.toString(occ.getMax())); xw.endElement(); } } xw.endElement(); } return null; } void outputWrap(SimpleType t, Annotated parent) { outputWrap(t, "type", parent); } void outputWrap(SimpleType t, String attributeName, Annotated parent) { String typeName = t.accept(simpleTypeNamer); if (typeName != null) { xw.attribute(attributeName, typeName); if (parent != null) outputAnnotation(parent); } else { if (parent != null) outputAnnotation(parent); xw.startElement(xs("simpleType")); t.accept(this); xw.endElement(); } } } class SimpleTypeNamer implements SimpleTypeVisitor { public String visitRestriction(SimpleTypeRestriction t) { if (t.getFacets().size() > 0) return null; if (t.getAnnotation() != null) return null; return xs(t.getName()); } public String visitRef(SimpleTypeRef t) { if (t.getAnnotation() != null) return null; return qualifyRef(schema.getSimpleType(t.getName()).getParentSchema().getUri(), t.getName()); } public String visitList(SimpleTypeList t) { return null; } public String visitUnion(SimpleTypeUnion t) { return null; } } private static final int NORMAL_CONTEXT = 0; private static final int COMPLEX_TYPE_CONTEXT = 1; private static final int NAMED_GROUP_CONTEXT = 2; class ParticleOutput implements ParticleVisitor { private Occurs occ = Occurs.EXACTLY_ONE; private int context = NORMAL_CONTEXT; private boolean startWrapperForElement() { boolean needWrapper = context >= COMPLEX_TYPE_CONTEXT; context = NORMAL_CONTEXT; if (needWrapper) xw.startElement(xs("sequence")); xw.startElement(xs("element")); outputOccurAttributes(); return needWrapper; } private boolean startWrapperForAny() { boolean needWrapper = context >= COMPLEX_TYPE_CONTEXT; context = NORMAL_CONTEXT; if (needWrapper) xw.startElement(xs("sequence")); xw.startElement(xs("any")); outputOccurAttributes(); return needWrapper; } private boolean startWrapperForGroupRef() { boolean needWrapper = context == NAMED_GROUP_CONTEXT; context = NORMAL_CONTEXT; if (needWrapper) xw.startElement(xs("sequence")); xw.startElement(xs("group")); outputOccurAttributes(); return needWrapper; } private boolean startWrapperForGroup(String groupType) { boolean needWrapper = context == NAMED_GROUP_CONTEXT && !occ.equals(Occurs.EXACTLY_ONE); context = NORMAL_CONTEXT; if (needWrapper) xw.startElement(xs("sequence")); xw.startElement(xs(groupType)); outputOccurAttributes(); return needWrapper; } private void endWrapper(boolean extra) { xw.endElement(); if (extra) xw.endElement(); } public VoidValue visitElement(Element p) { boolean usedWrapper; if (nsm.isGlobal(p)) { usedWrapper = startWrapperForElement(); xw.attribute("ref", qualifyName(p.getName())); } else if (!namespaceIsLocal(p.getName().getNamespaceUri())) { usedWrapper = startWrapperForGroupRef(); xw.attribute("ref", qualifyName(p.getName().getNamespaceUri(), nsm.getProxyName(p))); } else { usedWrapper = startWrapperForElement(); xw.attribute("name", p.getName().getLocalName()); if (!p.getName().getNamespaceUri().equals(targetNamespace)) xw.attribute("form", "unqualified"); complexTypeOutput.parent = p; p.getComplexType().accept(complexTypeOutput); } endWrapper(usedWrapper); return null; } public VoidValue visitWildcardElement(WildcardElement p) { String ns = NamespaceManager.otherNamespace(p.getWildcard()); boolean usedWrapper; if (ns != null && !ns.equals(targetNamespace)) { usedWrapper = startWrapperForGroupRef(); xw.attribute("ref", qualifyName(ns, nsm.getOtherElementName(ns))); } else { usedWrapper = startWrapperForAny(); namespaceAttribute(p.getWildcard()); xw.attribute("processContents", options.anyProcessContents); outputAnnotation(p); } endWrapper(usedWrapper); return null; } public VoidValue visitRepeat(ParticleRepeat p) { occ = Occurs.multiply(occ, p.getOccurs()); p.getChild().accept(this); return null; } public VoidValue visitSequence(ParticleSequence p) { boolean usedWrapper = startWrapperForGroup("sequence"); outputAnnotation(p); outputParticles(p.getChildren()); endWrapper(usedWrapper); return null; } public VoidValue visitChoice(ParticleChoice p) { boolean usedWrapper = startWrapperForGroup("choice"); outputAnnotation(p); outputParticles(p.getChildren()); endWrapper(usedWrapper); return null; } public VoidValue visitAll(ParticleAll p) { boolean usedWrapper = startWrapperForGroup("all"); outputAnnotation(p); outputParticles(p.getChildren()); endWrapper(usedWrapper); return null; } private void outputParticles(List particles) { for (Particle particle : particles) particle.accept(this); } public VoidValue visitGroupRef(GroupRef p) { String groupName = p.getName(); GroupDefinition def = schema.getGroup(groupName); Name elementName = nsm.getElementNameForGroupRef(def); boolean usedWrapper; if (elementName != null) { usedWrapper = startWrapperForElement(); xw.attribute("ref", qualifyName(elementName)); } else { usedWrapper = startWrapperForGroupRef(); xw.attribute("ref", qualifyRef(def.getParentSchema().getUri(), groupName)); } outputAnnotation(p); endWrapper(usedWrapper); return null; } void outputOccurAttributes() { if (occ.getMin() != 1) xw.attribute("minOccurs", Integer.toString(occ.getMin())); if (occ.getMax() != 1) xw.attribute("maxOccurs", occ.getMax() == Occurs.UNBOUNDED ? "unbounded" : Integer.toString(occ.getMax())); occ = Occurs.EXACTLY_ONE; } } class ComplexTypeOutput implements ComplexTypeVisitor { Annotated parent; public VoidValue visitComplexContent(ComplexTypeComplexContent t) { outputComplexTypeComplexContent(complexTypeSelector.transformComplexContent(t), null, parent); return null; } public VoidValue visitSimpleContent(ComplexTypeSimpleContent t) { outputComplexTypeSimpleContent(complexTypeSelector.transformSimpleContent(t), null, parent); return null; } public VoidValue visitNotAllowedContent(ComplexTypeNotAllowedContent t) { xw.startElement(xs("complexType")); xw.startElement(xs("choice")); xw.endElement(); xw.endElement(); return null; } } class AttributeUseOutput extends SchemaWalker { boolean isOptional = false; String defaultValue = null; public VoidValue visitOptionalAttribute(OptionalAttribute a) { isOptional = true; defaultValue = a.getDefaultValue(); a.getAttribute().accept(this); isOptional = false; defaultValue = null; return null; } public VoidValue visitAttribute(Attribute a) { if (nsm.isGlobal(a)) { xw.startElement(xs("attribute")); xw.attribute("ref", qualifyName(a.getName())); if (!isOptional) xw.attribute("use", "required"); else if (defaultValue != null) xw.attribute("default", defaultValue); xw.endElement(); } else if (namespaceIsLocal(a.getName().getNamespaceUri())) { xw.startElement(xs("attribute")); xw.attribute("name", a.getName().getLocalName()); if (!isOptional) xw.attribute("use", "required"); else if (defaultValue != null) xw.attribute("default", defaultValue); if (!a.getName().getNamespaceUri().equals("")) xw.attribute("form", "qualified"); if (a.getType() != null) simpleTypeOutput.outputWrap(a.getType(), a); else outputAnnotation(a); xw.endElement(); } else { xw.startElement(xs("attributeGroup")); xw.attribute("ref", qualifyName(a.getName().getNamespaceUri(), nsm.getProxyName(a))); xw.endElement(); } return null; } public VoidValue visitAttributeGroupRef(AttributeGroupRef a) { xw.startElement(xs("attributeGroup")); String name = a.getName(); xw.attribute("ref", qualifyRef(schema.getAttributeGroup(name).getParentSchema().getUri(), name)); xw.endElement(); return null; } } class AttributeWildcardOutput extends SchemaWalker { public VoidValue visitWildcardAttribute(WildcardAttribute a) { String ns = NamespaceManager.otherNamespace(a.getWildcard()); if (ns != null && !ns.equals(targetNamespace)) { xw.startElement(xs("attributeGroup")); xw.attribute("ref", qualifyName(ns, nsm.getOtherAttributeName(ns))); xw.endElement(); } else { xw.startElement(xs("anyAttribute")); namespaceAttribute(a.getWildcard()); xw.attribute("processContents", options.anyAttributeProcessContents); xw.endElement(); } return null; } } class GlobalElementOutput implements ParticleVisitor, ComplexTypeVisitor { public VoidValue visitElement(Element p) { Name name = p.getName(); if (nsm.isGlobal(p) && name.getNamespaceUri().equals(targetNamespace) && !globalElementsDefined.contains(name)) { globalElementsDefined.add(name); xw.startElement(xs("element")); xw.attribute("name", name.getLocalName()); outputComplexType(name, p.getComplexType(), p); xw.endElement(); } return p.getComplexType().accept(this); } public VoidValue visitRepeat(ParticleRepeat p) { return p.getChild().accept(this); } void visitList(List list) { for (Particle p : list) p.accept(this); } public VoidValue visitSequence(ParticleSequence p) { visitList(p.getChildren()); return null; } public VoidValue visitChoice(ParticleChoice p) { visitList(p.getChildren()); return null; } public VoidValue visitAll(ParticleAll p) { visitList(p.getChildren()); return null; } public VoidValue visitGroupRef(GroupRef p) { return null; } public VoidValue visitWildcardElement(WildcardElement p) { return null; } public VoidValue visitComplexContent(ComplexTypeComplexContent t) { if (t.getParticle() == null) return null; return t.getParticle().accept(this); } public VoidValue visitSimpleContent(ComplexTypeSimpleContent t) { return null; } public VoidValue visitNotAllowedContent(ComplexTypeNotAllowedContent t) { return null; } } class GlobalAttributeOutput extends AbstractAttributeUseVisitor { public VoidValue visitAttributeGroup(AttributeGroup a) { for (AttributeUse child : a.getChildren()) child.accept(this); return null; } public VoidValue visitAttribute(Attribute a) { Name name = a.getName(); if (nsm.isGlobal(a) && name.getNamespaceUri().equals(targetNamespace) && !globalAttributesDefined.contains(name)) { globalAttributesDefined.add(name); xw.startElement(xs("attribute")); xw.attribute("name", name.getLocalName()); if (a.getType() != null) simpleTypeOutput.outputWrap(a.getType(), a); xw.endElement(); } return null; } public VoidValue visitOptionalAttribute(OptionalAttribute a) { return a.getAttribute().accept(this); } public VoidValue visitAttributeGroupRef(AttributeGroupRef a) { return null; } public VoidValue visitWildcardAttribute(WildcardAttribute a) { return null; } } class SchemaOutput extends AbstractSchemaVisitor { public void visitGroup(GroupDefinition def) { Particle particle = def.getParticle(); ComplexTypeComplexContentExtension ct = complexTypeSelector.createComplexTypeForGroup(def.getName(), nsm); if (ct != null) { Annotated anno; if (tryAbstractElement(def)) anno = null; else anno = def; outputComplexTypeComplexContent(ct, def.getName(), anno); } else if (!nsm.isGroupDefinitionOmitted(def) && !tryAbstractElement(def) && !tryElementChoiceSameType(def)) { xw.startElement(xs("group")); xw.attribute("name", def.getName()); outputAnnotation(def); particleOutput.context = NAMED_GROUP_CONTEXT; particle.accept(particleOutput); xw.endElement(); } particle.accept(globalElementOutput); } private boolean tryAbstractElement(GroupDefinition def) { Name name = nsm.getGroupDefinitionAbstractElementName(def); if (name == null) return false; xw.startElement(xs("element")); xw.attribute("name", name.getLocalName()); xw.attribute("abstract", "true"); outputComplexType(name, abstractElementTypeSelector.getAbstractElementType(name), def); xw.endElement(); return true; } private boolean tryElementChoiceSameType(GroupDefinition def) { Particle particle = def.getParticle(); if (!(particle instanceof ParticleChoice)) return false; List children = ((ParticleChoice)particle).getChildren(); if (children.size() <= 1) return false; Iterator iter = children.iterator(); Particle first = iter.next(); if (!(first instanceof Element)) return false; if (!((Element)first).getName().getNamespaceUri().equals(targetNamespace)) return false; ComplexType type = ((Element)first).getComplexType(); do { Particle tem = iter.next(); if (!(tem instanceof Element)) return false; if (!((Element)tem).getComplexType().equals(type)) return false; if (!((Element)tem).getName().getNamespaceUri().equals(targetNamespace)) return false; } while (iter.hasNext()); if (type instanceof ComplexTypeComplexContent) { ComplexTypeComplexContentExtension t = complexTypeSelector.transformComplexContent((ComplexTypeComplexContent)type); if (t.getBase() != null && t.getParticle() == null && !t.isMixed() && t.getAttributeUses().equals(AttributeGroup.EMPTY)) return false; outputComplexTypeComplexContent(t, def.getName(), null); } else { ComplexTypeSimpleContentExtension t = complexTypeSelector.transformSimpleContent((ComplexTypeSimpleContent)type); if (t.getAttributeUses().equals(AttributeGroup.EMPTY) && (t.getBase() != null || t.getSimpleType().accept(simpleTypeNamer) != null)) return false; outputComplexTypeSimpleContent(t, def.getName(), null); } xw.startElement(xs("group")); xw.attribute("name", def.getName()); outputAnnotation(def); xw.startElement(xs("choice")); for (iter = children.iterator(); iter.hasNext();) { Element element = (Element)iter.next(); xw.startElement(xs("element")); if (nsm.isGlobal(element)) xw.attribute("ref", qualifyName(element.getName())); else { xw.attribute("name", element.getName().getLocalName()); xw.attribute("type", def.getName()); outputAnnotation(element); } xw.endElement(); } xw.endElement(); xw.endElement(); for (iter = children.iterator(); iter.hasNext();) { Element element = (Element)iter.next(); if (nsm.isGlobal(element) && !globalElementsDefined.contains(element.getName())) { globalElementsDefined.add(element.getName()); xw.startElement(xs("element")); xw.attribute("name", element.getName().getLocalName()); xw.attribute("type", def.getName()); outputAnnotation(element); xw.endElement(); } } return true; } public void visitSimpleType(SimpleTypeDefinition def) { ComplexTypeSimpleContentExtension ct = complexTypeSelector.createComplexTypeForSimpleType(def.getName()); if (ct != null) outputComplexTypeSimpleContent(ct, def.getName(), def); else { xw.startElement(xs("simpleType")); xw.attribute("name", def.getName()); outputAnnotation(def); def.getSimpleType().accept(simpleTypeOutput); xw.endElement(); } } public void visitAttributeGroup(AttributeGroupDefinition def) { if (complexTypeSelector.isComplexType(def.getName())) return; xw.startElement(xs("attributeGroup")); xw.attribute("name", def.getName()); outputAnnotation(def); outputAttributeUse(def.getAttributeUses()); xw.endElement(); def.getAttributeUses().accept(globalAttributeOutput); } public void visitRoot(RootDeclaration decl) { decl.getParticle().accept(globalElementOutput); } public void visitComment(Comment comment) { xw.comment(comment.getContent()); } } class MovedStructureOutput implements StructureVisitor { public VoidValue visitElement(Element element) { if (!nsm.isGlobal(element)) { xw.startElement(xs("group")); xw.attribute("name", nsm.getProxyName(element)); particleOutput.context = NAMED_GROUP_CONTEXT; particleOutput.visitElement(element); xw.endElement(); } globalElementOutput.visitElement(element); return null; } public VoidValue visitAttribute(Attribute attribute) { if (!nsm.isGlobal(attribute)) { xw.startElement(xs("attributeGroup")); xw.attribute("name", nsm.getProxyName(attribute)); attributeUseOutput.visitAttribute(attribute); xw.endElement(); } globalAttributeOutput.visitAttribute(attribute); return null; } } static void output(Schema schema, Guide guide, PrefixManager pm, OutputDirectory od, Options options, ErrorReporter er) throws IOException { NamespaceManager nsm = new NamespaceManager(schema, guide, pm); ComplexTypeSelector cts = new ComplexTypeSelector(schema); AbstractElementTypeSelector aets = new AbstractElementTypeSelector(schema, nsm, cts); Set globalElementsDefined = new HashSet(); Set globalAttributesDefined = new HashSet(); try { for (Schema sch : schema.getSubSchemas()) new BasicOutput(sch, er, od, options, nsm, pm, cts, aets, globalElementsDefined, globalAttributesDefined).output(); } catch (XmlWriter.WrappedException e) { throw e.getIOException(); } } private BasicOutput(Schema schema, ErrorReporter er, OutputDirectory od, Options options, NamespaceManager nsm, PrefixManager pm, ComplexTypeSelector complexTypeSelector, AbstractElementTypeSelector abstractElementTypeSelector, Set globalElementsDefined, Set globalAttributesDefined) throws IOException { this.schema = schema; this.nsm = nsm; this.pm = pm; this.complexTypeSelector = complexTypeSelector; this.abstractElementTypeSelector = abstractElementTypeSelector; this.globalElementsDefined = globalElementsDefined; this.globalAttributesDefined = globalAttributesDefined; this.sourceUri = schema.getUri(); this.od = od; this.targetNamespace = nsm.getTargetNamespace(schema.getUri()); this.xsPrefix = pm.getPrefix(WellKnownNamespaces.XML_SCHEMA); this.options = options; OutputDirectory.Stream stream = od.open(schema.getUri(), schema.getEncoding()); xw = new XmlWriter(stream.getWriter(), stream.getEncoding(), stream.getCharRepertoire(), od.getLineSeparator(), od.getIndent(), new String[0]); } private String topLevelPrefix(String ns) { if (!nsm.isTargetNamespace(ns)) return null; if (ns.equals("")) return ""; return pm.getPrefix(ns); } private void output() { outputCommentList(schema.getLeadingComments()); xw.startElement(xs("schema")); xw.attribute("xmlns:" + xsPrefix, WellKnownNamespaces.XML_SCHEMA); xw.attribute("elementFormDefault", "qualified"); if (!targetNamespace.equals("")) xw.attribute("targetNamespace", targetNamespace); for (String ns : nsm.getTargetNamespaces()) { if (!ns.equals("")) { String prefix = pm.getPrefix(ns); if (!prefix.equals("xml")) xw.attribute("xmlns:" + pm.getPrefix(ns), ns); } } for (String uri : nsm.effectiveIncludes(schema.getUri())) outputInclude(uri); List targetNamespaces = new Vector(); targetNamespaces.addAll(nsm.getTargetNamespaces()); Collections.sort(targetNamespaces); for (String ns : targetNamespaces) { if (!ns.equals(targetNamespace)) outputImport(ns, nsm.getRootSchema(ns)); } schema.accept(schemaOutput); if (nsm.getRootSchema(targetNamespace).equals(sourceUri)) { for (Structure structure : nsm.getMovedStructures(targetNamespace)) structure.accept(movedStructureOutput); outputOther(); } xw.endElement(); outputCommentList(schema.getTrailingComments()); xw.close(); } private String xs(String name) { return xsPrefix + ":" + name; } private boolean namespaceIsLocal(String ns) { return ns.equals(targetNamespace) || ns.equals(""); } private void outputAttributeUse(AttributeUse use) { use.accept(attributeUseOutput); use.accept(attributeWildcardOutput); } private void namespaceAttribute(Wildcard wc) { if (wc.isPositive()) { StringBuffer buf = new StringBuffer(); List namespaces = new Vector(wc.getNamespaces()); Collections.sort(namespaces); for (String ns : namespaces) { if (buf.length() > 0) buf.append(' '); if (ns.equals("")) buf.append("##local"); else if (ns.equals(targetNamespace)) buf.append("##targetNamespace"); else buf.append(ns); } xw.attribute("namespace", buf.toString()); } else { if (targetNamespace.equals(NamespaceManager.otherNamespace(wc))) xw.attribute("namespace", "##other"); } } private String qualifyRef(String schemaUri, String localName) { return qualifyName(nsm.getTargetNamespace(schemaUri), localName); } private String qualifyName(Name name) { return qualifyName(name.getNamespaceUri(), name.getLocalName()); } private String qualifyName(String ns, String localName) { if (ns.equals("")) return localName; return pm.getPrefix(ns) + ":" + localName; } private void outputOther() { String name = nsm.getOtherElementName(targetNamespace); if (name != null) { xw.startElement(xs("group")); xw.attribute("name", name); xw.startElement(xs("sequence")); xw.startElement(xs("any")); xw.attribute("namespace", "##other"); xw.attribute("processContents", options.anyProcessContents); xw.endElement(); xw.endElement(); xw.endElement(); } name = nsm.getOtherAttributeName(targetNamespace); if (name != null) { xw.startElement(xs("attributeGroup")); xw.attribute("name", name); xw.startElement(xs("anyAttribute")); xw.attribute("namespace", "##other"); xw.attribute("processContents", options.anyAttributeProcessContents); xw.endElement(); xw.endElement(); } } private void outputInclude(String href) { xw.startElement(xs("include")); xw.attribute("schemaLocation", od.reference(sourceUri, href)); xw.endElement(); } private void outputImport(String ns, String href) { xw.startElement(xs("import")); if (!ns.equals("")) xw.attribute("namespace", ns); xw.attribute("schemaLocation", od.reference(sourceUri, href)); xw.endElement(); } private void outputComplexTypeComplexContent(ComplexTypeComplexContentExtension t, String name, Annotated parent) { String base = t.getBase(); if (base != null) { base = qualifyRef(schema.getGroup(base).getParentSchema().getUri(), base); if (name == null && t.getParticle() == null && !t.isMixed() && t.getAttributeUses().equals(AttributeGroup.EMPTY)) { xw.attribute("type", base); if (parent != null) outputAnnotation(parent); return; } } if (name == null && parent != null) outputAnnotation(parent); xw.startElement(xs("complexType")); if (name != null) xw.attribute("name", name); if (t.isMixed()) xw.attribute("mixed", "true"); if (name != null && parent != null) outputAnnotation(parent); if (base != null) { xw.startElement(xs("complexContent")); xw.startElement(xs("extension")); xw.attribute("base", base); } if (t.getParticle() != null) { particleOutput.context = COMPLEX_TYPE_CONTEXT; t.getParticle().accept(particleOutput); } outputAttributeUse(t.getAttributeUses()); if (base != null) { xw.endElement(); xw.endElement(); } xw.endElement(); } private void outputComplexTypeSimpleContent(ComplexTypeSimpleContentExtension t, String name, Annotated parent) { String base = t.getBase(); AttributeUse attributeUses = t.getAttributeUses(); if (base != null) { base = qualifyRef(schema.getSimpleType(base).getParentSchema().getUri(), base); if (name == null && attributeUses.equals(AttributeGroup.EMPTY)) { xw.attribute("type", base); if (parent != null) outputAnnotation(parent); return; } } else if (attributeUses.equals(AttributeGroup.EMPTY)) { simpleTypeOutput.outputWrap(t.getSimpleType(), parent); return; } if (name == null && parent != null) outputAnnotation(parent); xw.startElement(xs("complexType")); if (name != null) xw.attribute("name", name); if (name != null && parent != null) outputAnnotation(parent); xw.startElement(xs("simpleContent")); if (base == null) base = t.getSimpleType().accept(simpleTypeNamer); if (base != null) { xw.startElement(xs("extension")); xw.attribute("base", base); } else { xw.startElement(xs("restriction")); xw.attribute("base", xs("anyType")); simpleTypeOutput.outputWrap(t.getSimpleType(), null); } outputAttributeUse(attributeUses); xw.endElement(); xw.endElement(); xw.endElement(); } private void outputComplexType(Name elementName, ComplexType ct, Annotated parent) { Name substitutionGroup = nsm.getSubstitutionGroup(elementName); if (substitutionGroup != null) { xw.attribute("substitutionGroup", qualifyName(substitutionGroup)); if (ct != null && ct.equals(abstractElementTypeSelector.getAbstractElementType(substitutionGroup))) ct = null; } if (ct != null) { if (ct instanceof ComplexTypeNotAllowedContent) { xw.attribute("abstract", "true"); outputAnnotation(parent); } else { complexTypeOutput.parent = parent; ct.accept(complexTypeOutput); } } else outputAnnotation(parent); } private void outputAnnotation(Annotated annotated) { Annotation annotation = annotated.getAnnotation(); if (annotation == null) return; xw.startElement(xs("annotation")); String documentation = annotation.getDocumentation(); if (documentation != null) { xw.startElement(xs("documentation")); xw.text(documentation); xw.endElement(); } xw.endElement(); } private void outputCommentList(List list) { for (Comment comment : list) xw.comment((comment).getContent()); } } BuiltinSimpleTypeHierarchy.java000066400000000000000000000017741225366607500377440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; class BuiltinSimpleTypeHierarchy { private BuiltinSimpleTypeHierarchy() { } static private final String[] parentType = { "normalizedString", "string", "token", "normalizedString", "language", "token", "Name", "token", "NMTOKEN", "token", "NCName", "Name", "ID", "NCName", "IDREF", "NCName", "ENTITY", "NCName", "integer", "decimal", "nonPositiveInteger", "integer", "long", "integer", "nonNegativeInteger", "integer", "negativeInteger", "nonPositiveInteger", "positiveInteger", "nonNegativeInteger", "int", "long", "unsignedLong", "nonNegativeInteger", "short", "int", "byte", "short", "unsignedInt", "unsignedLong", "unsignedShort", "unsignedInt", "unsignedByte", "unsignedShort" }; static String getParentType(String type) { for (int i = 0; i < parentType.length; i += 2) if (type.equals(parentType[i])) return parentType[i + 1]; return null; } } ChildType.java000066400000000000000000000025521225366607500343430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; class ChildType { static private final int ALLOW_EMPTY = 01; static private final int ALLOW_ELEMENT = 02; static private final int ALLOW_ATTRIBUTE = 04; static private final int ALLOW_DATA = 010; static private final int ALLOW_TEXT = 020; private final int flags; static final ChildType NOT_ALLOWED = new ChildType(0); static final ChildType EMPTY = new ChildType(ALLOW_EMPTY); static final ChildType ELEMENT = new ChildType(ALLOW_ELEMENT); static final ChildType ATTRIBUTE = new ChildType(ALLOW_ATTRIBUTE); static final ChildType DATA = new ChildType(ALLOW_DATA); static final ChildType TEXT = new ChildType(ALLOW_TEXT); private ChildType(int flags) { this.flags = flags; } public boolean equals(Object obj) { return obj instanceof ChildType && ((ChildType)obj).flags == this.flags; } public int hashCode() { return flags; } static ChildType choice(ChildType ct1, ChildType ct2) { return new ChildType(ct1.flags | ct2.flags); } static ChildType group(ChildType ct1, ChildType ct2) { if (ct1.flags == 0 || ct2.flags == 0) return NOT_ALLOWED; return new ChildType(((ct1.flags | ct2.flags) & ~ALLOW_EMPTY) | (ct1.flags & ct2.flags & ALLOW_EMPTY)); } boolean contains(ChildType ct) { return (flags & ct.flags) == ct.flags; } } ComplexTypeComplexContentExtension.java000066400000000000000000000013561225366607500415100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.Particle; class ComplexTypeComplexContentExtension extends ComplexTypeComplexContent { private final String base; ComplexTypeComplexContentExtension(AttributeUse attributeUses, Particle particle, boolean mixed, String base) { super(attributeUses, particle, mixed); this.base = base; } ComplexTypeComplexContentExtension(ComplexTypeComplexContent ct) { super(ct.getAttributeUses(), ct.getParticle(), ct.isMixed()); this.base = null; } String getBase() { return base; } } ComplexTypeSelector.java000066400000000000000000000312471225366607500364330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.xsd.basic.Attribute; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeSimpleContent; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.GroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.GroupRef; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll; import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice; import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat; import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence; import com.thaiopensource.relaxng.output.xsd.basic.ParticleVisitor; import com.thaiopensource.relaxng.output.xsd.basic.RootDeclaration; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SchemaTransformer; import com.thaiopensource.relaxng.output.xsd.basic.SchemaWalker; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeDefinition; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeList; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRef; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion; import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement; import com.thaiopensource.util.VoidValue; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; class ComplexTypeSelector extends SchemaWalker { static class Refs { final Set referencingElements = new HashSet(); final Set referencingDefinitions = new HashSet(); boolean nonTypeReference = false; boolean desirable = false; } static class NamedComplexType { private final boolean mixed; NamedComplexType(boolean mixed) { this.mixed = mixed; } } private final Map groupMap = new HashMap(); private final Map attributeGroupMap = new HashMap(); private final Map simpleTypeMap = new HashMap(); private String parentDefinition; private Element parentElement; private int nonTypeReference = 0; private int undesirable = 0; private final Map complexTypeMap = new HashMap(); private final Schema schema; private final Transformer transformer; private final ParticleVisitor baseFinder = new BaseFinder(); class Transformer extends SchemaTransformer { Transformer(Schema schema) { super(schema); } public AttributeUse visitAttributeGroupRef(AttributeGroupRef a) { if (complexTypeMap.get(a.getName()) != null) return AttributeGroup.EMPTY; return a; } public Particle visitGroupRef(GroupRef p) { if (complexTypeMap.get(p.getName()) != null) return null; return p; } public Particle visitElement(Element p) { return p; } public AttributeUse visitAttribute(Attribute a) { return a; } } class BaseFinder implements ParticleVisitor { public String visitGroupRef(GroupRef p) { if (complexTypeMap.get(p.getName()) != null) return p.getName(); return null; } public String visitSequence(ParticleSequence p) { return p.getChildren().get(0).accept(this); } public String visitElement(Element p) { return null; } public String visitWildcardElement(WildcardElement p) { return null; } public String visitRepeat(ParticleRepeat p) { return null; } public String visitChoice(ParticleChoice p) { return null; } public String visitAll(ParticleAll p) { return null; } } ComplexTypeSelector(Schema schema) { this.schema = schema; transformer = new Transformer(schema); schema.accept(this); chooseComplexTypes(groupMap); chooseComplexTypes(simpleTypeMap); } public void visitGroup(GroupDefinition def) { parentDefinition = def.getName(); def.getParticle().accept(this); parentDefinition = null; } public void visitSimpleType(SimpleTypeDefinition def) { parentDefinition = def.getName(); def.getSimpleType().accept(this); parentDefinition = null; } public void visitAttributeGroup(AttributeGroupDefinition def) { parentDefinition = def.getName(); def.getAttributeUses().accept(this); parentDefinition = null; } public void visitRoot(RootDeclaration decl) { undesirable++; decl.getParticle().accept(this); undesirable--; } public VoidValue visitElement(Element p) { Element oldParentElement = parentElement; int oldNonTypeReference = nonTypeReference; int oldExtensionReference = undesirable; parentElement = p; nonTypeReference = 0; undesirable = 0; p.getComplexType().accept(this); undesirable = oldExtensionReference; nonTypeReference = oldNonTypeReference; parentElement = oldParentElement; return VoidValue.VOID; } public VoidValue visitSequence(ParticleSequence p) { Iterator iter = p.getChildren().iterator(); undesirable++; (iter.next()).accept(this); undesirable--; nonTypeReference++; while (iter.hasNext()) (iter.next()).accept(this); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitChoice(ParticleChoice p) { nonTypeReference++; super.visitChoice(p); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitAll(ParticleAll p) { nonTypeReference++; super.visitAll(p); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitRepeat(ParticleRepeat p) { nonTypeReference++; super.visitRepeat(p); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitAttribute(Attribute a) { nonTypeReference++; SimpleType t = a.getType(); if (t != null) t.accept(this); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitComplexContent(ComplexTypeComplexContent t) { super.visitComplexContent(t); return VoidValue.VOID; } public VoidValue visitSimpleContent(ComplexTypeSimpleContent t) { super.visitSimpleContent(t); return VoidValue.VOID; } public VoidValue visitUnion(SimpleTypeUnion t) { nonTypeReference++; super.visitUnion(t); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitList(SimpleTypeList t) { nonTypeReference++; super.visitList(t); nonTypeReference--; return VoidValue.VOID; } public VoidValue visitGroupRef(GroupRef p) { noteRef(groupMap, p.getName()); return VoidValue.VOID; } public VoidValue visitAttributeGroupRef(AttributeGroupRef a) { noteRef(attributeGroupMap, a.getName()); return VoidValue.VOID; } public VoidValue visitRef(SimpleTypeRef t) { // Don't make it a complex type unless there are attributes undesirable++; noteRef(simpleTypeMap, t.getName()); undesirable--; return VoidValue.VOID; } private void noteRef(Map map, String name) { Refs refs = lookupRefs(map, name); if (nonTypeReference > 0) refs.nonTypeReference = true; else if (parentElement != null) refs.referencingElements.add(parentElement); else if (parentDefinition != null) refs.referencingDefinitions.add(parentDefinition); if (undesirable == 0) refs.desirable = true; } static private Refs lookupRefs(Map map, String name) { Refs refs = map.get(name); if (refs == null) { refs = new Refs(); map.put(name, refs); } return refs; } private void chooseComplexTypes(Map definitionMap) { for (;;) { boolean foundOne = false; for (Map.Entry entry : definitionMap.entrySet()) { String name = entry.getKey(); if (createComplexType(name, entry.getValue(), attributeGroupMap.get(name))) foundOne = true; } if (!foundOne) break; } } private boolean createComplexType(String name, Refs childRefs, Refs attributeGroupRefs) { if (complexTypeMap.get(name) != null) return false; if (childRefs.nonTypeReference) return false; if (attributeGroupRefs == null) { if (!childRefs.desirable) return false; } else if (!attributeGroupRefs.referencingDefinitions.equals(childRefs.referencingDefinitions) || !attributeGroupRefs.referencingElements.equals(childRefs.referencingElements)) return false; boolean mixed = false; boolean hadReference = false; for (Element elem : childRefs.referencingElements) { boolean m = elem.getComplexType().isMixed(); if (m != mixed) { if (hadReference) return false; mixed = m; } hadReference = true; } for (String def : childRefs.referencingDefinitions) { NamedComplexType ct = complexTypeMap.get(def); if (ct == null) return false; if (ct.mixed != mixed) { if (hadReference) return false; mixed = ct.mixed; } hadReference = true; } complexTypeMap.put(name, new NamedComplexType(mixed)); return true; } private Particle transformParticle(Particle particle) { if (particle == null) return particle; return particle.accept(transformer); } private AttributeUse transformAttributeUses(AttributeUse atts) { return atts.accept(transformer); } String particleBase(Particle particle) { if (particle == null) return null; return particle.accept(baseFinder); } ComplexTypeComplexContentExtension transformComplexContent(ComplexTypeComplexContent ct) { String base = particleBase(ct.getParticle()); if (base != null) { Particle particle = transformParticle(ct.getParticle()); return new ComplexTypeComplexContentExtension(transformAttributeUses(ct.getAttributeUses()), particle, particle != null && ct.isMixed(), base); } return new ComplexTypeComplexContentExtension(ct); } ComplexTypeSimpleContentExtension transformSimpleContent(ComplexTypeSimpleContent ct) { SimpleType st = ct.getSimpleType(); if (st instanceof SimpleTypeRef) { String name = ((SimpleTypeRef)st).getName(); NamedComplexType nct = complexTypeMap.get(name); if (nct != null) return new ComplexTypeSimpleContentExtension(transformAttributeUses(ct.getAttributeUses()), null, name); } return new ComplexTypeSimpleContentExtension(ct); } ComplexTypeComplexContentExtension createComplexTypeForGroup(String name, NamespaceManager nsm) { NamedComplexType ct = complexTypeMap.get(name); if (ct == null) return null; AttributeGroupDefinition attDef = schema.getAttributeGroup(name); AttributeUse att = attDef == null ? AttributeGroup.EMPTY : attDef.getAttributeUses(); GroupDefinition def = schema.getGroup(name); if (nsm.getGroupDefinitionAbstractElementName(def) != null) return new ComplexTypeComplexContentExtension(att, new GroupRef(def.getParticle().getLocation(), null, name), ct.mixed, null); return transformComplexContent(new ComplexTypeComplexContent(att, def.getParticle(), ct.mixed)); } ComplexTypeSimpleContentExtension createComplexTypeForSimpleType(String name) { NamedComplexType ct = complexTypeMap.get(name); if (ct == null) return null; AttributeGroupDefinition attDef = schema.getAttributeGroup(name); AttributeUse att = attDef == null ? AttributeGroup.EMPTY : attDef.getAttributeUses(); return transformSimpleContent(new ComplexTypeSimpleContent(att, schema.getSimpleType(name).getSimpleType())); } boolean isComplexType(String name) { return complexTypeMap.get(name) != null; } } ComplexTypeSimpleContentExtension.java000066400000000000000000000013161225366607500413260ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeSimpleContent; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; class ComplexTypeSimpleContentExtension extends ComplexTypeSimpleContent { private final String base; ComplexTypeSimpleContentExtension(AttributeUse attributeUses, SimpleType simpleType, String base) { super(attributeUses, simpleType); this.base = base; } ComplexTypeSimpleContentExtension(ComplexTypeSimpleContent ct) { super(ct.getAttributeUses(), ct.getSimpleType()); this.base = null; } String getBase() { return base; } } Guide.java000066400000000000000000000020061225366607500335050ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import java.util.Set; import java.util.HashSet; class Guide { private boolean defaultGroupEnableAbstractElements; private final Set nonDefaultGroupSet = new HashSet(); Guide(boolean defaultGroupEnableAbstractElements) { this.defaultGroupEnableAbstractElements = defaultGroupEnableAbstractElements; } void setDefaultGroupEnableAbstractElements(boolean defaultGroupEnableAbstractElements) { this.defaultGroupEnableAbstractElements = defaultGroupEnableAbstractElements; } void setGroupEnableAbstractElement(String name, boolean enable) { if (enable != defaultGroupEnableAbstractElements) nonDefaultGroupSet.add(name); } boolean getGroupEnableAbstractElement(String name) { return nonDefaultGroupSet.contains(name) ? !defaultGroupEnableAbstractElements : defaultGroupEnableAbstractElements; } boolean getDefaultGroupEnableAbstractElements() { return defaultGroupEnableAbstractElements; } } NamespaceManager.java000066400000000000000000000551221225366607500356460ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.xsd.basic.Attribute; import com.thaiopensource.relaxng.output.xsd.basic.Definition; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.GroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.GroupRef; import com.thaiopensource.relaxng.output.xsd.basic.Include; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SchemaWalker; import com.thaiopensource.relaxng.output.xsd.basic.Structure; import com.thaiopensource.relaxng.output.xsd.basic.Wildcard; import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute; import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; public class NamespaceManager { private final Schema schema; private final Map elementNameMap = new HashMap(); private final Map attributeNameMap = new HashMap(); private final Map substitutionGroupMap = new HashMap(); private final Map groupDefinitionAbstractElementMap = new HashMap(); private final Map> abstractElementSubstitutionGroupMemberMap = new HashMap>(); static class SourceUri { String targetNamespace; // list of strings giving included URIs final List includes = new Vector(); } static class TargetNamespace { String rootSchema; final List movedStructures = new Vector(); final Set movedStructureSet = new HashSet(); final Map movedStructureNameMap = new HashMap(); final Set movedElementNameSet = new HashSet(); final Set movedAttributeNameSet = new HashSet(); boolean movedOtherElement = false; boolean movedOtherAttribute = false; String otherElementName; String otherAttributeName; } static class NameInfo { static final int OCCUR_NONE = 0; static final int OCCUR_NESTED = 1; static final int OCCUR_TOP = 2; static final int OCCUR_MOVE = 3; static final int OCCUR_ROOT = 4; int occur = OCCUR_NONE; Structure globalType = null; } // Maps sourceUri to SourceUri private final Map sourceUriMap = new HashMap(); // Maps targetNamespace to TargetNamespace private final Map targetNamespaceMap = new HashMap(); class IncludeFinder extends SchemaWalker { private final SourceUri source; IncludeFinder(Schema schema) { source = lookupSourceUri(schema.getUri()); schema.accept(this); } public void visitInclude(Include include) { Schema included = include.getIncludedSchema(); source.includes.add(included.getUri()); new IncludeFinder(included); } } class RootMarker extends SchemaWalker { public void visitGroup(GroupDefinition def) { } public VoidValue visitElement(Element p) { NameInfo info = lookupElementName(p.getName()); info.globalType = p; info.occur = NameInfo.OCCUR_ROOT; lookupTargetNamespace(p.getName().getNamespaceUri()); return VoidValue.VOID; } } static class NamespaceUsage { int elementCount; int attributeCount; static boolean isBetter(NamespaceUsage n1, NamespaceUsage n2) { return (n1.elementCount > n2.elementCount || (n1.elementCount == n2.elementCount && n1.attributeCount > n2.attributeCount)); } public boolean equals(Object obj) { if (!(obj instanceof NamespaceUsage)) return false; NamespaceUsage other = (NamespaceUsage)obj; return (elementCount == other.elementCount && attributeCount == other.attributeCount); } } class TargetNamespaceSelector extends SchemaWalker { private boolean nested; private final Map namespaceUsageMap = new HashMap(); TargetNamespaceSelector(Schema schema) { schema.accept(this); lookupSourceUri(schema.getUri()).targetNamespace = selectTargetNamespace(); } public VoidValue visitElement(Element element) { NamespaceUsage usage = getUsage(element.getName().getNamespaceUri()); if (!nested) usage.elementCount++; boolean saveNested = nested; nested = true; element.getComplexType().accept(this); nested = saveNested; return VoidValue.VOID; } public VoidValue visitAttribute(Attribute a) { NamespaceUsage usage = getUsage(a.getName().getNamespaceUri()); if (!nested) usage.attributeCount++; return VoidValue.VOID; } public VoidValue visitWildcardElement(WildcardElement p) { return visitWildcard(p.getWildcard()); } public VoidValue visitWildcardAttribute(WildcardAttribute a) { return visitWildcard(a.getWildcard()); } private VoidValue visitWildcard(Wildcard wc) { String ns = otherNamespace(wc); if (ns != null) { lookupTargetNamespace(ns); if (!nested) getUsage(ns).attributeCount++; } return VoidValue.VOID; } private NamespaceUsage getUsage(String ns) { NamespaceUsage usage = namespaceUsageMap.get(ns); if (usage == null) { usage = new NamespaceUsage(); namespaceUsageMap.put(ns, usage); if (!ns.equals("")) lookupTargetNamespace(ns); } return usage; } public void visitInclude(Include include) { new TargetNamespaceSelector(include.getIncludedSchema()); } String selectTargetNamespace() { Map.Entry best = null; for (Map.Entry tem : namespaceUsageMap.entrySet()) { if (best == null || NamespaceUsage.isBetter(tem.getValue(), best.getValue()) // avoid output depending on order of hash table iteration || (tem.getValue().equals(best.getValue()) && (tem.getKey()).compareTo(best.getKey()) < 0)) best = tem; } namespaceUsageMap.clear(); if (best == null) return null; String targetNamespace = best.getKey(); // for "" case lookupTargetNamespace(targetNamespace); return targetNamespace; } } class GlobalElementSelector extends SchemaWalker { private final boolean absentTargetNamespace; private boolean nested = false; GlobalElementSelector(Schema schema) { absentTargetNamespace = getTargetNamespace(schema.getUri()).equals(""); schema.accept(this); } public VoidValue visitElement(Element element) { Name name = element.getName(); if (!name.getNamespaceUri().equals("") || absentTargetNamespace) { NameInfo info = lookupElementName(name); int occur = nested ? NameInfo.OCCUR_NESTED : NameInfo.OCCUR_TOP; if (occur > info.occur) { info.occur = occur; info.globalType = element; } else if (occur == info.occur && !element.equals(info.globalType)) info.globalType = null; } boolean saveNested = nested; nested = true; element.getComplexType().accept(this); nested = saveNested; return VoidValue.VOID; } public void visitInclude(Include include) { new GlobalElementSelector(include.getIncludedSchema()); } } class StructureMover extends SchemaWalker { private final String currentNamespace; StructureMover(String currentNamespace) { this.currentNamespace = currentNamespace; } public VoidValue visitElement(Element p) { NameInfo info = lookupElementName(p.getName()); String ns = p.getName().getNamespaceUri(); if (ns.equals(currentNamespace) || (ns.equals("") && !p.equals(info.globalType))) p.getComplexType().accept(this); else { noteMoved(info, p); moveStructure(p); p.getComplexType().accept(new StructureMover(ns)); } return VoidValue.VOID; } public VoidValue visitAttribute(Attribute a) { String ns = a.getName().getNamespaceUri(); if (!ns.equals("") && !ns.equals(currentNamespace)) { noteMoved(lookupAttributeName(a.getName()), a); moveStructure(a); } return VoidValue.VOID; } private void noteMoved(NameInfo info, Structure s) { if (info.occur < NameInfo.OCCUR_MOVE) { info.occur = NameInfo.OCCUR_MOVE; info.globalType = s; } else if (info.occur == NameInfo.OCCUR_MOVE && !s.equals(info.globalType)) info.globalType = null; } private void moveStructure(Structure p) { TargetNamespace tn = lookupTargetNamespace(p.getName().getNamespaceUri()); if (!tn.movedStructureSet.contains(p)) { tn.movedStructureSet.add(p); tn.movedStructures.add(p); } } public void visitInclude(Include include) { Schema included = include.getIncludedSchema(); included.accept(new StructureMover(getTargetNamespace(included.getUri()))); } public VoidValue visitWildcardElement(WildcardElement p) { return visitWildcard(p.getWildcard(), true); } public VoidValue visitWildcardAttribute(WildcardAttribute a) { return visitWildcard(a.getWildcard(), false); } private VoidValue visitWildcard(Wildcard wc, boolean isElement) { String ns = otherNamespace(wc); if (ns != null && !ns.equals(currentNamespace)) { TargetNamespace tn = lookupTargetNamespace(ns); if (isElement) tn.movedOtherElement = true; else tn.movedOtherAttribute = true; } return VoidValue.VOID; } } NamespaceManager(Schema schema, Guide guide, SourceUriGenerator sug) { this.schema = schema; new IncludeFinder(schema); schema.accept(new RootMarker()); assignTargetNamespaces(); new GlobalElementSelector(schema); findSubstitutionGroups(guide); chooseRootSchemas(sug); schema.accept(new StructureMover(getTargetNamespace(schema.getUri()))); } private void assignTargetNamespaces() { new TargetNamespaceSelector(schema); // TODO maybe use info from to select which targetNamespace of included schemas to use String ns = filterUpTargetNamespace(schema.getUri()); if (ns == null) { lookupTargetNamespace(""); lookupSourceUri(schema.getUri()).targetNamespace = ""; ns = ""; } inheritDownTargetNamespace(schema.getUri(), ns); } private String filterUpTargetNamespace(String sourceUri) { String ns = getTargetNamespace(sourceUri); if (ns != null) return ns; List includes = lookupSourceUri(sourceUri).includes; if (includes.size() == 0) return null; Map occurMap = new HashMap(); for (String include : includes) { String tem = filterUpTargetNamespace(include); if (tem != null) { Integer count = occurMap.get(tem); occurMap.put(tem, count == null ? 1 : count + 1); } } Map.Entry best = null; boolean bestAmbig = false; for (Map.Entry tem : occurMap.entrySet()) { if (best == null || tem.getValue() > best.getValue()) { best = tem; bestAmbig = false; } else if ((tem.getValue()).intValue() == (best.getValue()).intValue()) bestAmbig = true; } if (best == null || bestAmbig) return null; ns = best.getKey(); lookupSourceUri(sourceUri).targetNamespace = ns; return ns; } private void inheritDownTargetNamespace(String sourceUri, String targetNamespace) { for (String uri : lookupSourceUri(sourceUri).includes) { String ns = lookupSourceUri(uri).targetNamespace; if (ns == null) { ns = targetNamespace; lookupSourceUri(uri).targetNamespace = ns; } inheritDownTargetNamespace(uri, ns); } } private void chooseRootSchemas(SourceUriGenerator sug) { for (Map.Entry entry : targetNamespaceMap.entrySet()) { String ns = entry.getKey(); List list = new Vector(); findRootSchemas(schema.getUri(), ns, list); if (list.size() == 1) (entry.getValue()).rootSchema = list.get(0); else { String sourceUri = sug.generateSourceUri(ns); lookupSourceUri(sourceUri).includes.addAll(list); lookupSourceUri(sourceUri).targetNamespace = ns; (entry.getValue()).rootSchema = sourceUri; schema.addInclude(sourceUri, schema.getEncoding(), null, null); } } } boolean isGlobal(Element element) { return element.equals(lookupElementName(element.getName()).globalType); } Element getGlobalElement(Name name) { NameInfo info = elementNameMap.get(name); if (info == null) return null; return (Element)info.globalType; } boolean isGlobal(Attribute attribute) { return attribute.equals(lookupAttributeName(attribute.getName()).globalType); } String getProxyName(Structure struct) { String ns = struct.getName().getNamespaceUri(); TargetNamespace tn = lookupTargetNamespace(ns); String name = tn.movedStructureNameMap.get(struct); if (name == null) { name = generateName(ns, tn, struct.getName().getLocalName(), struct instanceof Element); tn.movedStructureNameMap.put(struct, name); } return name; } String getOtherElementName(String ns) { TargetNamespace tn = lookupTargetNamespace(ns); if (!tn.movedOtherElement) return null; if (tn.otherElementName == null) tn.otherElementName = generateName(ns, tn, "local", true); return tn.otherElementName; } String getOtherAttributeName(String ns) { TargetNamespace tn = lookupTargetNamespace(ns); if (!tn.movedOtherAttribute) return null; if (tn.otherAttributeName == null) tn.otherAttributeName = generateName(ns, tn, "local", false); return tn.otherAttributeName; } private String generateName(String ns, TargetNamespace tn, String base, boolean isElement) { Set movedStructureNameSet = isElement ? tn.movedElementNameSet : tn.movedAttributeNameSet; String name = base; for (int n = 1;; n++) { if (!movedStructureNameSet.contains(name)) { Definition def; if (isElement) def = schema.getGroup(name); else def = schema.getAttributeGroup(name); if (def == null || !getTargetNamespace(def.getParentSchema().getUri()).equals(ns) || (def instanceof GroupDefinition && getElementNameForGroupRef((GroupDefinition)def) != null)) break; } name = base + Integer.toString(n); } movedStructureNameSet.add(name); return name; } static class GroupDefinitionFinder extends SchemaWalker { final List list = new Vector(); public void visitGroup(GroupDefinition def) { list.add(def); } static List findGroupDefinitions(Schema schema) { GroupDefinitionFinder gdf = new GroupDefinitionFinder(); schema.accept(gdf); return gdf.list; } } private void findSubstitutionGroups(Guide guide) { List groups = GroupDefinitionFinder.findGroupDefinitions(schema); Map elementNameToGroupName = new HashMap(); while (addAbstractElements(guide, groups, elementNameToGroupName)) ; cleanSubstitutionGroupMap(elementNameToGroupName); cleanAbstractElementSubstitutionGroupMemberMap(elementNameToGroupName); } private boolean addAbstractElements(Guide guide, List groups, Map elementNameToGroupName) { Set newAbstractElements = new HashSet(); for (GroupDefinition def : groups) { if (guide.getGroupEnableAbstractElement(def.getName()) && getGroupDefinitionAbstractElementName(def) == null) { Name elementName = abstractElementName(def); if (elementName != null) { List members = substitutionGroupMembers(def); if (members != null) { elementNameToGroupName.put(elementName, def.getName()); addSubstitutionGroup(elementName, members, newAbstractElements); } } } } if (newAbstractElements.size() == 0) return false; for (Name name : newAbstractElements) { groupDefinitionAbstractElementMap.put(elementNameToGroupName.get(name), name); } return true; } private void addSubstitutionGroup(Name elementName, List members, Set newAbstractElements) { for (Name member : members) { Name old = getSubstitutionGroup(member); if (old != null && !old.equals(elementName)) { newAbstractElements.remove(old); return; } substitutionGroupMap.put(member, elementName); } newAbstractElements.add(elementName); abstractElementSubstitutionGroupMemberMap.put(elementName, members); } private void cleanSubstitutionGroupMap(Map elementNameToGroupName) { for (Iterator> iter = substitutionGroupMap.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = iter.next(); Name head = entry.getValue(); if (groupDefinitionAbstractElementMap.get(elementNameToGroupName.get(head)) == null) iter.remove(); } } private void cleanAbstractElementSubstitutionGroupMemberMap(Map elementNameToGroupName) { for (Iterator iter = abstractElementSubstitutionGroupMemberMap.keySet().iterator(); iter.hasNext();) { if (groupDefinitionAbstractElementMap.get(elementNameToGroupName.get(iter.next())) == null) iter.remove(); } } private Name abstractElementName(GroupDefinition def) { Name name = new Name(getTargetNamespace(def.getParentSchema().getUri()), def.getName()); if (lookupElementName(name).globalType != null) return null; return name; } private List substitutionGroupMembers(GroupDefinition def) { if (def.getParticle() instanceof Element) return null; List members = new Vector(); if (!particleMembers(def.getParticle(), members)) return null; return members; } private boolean particleMembers(Particle child, List members) { if (child instanceof Element) { Element e = (Element)child; if (!isGlobal(e)) return false; members.add(e.getName()); } else if (child instanceof GroupRef) { Name name = getElementNameForGroupRef(schema.getGroup(((GroupRef)child).getName())); if (name == null) return false; members.add(name); } else if (child instanceof ParticleChoice) { for (Particle particle : ((ParticleChoice)child).getChildren()) { if (!particleMembers(particle, members)) return false; } } else return false; return true; } Name getElementNameForGroupRef(GroupDefinition def) { Name abstractElementName = getGroupDefinitionAbstractElementName(def); if (abstractElementName != null) return abstractElementName; return getGroupDefinitionSingleElementName(def); } boolean isGroupDefinitionOmitted(GroupDefinition def) { return getGroupDefinitionSingleElementName(def) != null; } Name getGroupDefinitionAbstractElementName(GroupDefinition def) { return groupDefinitionAbstractElementMap.get(def.getName()); } List getAbstractElementSubstitutionGroupMembers(Name name) { return abstractElementSubstitutionGroupMemberMap.get(name); } private Name getGroupDefinitionSingleElementName(GroupDefinition def) { Particle particle = def.getParticle(); if (!(particle instanceof Element) || !isGlobal((Element)particle)) return null; return ((Element)particle).getName(); } Name getSubstitutionGroup(Name name) { return substitutionGroupMap.get(name); } String getTargetNamespace(String schemaUri) { return lookupSourceUri(schemaUri).targetNamespace; } boolean isTargetNamespace(String ns) { return targetNamespaceMap.get(ns) != null; } Set getTargetNamespaces() { return targetNamespaceMap.keySet(); } String getRootSchema(String targetNamespace) { return lookupTargetNamespace(targetNamespace).rootSchema; } List getMovedStructures(String namespace) { return lookupTargetNamespace(namespace).movedStructures; } List effectiveIncludes(String sourceUri) { String ns = getTargetNamespace(sourceUri); List list = new Vector(); for (String uri : lookupSourceUri(sourceUri).includes) findRootSchemas(uri, ns, list); return list; } private void findRootSchemas(String sourceUri, String ns, List list) { if (getTargetNamespace(sourceUri).equals(ns)) list.add(sourceUri); else { for (String uri : lookupSourceUri(sourceUri).includes) findRootSchemas(uri, ns, list); } } private SourceUri lookupSourceUri(String uri) { SourceUri s = sourceUriMap.get(uri); if (s == null) { s = new SourceUri(); sourceUriMap.put(uri, s); } return s; } private TargetNamespace lookupTargetNamespace(String ns) { TargetNamespace t = targetNamespaceMap.get(ns); if (t == null) { t = new TargetNamespace(); targetNamespaceMap.put(ns, t); } return t; } private NameInfo lookupElementName(Name name) { NameInfo info = elementNameMap.get(name); if (info == null) { info = new NameInfo(); elementNameMap.put(name, info); } return info; } private NameInfo lookupAttributeName(Name name) { NameInfo info = attributeNameMap.get(name); if (info == null) { info = new NameInfo(); attributeNameMap.put(name, info); } return info; } static String otherNamespace(Wildcard wc) { if (wc.isPositive()) return null; Set namespaces = wc.getNamespaces(); switch (namespaces.size()) { case 2: if (!namespaces.contains("")) return null; Iterator iter = namespaces.iterator(); String ns = iter.next(); if (!ns.equals("")) return ns; return iter.next(); case 1: if (namespaces.contains("")) return ""; } return null; } } PrefixManager.java000066400000000000000000000177501225366607500352140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AbstractVisitor; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.NamespaceContext; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Naming; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class PrefixManager implements SourceUriGenerator { private final Map prefixMap = new HashMap(); private final Set usedPrefixes = new HashSet(); /** * Set of prefixes that cannot be used for schema namespace. */ private final Set reservedPrefixes = new HashSet(); private int nextGenIndex = 1; static private final String[] xsdPrefixes = { "xs", "xsd" }; static private final int MAX_PREFIX_LENGTH = 10; static class PrefixUsage { int count; } class PrefixSelector extends AbstractVisitor { private final SchemaInfo si; private String inheritedNamespace; private final Map> namespacePrefixUsageMap = new HashMap>(); PrefixSelector(SchemaInfo si) { this.si = si; this.inheritedNamespace = ""; si.getGrammar().componentsAccept(this); NamespaceContext context = si.getGrammar().getContext(); if (context != null) { for (String prefix : context.getPrefixes()) { if (!prefix.equals("")) notePrefix(prefix, resolveNamespace(context.getNamespace(prefix))); } } } public VoidValue visitElement(ElementPattern p) { p.getNameClass().accept(this); p.getChild().accept(this); return VoidValue.VOID; } public VoidValue visitAttribute(AttributePattern p) { return p.getNameClass().accept(this); } public VoidValue visitChoice(ChoiceNameClass nc) { nc.childrenAccept(this); return VoidValue.VOID; } public VoidValue visitName(NameNameClass nc) { notePrefix(nc.getPrefix(), resolveNamespace(nc.getNamespaceUri())); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { for (Map.Entry entry : p.getPrefixMap().entrySet()) { String prefix = entry.getKey(); if (prefix != null && !prefix.equals("")) { String ns = resolveNamespace(entry.getValue()); notePrefix(prefix, ns); if (!ns.equals(WellKnownNamespaces.XML_SCHEMA)) reservedPrefixes.add(prefix); } } return VoidValue.VOID; } private String resolveNamespace(String ns) { return ns == NameNameClass.INHERIT_NS ? inheritedNamespace : ns; } private void notePrefix(String prefix, String ns) { if (prefix == null || ns == null || ns.equals("")) return; Map prefixUsageMap = namespacePrefixUsageMap.get(ns); if (prefixUsageMap == null) { prefixUsageMap = new HashMap(); namespacePrefixUsageMap.put(ns, prefixUsageMap); } PrefixUsage prefixUsage = prefixUsageMap.get(prefix); if (prefixUsage == null) { prefixUsage = new PrefixUsage(); prefixUsageMap.put(prefix, prefixUsage); } prefixUsage.count++; } public VoidValue visitComposite(CompositePattern p) { p.childrenAccept(this); return VoidValue.VOID; } public VoidValue visitUnary(UnaryPattern p) { return p.getChild().accept(this); } public VoidValue visitDefine(DefineComponent c) { c.getBody().accept(this); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { c.componentsAccept(this); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { String saveInheritedNamespace = inheritedNamespace; inheritedNamespace = c.getNs(); si.getSchema(c.getUri()).componentsAccept(this); inheritedNamespace = saveInheritedNamespace; return VoidValue.VOID; } void assignPrefixes() { for (Map.Entry> entry : namespacePrefixUsageMap.entrySet()) { String ns = entry.getKey(); if (!ns.equals("") && !ns.equals(WellKnownNamespaces.XML)) { Map prefixUsageMap = entry.getValue(); if (prefixUsageMap != null) { Map.Entry best = null; for (Map.Entry tem : prefixUsageMap.entrySet()) { if ((best == null || (tem.getValue()).count > (best.getValue()).count) && prefixOk(tem.getKey(), ns)) best = tem; } if (best != null) usePrefix(best.getKey(), ns); } } } } } PrefixManager(SchemaInfo si) { usePrefix("xml", WellKnownNamespaces.XML); new PrefixSelector(si).assignPrefixes(); } String getPrefix(String namespace) { String prefix = prefixMap.get(namespace); if (prefix == null && namespace.equals(WellKnownNamespaces.XML_SCHEMA)) { for (int i = 0; i < xsdPrefixes.length; i++) if (tryUsePrefix(xsdPrefixes[i], namespace)) return xsdPrefixes[i]; } if (prefix == null) prefix = tryUseUri(namespace); if (prefix == null) { do { prefix = "ns" + Integer.toString(nextGenIndex++); } while (!tryUsePrefix(prefix, namespace)); } return prefix; } private String tryUseUri(String namespace) { String segment = chooseSegment(namespace); if (segment == null) return null; if (segment.length() <= MAX_PREFIX_LENGTH && tryUsePrefix(segment, namespace)) return segment; for (int i = 1; i <= segment.length(); i++) { String prefix = segment.substring(0, i); if (tryUsePrefix(prefix, namespace)) return prefix; } return null; } private boolean tryUsePrefix(String prefix, String namespace) { if (!prefixOk(prefix, namespace)) return false; usePrefix(prefix, namespace); return true; } private boolean prefixOk(String prefix, String namespace) { return (!usedPrefixes.contains(prefix) && !(reservedPrefixes.contains(prefix) && namespace.equals(WellKnownNamespaces.XML_SCHEMA))); } private void usePrefix(String prefix, String namespace) { usedPrefixes.add(prefix); prefixMap.put(namespace, prefix); } static private String chooseSegment(String ns) { int off = ns.indexOf('#'); if (off >= 0) { String segment = ns.substring(off + 1).toLowerCase(); if (Naming.isNcname(segment)) return segment; } else off = ns.length(); for (;;) { int i = ns.lastIndexOf('/', off - 1); if (i < 0 || (i > 0 && ns.charAt(i - 1) == '/')) break; String segment = ns.substring(i + 1, off).toLowerCase(); if (segmentOk(segment)) return segment; off = i; } off = ns.indexOf(':'); if (off >= 0) { String segment = ns.substring(off + 1).toLowerCase(); if (segmentOk(segment)) return segment; } return null; } private static boolean segmentOk(String segment) { return Naming.isNcname(segment) && !segment.equals("ns") && !segment.equals("namespace"); } public String generateSourceUri(String ns) { // TODO add method to OutputDirectory to do this properly if (ns.equals("")) return "local"; else return "/" + getPrefix(ns); } } RefChecker.java000066400000000000000000000064131225366607500344570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AbstractVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.ParentRefPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.output.common.ErrorReporter; import java.util.HashMap; import java.util.Map; class RefChecker extends AbstractVisitor { private final SchemaInfo schema; private final ErrorReporter er; private final Map refMap = new HashMap(); private int currentDepth = 0; static private class Ref { int checkRecursionDepth; Ref(int checkRecursionDepth) { this.checkRecursionDepth = checkRecursionDepth; } } private RefChecker(SchemaInfo schema, ErrorReporter er) { this.schema = schema; this.er = er; } static void check(SchemaInfo schema, ErrorReporter er) { schema.getGrammar().componentsAccept(new RefChecker(schema, er)); } public VoidValue visitDiv(DivComponent c) { c.componentsAccept(this); return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { String name = c.getName(); if (name == DefineComponent.START || refMap.get(name) == null) c.getBody().accept(this); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { schema.getSchema(c.getUri()).componentsAccept(this); return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { currentDepth++; p.getChild().accept(this); currentDepth--; return VoidValue.VOID; } public VoidValue visitUnary(UnaryPattern p) { return p.getChild().accept(this); } public VoidValue visitComposite(CompositePattern p) { p.childrenAccept(this); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { Ref ref = refMap.get(p.getName()); if (ref == null) { ref = new Ref(currentDepth); refMap.put(p.getName(), ref); Pattern body = schema.getBody(p); if (body == null) er.error("undefined_reference", p.getName(), p.getSourceLocation()); else schema.getBody(p).accept(this); ref.checkRecursionDepth = -1; } else if (currentDepth == ref.checkRecursionDepth) er.error("recursive_reference", p.getName(), p.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitExternalRef(ExternalRefPattern p) { er.error("external_ref_not_supported", p.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitGrammar(GrammarPattern p) { er.error("nested_grammar_not_supported", p.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitParentRef(ParentRefPattern p) { er.error("parent_ref_no_grammar", p.getSourceLocation()); return VoidValue.VOID; } } RestrictionsChecker.java000066400000000000000000000246751225366607500364450ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AbstractVisitor; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.common.ErrorReporter; import java.util.HashSet; import java.util.Set; public class RestrictionsChecker { private final SchemaInfo si; private final ErrorReporter er; private final Set checkedPatterns = new HashSet(); private static final int DISALLOW_ELEMENT = 0x1; private static final int DISALLOW_ATTRIBUTE = 0x2; private static final int DISALLOW_LIST = 0x4; private static final int DISALLOW_TEXT = 0x8; private static final int DISALLOW_EMPTY = 0x10; private static final int DISALLOW_DATA = 0x20; private static final int DISALLOW_GROUP = 0x40; private static final int DISALLOW_INTERLEAVE = 0x80; private static final int DISALLOW_ONE_OR_MORE = 0x100; private static final int START_DISALLOW = DISALLOW_ATTRIBUTE|DISALLOW_LIST|DISALLOW_TEXT|DISALLOW_DATA|DISALLOW_EMPTY|DISALLOW_GROUP|DISALLOW_INTERLEAVE|DISALLOW_ONE_OR_MORE; private static final int LIST_DISALLOW = DISALLOW_ATTRIBUTE|DISALLOW_ELEMENT|DISALLOW_TEXT|DISALLOW_LIST|DISALLOW_INTERLEAVE; private static final int DATA_EXCEPT_DISALLOW = DISALLOW_ATTRIBUTE|DISALLOW_ELEMENT|DISALLOW_LIST|DISALLOW_EMPTY|DISALLOW_TEXT|DISALLOW_GROUP|DISALLOW_INTERLEAVE|DISALLOW_ONE_OR_MORE; private static final int ATTRIBUTE_DISALLOW = DISALLOW_ATTRIBUTE|DISALLOW_ELEMENT; private final PatternVisitor startVisitor = new Visitor("start", START_DISALLOW); private final PatternVisitor topLevelVisitor = new ListVisitor(null, 0); private final PatternVisitor elementVisitor = new ElementVisitor(); private final PatternVisitor elementRepeatVisitor = new ElementRepeatVisitor(); private final PatternVisitor elementRepeatGroupVisitor = new Visitor("element_repeat_group", DISALLOW_ATTRIBUTE); private final PatternVisitor elementRepeatInterleaveVisitor = new Visitor("element_repeat_interleave", DISALLOW_ATTRIBUTE); private final PatternVisitor attributeVisitor = new Visitor("attribute", ATTRIBUTE_DISALLOW); private final PatternVisitor listVisitor = new ListVisitor("list", LIST_DISALLOW); private final PatternVisitor dataExceptVisitor = new Visitor("data_except", DATA_EXCEPT_DISALLOW); class Visitor extends AbstractVisitor { private final String contextKey; private final int flags; Visitor(String contextKey, int flags) { this.contextKey = contextKey; this.flags = flags; } private boolean checkContext(int flag, String patternName, Pattern p) { if ((flags & flag) != 0) { er.error("illegal_contains", er.getLocalizer().message(contextKey), patternName, p.getSourceLocation()); return false; } else return true; } public VoidValue visitGroup(GroupPattern p) { if (checkContext(DISALLOW_GROUP, "group", p)) { checkGroup(p); super.visitGroup(p); } return VoidValue.VOID; } public VoidValue visitInterleave(InterleavePattern p) { if (checkContext(DISALLOW_INTERLEAVE, "interleave", p)) { checkGroup(p); super.visitInterleave(p); } return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { if (checkContext(DISALLOW_ELEMENT, "element", p) && !alreadyChecked(p)) p.getChild().accept(elementVisitor); return VoidValue.VOID; } public VoidValue visitAttribute(AttributePattern p) { if (checkContext(DISALLOW_ATTRIBUTE, "attribute", p) && !alreadyChecked(p)) p.getChild().accept(attributeVisitor); return VoidValue.VOID; } public VoidValue visitData(DataPattern p) { if (checkContext(DISALLOW_DATA, "data", p) && !alreadyChecked(p)) { Pattern except = p.getExcept(); if (except != null) except.accept(dataExceptVisitor); } return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { checkContext(DISALLOW_DATA, "value", p); return VoidValue.VOID; } public VoidValue visitList(ListPattern p) { if (checkContext(DISALLOW_LIST, "list", p) && !alreadyChecked(p)) p.getChild().accept(listVisitor); return VoidValue.VOID; } public VoidValue visitEmpty(EmptyPattern p) { checkContext(DISALLOW_EMPTY, "empty", p); return VoidValue.VOID; } public VoidValue visitOptional(OptionalPattern p) { if (checkContext(DISALLOW_EMPTY, "optional", p)) super.visitOptional(p); return VoidValue.VOID; } public VoidValue visitText(TextPattern p) { checkContext(DISALLOW_TEXT, "text", p); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { if (checkContext(DISALLOW_TEXT, "mixed", p)) { if (si.getChildType(p.getChild()).contains(ChildType.DATA)) er.error("mixed_data", p.getSourceLocation()); super.visitMixed(p); } return VoidValue.VOID; } public VoidValue visitOneOrMore(OneOrMorePattern p) { if (checkContext(DISALLOW_ONE_OR_MORE, "oneOrMore", p)) { checkNoDataUnlessInList(p, "oneOrMore"); super.visitOneOrMore(p); } return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { if (checkContext(DISALLOW_ONE_OR_MORE, "zeroOrMore", p)) { checkNoDataUnlessInList(p, "zeroOrMore"); super.visitZeroOrMore(p); } return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { return si.getBody(p).accept(this); } void checkNoDataUnlessInList(UnaryPattern p, String patternName) { if (!inList() && si.getChildType(p.getChild()).contains(ChildType.DATA)) er.error("not_in_list", patternName, p.getSourceLocation()); } void checkGroup(CompositePattern p) { int simpleCount = 0; boolean hadComplex = false; for (Pattern child : p.getChildren()) { ChildType ct = si.getChildType(child); boolean simple = ct.contains(ChildType.DATA); boolean complex = ct.contains(ChildType.TEXT) || ct.contains(ChildType.ELEMENT); if ((complex && simpleCount > 0) || (simple && hadComplex)) { er.error("group_data_other_children", p instanceof GroupPattern ? "group" : "interleave", p.getSourceLocation()); return; } if (simple) simpleCount++; if (complex) hadComplex = true; } if (simpleCount > 1) { if (p instanceof InterleavePattern) er.error("interleave_data", p.getSourceLocation()); else if (!inList()) er.error("group_data", p.getSourceLocation()); } } boolean inList() { return false; } } class ListVisitor extends Visitor { public ListVisitor(String contextKey, int flags) { super(contextKey, flags); } boolean inList() { return true; } } class ElementVisitor extends Visitor { ElementVisitor() { super(null, 0); } public VoidValue visitAttribute(AttributePattern p) { p.getNameClass().accept(this); return super.visitAttribute(p); } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { return elementRepeatVisitor.visitZeroOrMore(p); } public VoidValue visitOneOrMore(OneOrMorePattern p) { return elementRepeatVisitor.visitOneOrMore(p); } public VoidValue visitAnyName(AnyNameNameClass nc) { er.error("any_name_attribute_not_repeated", nc.getSourceLocation()); return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { er.error("ns_name_attribute_not_repeated", nc.getSourceLocation()); return VoidValue.VOID; } } class ElementRepeatVisitor extends Visitor { ElementRepeatVisitor() { super(null, 0); } public VoidValue visitGroup(GroupPattern p) { return elementRepeatGroupVisitor.visitGroup(p); } public VoidValue visitInterleave(InterleavePattern p) { return elementRepeatInterleaveVisitor.visitInterleave(p); } } class GrammarVisitor implements ComponentVisitor { public VoidValue visitDiv(DivComponent c) { c.componentsAccept(this); return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { if (c.getName() != DefineComponent.START) c.getBody().accept(topLevelVisitor); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { si.getSchema(c.getUri()).componentsAccept(this); return VoidValue.VOID; } } private RestrictionsChecker(SchemaInfo si, ErrorReporter er) { this.si = si; this.er = er; Pattern start = si.getStart(); if (start != null) start.accept(startVisitor); si.getGrammar().componentsAccept(new GrammarVisitor()); } static void check(SchemaInfo si, ErrorReporter er) { new RestrictionsChecker(si, er); } private boolean alreadyChecked(Pattern p) { if (checkedPatterns.contains(p)) return true; else { checkedPatterns.add(p); return false; } } } SchemaInfo.java000066400000000000000000000257141225366607500344770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Combine; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.common.ErrorReporter; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; class SchemaInfo { private final SchemaCollection sc; private final GrammarPattern grammar; private final ErrorReporter er; private final Map childTypeMap = new HashMap(); private final Map defineMap = new HashMap(); private final Set ignoredDefines = new HashSet(); private final PatternVisitor childTypeVisitor = new ChildTypeVisitor(); private static final int DEFINE_KEEP = 0; private static final int DEFINE_IGNORE = 1; private static final int DEFINE_REQUIRE = 2; static private class Define { int status = DEFINE_KEEP; boolean hadImplicit; Combine combine; Pattern pattern; CompositePattern wrapper; DefineComponent head; } abstract class PatternAnalysisVisitor extends AbstractPatternVisitor { abstract T get(Pattern p); abstract T choice(T o1, T o2); abstract T group(T o1, T o2); T interleave(T o1, T o2) { return group(o1, o2); } T ref(T obj) { return obj; } T oneOrMore(T obj) { return group(obj, obj); } abstract T empty(); abstract T text(); abstract T data(); abstract T notAllowed(); T list(T obj) { return data(); } public T visitChoice(ChoicePattern p) { List list = p.getChildren(); T obj = get(list.get(0)); for (int i = 1, length = list.size(); i < length; i++) obj = choice(obj, get(list.get(i))); return obj; } public T visitGroup(GroupPattern p) { List list = p.getChildren(); T obj = get(list.get(0)); for (int i = 1, length = list.size(); i < length; i++) obj = group(obj, get(list.get(i))); return obj; } public T visitInterleave(InterleavePattern p) { List list = p.getChildren(); T obj = get(list.get(0)); for (int i = 1, length = list.size(); i < length; i++) obj = interleave(obj, get(list.get(i))); return obj; } public T visitZeroOrMore(ZeroOrMorePattern p) { return choice(empty(), oneOrMore(get(p.getChild()))); } public T visitOneOrMore(OneOrMorePattern p) { return oneOrMore(get(p.getChild())); } public T visitOptional(OptionalPattern p) { return choice(empty(), get(p.getChild())); } public T visitEmpty(EmptyPattern p) { return empty(); } public T visitRef(RefPattern p) { return ref(get(getBody(p))); } public T visitMixed(MixedPattern p) { return interleave(text(), get(p.getChild())); } public T visitText(TextPattern p) { return text(); } public T visitData(DataPattern p) { return data(); } public T visitValue(ValuePattern p) { return data(); } public T visitList(ListPattern p) { return list(get(p.getChild())); } public T visitNotAllowed(NotAllowedPattern p) { return notAllowed(); } public T visitPattern(Pattern p) { return null; } } class ChildTypeVisitor extends PatternAnalysisVisitor { ChildType get(Pattern p) { return getChildType(p); } ChildType empty() { return ChildType.EMPTY; } ChildType text() { return ChildType.choice(ChildType.TEXT, ChildType.EMPTY); } ChildType data() { return ChildType.DATA; } ChildType notAllowed() { return ChildType.NOT_ALLOWED; } ChildType list(ChildType t) { if (t == ChildType.NOT_ALLOWED) return t; return data(); } ChildType choice(ChildType t1, ChildType t2) { return ChildType.choice(t1, t2); } ChildType group(ChildType t1, ChildType t2) { return ChildType.group(t1, t2); } public ChildType visitElement(ElementPattern p) { return ChildType.ELEMENT; } public ChildType visitAttribute(AttributePattern p) { if (getChildType(p.getChild()) == ChildType.NOT_ALLOWED) return ChildType.NOT_ALLOWED; return ChildType.choice(ChildType.ATTRIBUTE, ChildType.EMPTY); } } static class Override { int status; final Define define; final String name; Override(Define define, String name) { this.define = define; this.name = name; } } class GrammarVisitor implements ComponentVisitor { private final Set openIncludes = new HashSet(); private final Set allIncludes = new HashSet(); private List overrides = null; public VoidValue visitDefine(DefineComponent c) { Define define = lookupDefine(c.getName()); if (overrides != null) overrides.add(new Override(define, c.getName())); if (define.status != DEFINE_KEEP) { ignoredDefines.add(c); define.status = DEFINE_IGNORE; return VoidValue.VOID; } if (c.getCombine() == null) { if (define.hadImplicit) { er.error("multiple_define", c.getName(), c.getSourceLocation()); return VoidValue.VOID; } define.hadImplicit = true; } else if (define.combine == null) { define.combine = c.getCombine(); if (define.combine == Combine.CHOICE) define.wrapper = new ChoicePattern(); else define.wrapper = new InterleavePattern(); define.wrapper.setSourceLocation(c.getSourceLocation()); } else if (define.combine != c.getCombine()) { er.error("inconsistent_combine", c.getName(), c.getSourceLocation()); return VoidValue.VOID; } if (define.pattern == null) { define.pattern = c.getBody(); define.head = c; } else { if (define.pattern != define.wrapper) define.wrapper.getChildren().add(define.pattern); define.wrapper.getChildren().add(c.getBody()); define.pattern = define.wrapper; } return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { c.componentsAccept(this); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { List overrides = new Vector(); List savedOverrides = this.overrides; this.overrides = overrides; c.componentsAccept(this); this.overrides = savedOverrides; String uri = c.getUri(); if (openIncludes.contains(uri)) er.error("include_loop", uri, c.getSourceLocation()); else if (allIncludes.contains(uri)) er.error("multiple_include", uri, c.getSourceLocation()); else { for (Override or : overrides) { or.status = or.define.status; or.define.status = DEFINE_REQUIRE; } allIncludes.add(uri); openIncludes.add(uri); getSchema(uri).componentsAccept(this); openIncludes.remove(uri); for (Override or : overrides) { if (or.define.status == DEFINE_REQUIRE) { if (or.name == DefineComponent.START) er.error("missing_start_replacement", c.getSourceLocation()); else er.error("missing_define_replacement", or.name, c.getSourceLocation()); } or.define.status = or.status; } } return VoidValue.VOID; } } SchemaInfo(SchemaCollection sc, ErrorReporter er) { this.sc = sc; this.er = er; forceGrammar(); grammar = getSchema(sc.getMainUri()); grammar.componentsAccept(new GrammarVisitor()); } private void forceGrammar() { SchemaDocument sd = sc.getSchemaDocumentMap().get(sc.getMainUri()); sd.setPattern(convertToGrammar(sd.getPattern())); // TODO convert other schemas } private static GrammarPattern convertToGrammar(Pattern p) { if (p instanceof GrammarPattern) return (GrammarPattern)p; GrammarPattern g = new GrammarPattern(); g.setSourceLocation(p.getSourceLocation()); g.setContext(p.getContext()); DefineComponent dc = new DefineComponent(DefineComponent.START, p); dc.setSourceLocation(p.getSourceLocation()); g.getComponents().add(dc); return g; } GrammarPattern getGrammar() { return grammar; } String getMainUri() { return sc.getMainUri(); } GrammarPattern getSchema(String sourceUri) { return (GrammarPattern)(sc.getSchemaDocumentMap().get(sourceUri)).getPattern(); } String getEncoding(String sourceUri) { return (sc.getSchemaDocumentMap().get(sourceUri)).getEncoding(); } ChildType getChildType(Pattern p) { ChildType ct = childTypeMap.get(p); if (ct == null) { ct = p.accept(childTypeVisitor); childTypeMap.put(p, ct); } return ct; } Pattern getStart() { return lookupDefine(DefineComponent.START).pattern; } Pattern getBody(RefPattern p) { return lookupDefine(p.getName()).pattern; } Pattern getBody(DefineComponent c) { Define def = lookupDefine(c.getName()); if (def == null || def.head != c) return null; return def.pattern; } boolean isIgnored(DefineComponent c) { return ignoredDefines.contains(c); } private Define lookupDefine(String name) { Define define = defineMap.get(name); if (define == null) { define = new Define(); defineMap.put(name, define); } return define; } }SourceUriGenerator.java000066400000000000000000000001771225366607500362460ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; public interface SourceUriGenerator { String generateSourceUri(String ns); } Transformer.java000066400000000000000000000442501225366607500347610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.output.xsd.basic.AbstractAttributeUseVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Attribute; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupDefinition; import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.AttributeUseChoice; import com.thaiopensource.relaxng.output.xsd.basic.ComplexType; import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent; import com.thaiopensource.relaxng.output.xsd.basic.Element; import com.thaiopensource.relaxng.output.xsd.basic.Facet; import com.thaiopensource.relaxng.output.xsd.basic.GroupRef; import com.thaiopensource.relaxng.output.xsd.basic.Occurs; import com.thaiopensource.relaxng.output.xsd.basic.OptionalAttribute; import com.thaiopensource.relaxng.output.xsd.basic.Particle; import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll; import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice; import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat; import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence; import com.thaiopensource.relaxng.output.xsd.basic.ParticleVisitor; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.xsd.basic.SchemaTransformer; import com.thaiopensource.relaxng.output.xsd.basic.SimpleType; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction; import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion; import com.thaiopensource.relaxng.output.xsd.basic.SingleAttributeUse; import com.thaiopensource.relaxng.output.xsd.basic.Wildcard; import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute; import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement; import com.thaiopensource.util.Equal; import com.thaiopensource.xml.util.Name; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; class Transformer extends SchemaTransformer { private final AttributeMapper attributeMapper = new AttributeMapper(); private final Set transformedAttributeGroups = new HashSet(); private final ErrorReporter er; private boolean preserveAllGroup = false; Transformer(Schema schema, ErrorReporter er) { super(schema); this.er = er; } public SimpleType visitUnion(SimpleTypeUnion t) { List list = transformSimpleTypeList(t.getChildren()); SimpleType combined = combineEnumeration(t, list); if (combined != null) return combined; return new SimpleTypeUnion(t.getLocation(), t.getAnnotation(), list); } private static SimpleType combineEnumeration(SimpleTypeUnion orig, List transformedChildren) { if (transformedChildren.size() < 2) return null; SimpleType first = transformedChildren.get(0); if (!(first instanceof SimpleTypeRestriction)) return null; String builtinTypeName = ((SimpleTypeRestriction)first).getName(); List facets = new Vector(); for (SimpleType child : transformedChildren) { if (!(child instanceof SimpleTypeRestriction)) return null; SimpleTypeRestriction restriction = (SimpleTypeRestriction)child; if (!restriction.getName().equals(builtinTypeName)) return null; if (restriction.getFacets().isEmpty()) return null; for (Facet facet : restriction.getFacets()) { if (!facet.getName().equals("enumeration")) return null; facets.add(facet); } } return new SimpleTypeRestriction(orig.getLocation(), orig.getAnnotation(), builtinTypeName, facets); } class SequenceDetector implements ParticleVisitor { public Boolean visitElement(Element p) { return Boolean.FALSE; } public Boolean visitWildcardElement(WildcardElement p) { return Boolean.FALSE; } public Boolean visitSequence(ParticleSequence p) { return Boolean.TRUE; } public Boolean visitGroupRef(GroupRef p) { return getSchema().getGroup(p.getName()).getParticle().accept(this); } public Boolean visitAll(ParticleAll p) { return Boolean.FALSE; } public Boolean visitRepeat(ParticleRepeat p) { return p.getChild().accept(this); } public Boolean visitChoice(ParticleChoice p) { for (Particle child : p.getChildren()) if (child.accept(this) == Boolean.TRUE) return Boolean.TRUE; return Boolean.FALSE; } } class AllBodyTransformer extends SchemaTransformer { public AllBodyTransformer(Schema schema) { super(schema); } public Particle visitGroupRef(GroupRef p) { if (new SequenceDetector().visitGroupRef(p) == Boolean.FALSE) return p; return getSchema().getGroup(p.getName()).getParticle().accept(this); } public Particle visitSequence(ParticleSequence p) { return new ParticleChoice(p.getLocation(), p.getAnnotation(), transformParticleList(p.getChildren())); } public Particle visitRepeat(ParticleRepeat p) { return p.getChild().accept(this); } public Particle visitElement(Element p) { return Transformer.this.visitElement(p); } } public Particle visitAll(ParticleAll p) { if (preserveAllGroup) { preserveAllGroup = false; return super.visitAll(p); } return new ParticleRepeat(p.getLocation(), p.getAnnotation(), new ParticleChoice(p.getLocation(), null, new AllBodyTransformer(getSchema()).transformParticleList(transformParticleList(p.getChildren()))), Occurs.ZERO_OR_MORE); } public AttributeUse visitAttributeGroup(AttributeGroup a) { List children = transformAttributeUseList(a.getChildren()); Wildcard wildcard = null; boolean[] removeWildcard = new boolean[children.size()]; boolean multipleWildcards = false; int wildcardUseIndex = -1; for (int i = 0; i < removeWildcard.length; i++) { Wildcard wc = attributeMapper.getAttributeWildcard(children.get(i)); if (wc != null) { if (wildcard == null) { wildcard = wc; wildcardUseIndex = i; } else { multipleWildcards = true; Wildcard union = Wildcard.union(wildcard, wc); if (union.equals(wildcard)) removeWildcard[i] = true; else if (union.equals(wc)) { if (wildcardUseIndex >= 0) removeWildcard[wildcardUseIndex] = true; wildcardUseIndex = i; wildcard = wc; } else { removeWildcard[i] = true; if (wildcardUseIndex >= 0) removeWildcard[wildcardUseIndex] = true; wildcard = union; wildcardUseIndex = -1; } } } } if (!multipleWildcards) { if (children == a.getChildren()) return a; return new AttributeGroup(a.getLocation(), a.getAnnotation(), children); } List newChildren = new Vector(); for (int i = 0; i < removeWildcard.length; i++) { AttributeUse att = children.get(i); if (removeWildcard[i]) att = att.accept(new AttributeTransformer(null, null, false)); newChildren.add(att); } if (wildcardUseIndex == -1) newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard)); return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren); } public AttributeUse visitAttributeUseChoice(AttributeUseChoice a) { List children = transformAttributeUseList(a.getChildren()); Map[] maps = (Map[])new Map[children.size()]; int wildcardUseIndex = -1; Wildcard wildcard = null; for (int i = 0; i < maps.length; i++) { maps[i] = attributeMapper.getAttributeMap(children.get(i)); Wildcard wc = attributeMapper.getAttributeWildcard(children.get(i)); if (wc != null) { if (wildcard == null) { wildcard = wc; wildcardUseIndex = i; } else { Wildcard union = Wildcard.union(wildcard, wc); if (!union.equals(wildcard)) { if (union.equals(wc)) wildcardUseIndex = i; else wildcardUseIndex = -1; wildcard = union; } } } } Set required = new HashSet(); Set union = new HashSet(maps[0].keySet()); for (int i = 1; i < maps.length; i++) union.addAll(maps[i].keySet()); Set[] retainAttributeNames = (Set[])new Set[children.size()]; for (int i = 0; i < retainAttributeNames.length; i++) retainAttributeNames[i] = new HashSet(); List newChildren = new Vector(); for (Name name : union) { if (wildcard == null || !wildcard.contains(name)) { SingleAttributeUse[] uses = new SingleAttributeUse[maps.length]; int useIndex = -1; boolean isRequired = true; for (int i = 0; i < maps.length; i++) { uses[i] = maps[i].get(name); if (uses[i] != null) { if (useIndex >= 0) useIndex = -2; else if (useIndex == -1) useIndex = i; if (uses[i].isOptional()) isRequired = false; } else isRequired = false; } if (isRequired) required.add(name); if (useIndex < 0) useIndex = chooseUseIndex(uses); if (useIndex >= 0) retainAttributeNames[useIndex].add(name); else { List choices = new Vector(); for (int i = 0; i < uses.length; i++) if (uses[i] != null && uses[i].getType() != null) choices.add(uses[i].getType()); Attribute tem = new Attribute(a.getLocation(), null, name, new SimpleTypeUnion(a.getLocation(), null, choices).accept(this)); if (isRequired) newChildren.add(tem); else newChildren.add(new OptionalAttribute(a.getLocation(), null, tem, null)); } } } for (int i = 0; i < retainAttributeNames.length; i++) { AttributeUse tem = children.get(i).accept(new AttributeTransformer(retainAttributeNames[i], required, i == wildcardUseIndex)); if (!tem.equals(AttributeGroup.EMPTY)) newChildren.add(tem); } if (wildcard != null && wildcardUseIndex == -1) newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard)); return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren); } private static int chooseUseIndex(SingleAttributeUse[] uses) { for (int i = 0; i < uses.length; i++) if (uses[i] != null && uses[i].getType() == null && uses[i].getDefaultValue() == null) return i; int firstIndex = -1; for (int i = 0; i < uses.length; i++) { if (uses[i] != null) { if (firstIndex == -1) firstIndex = i; else if (!Equal.equal(uses[i].getType(), uses[firstIndex].getType()) || !Equal.equal(uses[i].getDefaultValue(), uses[firstIndex].getDefaultValue())) return -1; } } return firstIndex; } static class AttributeInfo { final Map map; final Wildcard wildcard; final static Map EMPTY_MAP = Collections.emptyMap(); AttributeInfo(Map map, Wildcard wildcard) { this.map = map; this.wildcard = wildcard; } } class AttributeMapper extends AbstractAttributeUseVisitor { private final Map cache = new HashMap(); Map getAttributeMap(AttributeUse a) { return getAttributeInfo(a).map; } Wildcard getAttributeWildcard(AttributeUse a) { return getAttributeInfo(a).wildcard; } private AttributeInfo getAttributeInfo(AttributeUse a) { AttributeInfo info = cache.get(a); if (info == null) { info = a.accept(this); cache.put(a, info); } return info; } public AttributeInfo visitAttribute(Attribute a) { Map map = new HashMap(); map.put(a.getName(), a); return new AttributeInfo(map, null); } public AttributeInfo visitAttributeGroup(AttributeGroup a) { Map map = new HashMap(); Wildcard wildcard = null; for (AttributeUse child : a.getChildren()) { AttributeInfo info = getAttributeInfo(child); if (info.wildcard != null) wildcard = info.wildcard; map.putAll(info.map); } return new AttributeInfo(map, wildcard); } public AttributeInfo visitOptionalAttribute(OptionalAttribute a) { Map map = new HashMap(); map.put(a.getAttribute().getName(), a); return new AttributeInfo(map, null); } public AttributeInfo visitAttributeGroupRef(AttributeGroupRef a) { return getAttributeInfo(getTransformedAttributeGroup(a.getName())); } public AttributeInfo visitWildcardAttribute(WildcardAttribute a) { return new AttributeInfo(AttributeInfo.EMPTY_MAP, a.getWildcard()); } } class AttributeTransformer extends AbstractAttributeUseVisitor { private final Set retainNames; private final Set requiredNames; private final boolean retainWildcard; public AttributeTransformer(Set retainNames, Set requiredNames, boolean retainWildcard) { this.retainNames = retainNames; this.requiredNames = requiredNames; this.retainWildcard = retainWildcard; } public AttributeUse visitAttribute(Attribute a) { if (retainNames != null && !retainNames.contains(a.getName())) return AttributeGroup.EMPTY; if (requiredNames != null && !requiredNames.contains(a.getName())) return new OptionalAttribute(a.getLocation(), null, a, null); return a; } public AttributeUse visitOptionalAttribute(OptionalAttribute a) { if (retainNames != null && !retainNames.contains(a.getName())) return AttributeGroup.EMPTY; return a; } public AttributeUse visitWildcardAttribute(WildcardAttribute a) { if (!retainWildcard) return AttributeGroup.EMPTY; return a; } public AttributeUse visitAttributeGroupRef(AttributeGroupRef a) { AttributeUse refed = getTransformedAttributeGroup(a.getName()); if (isOk(attributeMapper.getAttributeMap(refed)) && (retainWildcard || attributeMapper.getAttributeWildcard(refed) == null)) return a; return refed.accept(this); } private boolean isOk(Map map) { for (Map.Entry entry : map.entrySet()) { Name name = entry.getKey(); SingleAttributeUse use = entry.getValue(); if (retainNames != null && !retainNames.contains(name)) return false; if (requiredNames != null && !use.isOptional() && !requiredNames.contains(name)) return false; } return true; } public AttributeUse visitAttributeGroup(AttributeGroup a) { List children = a.getChildren(); List transformedChildren = null; for (int i = 0, len = children.size(); i < len; i++) { AttributeUse child = children.get(i).accept(this); if (transformedChildren != null) { if (!child.equals(AttributeGroup.EMPTY)) transformedChildren.add(child); } else if (child != children.get(i)) { transformedChildren = new Vector(); for (int j = 0; j < i; j++) transformedChildren.add(children.get(j)); if (!child.equals(AttributeGroup.EMPTY)) transformedChildren.add(child); } } if (transformedChildren == null) return a; return new AttributeGroup(a.getLocation(), a.getAnnotation(), transformedChildren); } } public void visitAttributeGroup(AttributeGroupDefinition def) { def.setAttributeUses(getTransformedAttributeGroup(def.getName())); } private AttributeUse getTransformedAttributeGroup(String name) { AttributeGroupDefinition def = getSchema().getAttributeGroup(name); if (!transformedAttributeGroups.contains(name)) { def.setAttributeUses(def.getAttributeUses().accept(this)); transformedAttributeGroups.add(name); } return def.getAttributeUses(); } public Particle visitElement(Element p) { if (containsLegalAllGroup(p)) preserveAllGroup = true; return super.visitElement(p); } private static boolean containsLegalAllGroup(Element p) { ComplexType t = p.getComplexType(); if (!(t instanceof ComplexTypeComplexContent)) return false; Particle particle = ((ComplexTypeComplexContent)t).getParticle(); if (!(particle instanceof ParticleAll)) return false; String ns = p.getName().getNamespaceUri(); for (Particle child : ((ParticleAll)particle).getChildren()) { if (child instanceof ParticleRepeat) { Occurs occur = ((ParticleRepeat)child).getOccurs(); if (occur.getMin() > 1 || occur.getMax() > 1) return false; child = ((ParticleRepeat)child).getChild(); } if (!(child instanceof Element)) return false; if (!((Element)child).getName().getNamespaceUri().equals(ns)) return false; } return true; } } WildcardBuilder.java000066400000000000000000000061071225366607500355160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassVisitor; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.output.xsd.basic.Wildcard; import com.thaiopensource.xml.util.Name; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; class WildcardBuilder implements NameClassVisitor { private boolean inExcept = false; private final String inheritedNamespace; private Wildcard wildcard = null; private Set excludedNames; private Set namespaces; private String inNs = null; static Wildcard createWildcard(NameClass nc, String inheritedNamespace) { WildcardBuilder builder = new WildcardBuilder(inheritedNamespace); nc.accept(builder); return builder.wildcard; } private void combineWildcard(Wildcard wc) { if (wildcard == null) wildcard = wc; else wildcard = Wildcard.union(wildcard, wc); } private WildcardBuilder(String inheritedNamespace) { this.inheritedNamespace = inheritedNamespace; } public VoidValue visitChoice(ChoiceNameClass nc) { List list = nc.getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); return VoidValue.VOID; } public VoidValue visitAnyName(AnyNameNameClass nc) { if (!inExcept) { if (nc.getExcept() != null) { namespaces = new HashSet(); excludedNames = new HashSet(); inExcept = true; nc.getExcept().accept(this); inExcept = false; } else { namespaces = Collections.emptySet(); excludedNames = Collections.emptySet(); } combineWildcard(new Wildcard(false, namespaces, excludedNames)); } return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { String ns = resolve(nc.getNs()); if (!inExcept) { if (nc.getExcept() != null) { namespaces = null; excludedNames = new HashSet(); inNs = ns; inExcept = true; nc.getExcept().accept(this); inExcept = false; inNs = null; } else excludedNames = Collections.emptySet(); namespaces = new HashSet(); namespaces.add(ns); combineWildcard(new Wildcard(true, namespaces, excludedNames)); } else if (inNs == null) namespaces.add(ns); return VoidValue.VOID; } public VoidValue visitName(NameNameClass nc) { if (inExcept) { String ns = resolve(nc.getNamespaceUri()); if (inNs == null || inNs.equals(ns)) excludedNames.add(new Name(ns, nc.getLocalName())); } return VoidValue.VOID; } private String resolve(String ns) { if (ns == NameNameClass.INHERIT_NS) return inheritedNamespace; return ns; } } XsdOutputFormat.java000066400000000000000000000060731225366607500356100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdpackage com.thaiopensource.relaxng.output.xsd; import com.thaiopensource.relaxng.output.OutputFormat; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.OutputFailedException; import com.thaiopensource.relaxng.output.OutputDirectoryParamProcessor; import com.thaiopensource.relaxng.output.xsd.basic.Schema; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.relaxng.translate.util.ParamProcessor; import com.thaiopensource.relaxng.translate.util.AbstractParam; import com.thaiopensource.relaxng.translate.util.EnumParam; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public class XsdOutputFormat implements OutputFormat { static private final boolean DEFAULT_ENABLE_ABSTRACT_ELEMENT = true; static private final String[] processContents = { "skip", "lax", "strict" }; public void output(SchemaCollection sc, OutputDirectory od, String[] params, String inputFormat, ErrorHandler eh) throws SAXException, IOException, OutputFailedException, InvalidParamsException { final Guide guide = new Guide(DEFAULT_ENABLE_ABSTRACT_ELEMENT); final BasicOutput.Options outputOptions = new BasicOutput.Options(); if ("dtd".equals(inputFormat)) outputOptions.anyProcessContents = "strict"; ParamProcessor pp = new OutputDirectoryParamProcessor(od); pp.declare("disable-abstract-elements", new AbstractParam() { public void set(boolean value) { guide.setDefaultGroupEnableAbstractElements(!value); } }); pp.declare("any-process-contents", new EnumParam(processContents) { protected void setEnum(int i) { outputOptions.anyProcessContents = getValues()[i]; } }); pp.declare("any-attribute-process-contents", new EnumParam(processContents) { protected void setEnum(int i) { outputOptions.anyAttributeProcessContents = getValues()[i]; } }); pp.process(params, eh); try { ErrorReporter er = new ErrorReporter(eh, XsdOutputFormat.class); SchemaInfo si = new SchemaInfo(sc, er); if (!er.getHadError()) { RefChecker.check(si, er); if (!er.getHadError()) { RestrictionsChecker.check(si, er); if (!er.getHadError()) { Schema schema = BasicBuilder.buildBasicSchema(si, guide, er); if (!er.getHadError()) { new Transformer(schema, er).transform(); if (!er.getHadError()) BasicOutput.output(schema, guide, new PrefixManager(si), od, outputOptions, er); } } } } if (er.getHadError()) throw new OutputFailedException(); } catch (ErrorReporter.WrappedSAXException e) { throw e.getException(); } } } jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basic/000077500000000000000000000000001225366607500327475ustar00rootroot00000000000000AbstractAttributeUseVisitor.java000066400000000000000000000003631225366607500412210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public abstract class AbstractAttributeUseVisitor implements AttributeUseVisitor { public T visitAttributeUseChoice(AttributeUseChoice a) { return visitAttributeGroup(a); } } AbstractSchemaVisitor.java000066400000000000000000000007131225366607500400000ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public class AbstractSchemaVisitor implements SchemaVisitor { public void visitGroup(GroupDefinition def) { } public void visitAttributeGroup(AttributeGroupDefinition def) { } public void visitSimpleType(SimpleTypeDefinition def) { } public void visitInclude(Include include) { } public void visitRoot(RootDeclaration decl) { } public void visitComment(Comment comment) { } } Annotated.java000066400000000000000000000014161225366607500354520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.util.Equal; public class Annotated extends Located { private final Annotation annotation; public Annotated(SourceLocation location, Annotation annotation) { super(location); this.annotation = annotation; } public Annotation getAnnotation() { return annotation; } public boolean equals(Object obj) { if (obj == null) return false; if (this.getClass() != obj.getClass()) return false; return Equal.equal(annotation, ((Annotated)obj).annotation); } public int hashCode() { int hc = getClass().hashCode(); if (annotation != null) hc ^= annotation.hashCode(); return hc; } } Annotation.java000066400000000000000000000011311225366607500356410ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.util.Equal; public class Annotation { private final String documentation; public Annotation(String documentation) { this.documentation = documentation; } public String getDocumentation() { return documentation; } public boolean equals(Object obj) { return obj instanceof Annotation && Equal.equal(documentation, ((Annotation)obj).documentation); } public int hashCode() { if (documentation != null) return documentation.hashCode(); return Annotation.class.hashCode(); } } Attribute.java000066400000000000000000000023711225366607500355010ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.xml.util.Name; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.util.Equal; public class Attribute extends SingleAttributeUse implements Structure { private final Name name; private final SimpleType type; /** * type may be null, indicating any type */ public Attribute(SourceLocation location, Annotation annotation, Name name, SimpleType type) { super(location, annotation); this.name = name; this.type = type; } public Name getName() { return name; } public SimpleType getType() { return type; } public T accept(AttributeUseVisitor visitor) { return visitor.visitAttribute(this); } public T accept(StructureVisitor visitor) { return visitor.visitAttribute(this); } public boolean equals(Object obj) { if (!super.equals(obj)) return false; Attribute other = (Attribute)obj; return Equal.equal(this.type, other.type) && this.name.equals(other.name); } public int hashCode() { int hc = super.hashCode() ^ name.hashCode(); if (type != null) hc ^= type.hashCode(); return hc; } public boolean isOptional() { return false; } } AttributeGroup.java000066400000000000000000000017701225366607500365200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; import java.util.Collections; public class AttributeGroup extends AttributeUse { private final List children; private static final List EMPTY_LIST = Collections.emptyList(); public static final AttributeGroup EMPTY = new AttributeGroup(null, null, EMPTY_LIST); public AttributeGroup(SourceLocation location, Annotation annotation, List children) { super(location, annotation); this.children = Collections.unmodifiableList(children); } public List getChildren() { return children; } public boolean equals(Object obj) { return super.equals(obj) && ((AttributeGroup)obj).children.equals(children); } public int hashCode() { return super.hashCode() ^ children.hashCode(); } public T accept(AttributeUseVisitor visitor) { return visitor.visitAttributeGroup(this); } } AttributeGroupDefinition.java000066400000000000000000000013231225366607500405230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class AttributeGroupDefinition extends Definition { private AttributeUse attributeUses; public AttributeGroupDefinition(SourceLocation location, Annotation annotation, Schema parentSchema, String name, AttributeUse attributeUses) { super(location, annotation, parentSchema, name); this.attributeUses = attributeUses; } public AttributeUse getAttributeUses() { return attributeUses; } public void setAttributeUses(AttributeUse attributeUses) { this.attributeUses = attributeUses; } public void accept(SchemaVisitor visitor) { visitor.visitAttributeGroup(this); } } AttributeGroupRef.java000066400000000000000000000012761225366607500371560ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class AttributeGroupRef extends AttributeUse { private final String name; public AttributeGroupRef(SourceLocation location, Annotation annotation, String name) { super(location, annotation); this.name = name; } public String getName() { return name; } public T accept(AttributeUseVisitor visitor) { return visitor.visitAttributeGroupRef(this); } public boolean equals(Object obj) { return super.equals(obj) && ((AttributeGroupRef)obj).name.equals(name); } public int hashCode() { return super.hashCode() ^ name.hashCode(); } } AttributeUse.java000066400000000000000000000005251225366607500361550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public abstract class AttributeUse extends Annotated { public AttributeUse(SourceLocation location, Annotation annotation) { super(location, annotation); } public abstract T accept(AttributeUseVisitor visitor); } AttributeUseChoice.java000066400000000000000000000007121225366607500372660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; public class AttributeUseChoice extends AttributeGroup { public AttributeUseChoice(SourceLocation location, Annotation annotation, List children) { super(location, annotation, children); } public T accept(AttributeUseVisitor visitor) { return visitor.visitAttributeUseChoice(this); } } AttributeUseVisitor.java000066400000000000000000000005641225366607500375400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface AttributeUseVisitor { T visitAttribute(Attribute a); T visitOptionalAttribute(OptionalAttribute a); T visitAttributeGroupRef(AttributeGroupRef a); T visitAttributeGroup(AttributeGroup a); T visitAttributeUseChoice(AttributeUseChoice a); T visitWildcardAttribute(WildcardAttribute a); } Comment.java000066400000000000000000000010161225366607500351330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class Comment extends Located implements TopLevel { private String content; public Comment(SourceLocation location, String content) { super(location); this.content = content; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public void accept(SchemaVisitor visitor) { visitor.visitComment(this); } } ComplexType.java000066400000000000000000000003161225366607500360040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public abstract class ComplexType { public abstract T accept(ComplexTypeVisitor visitor); public boolean isMixed() { return false; } } ComplexTypeAllowedContent.java000066400000000000000000000005421225366607500406500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public abstract class ComplexTypeAllowedContent extends ComplexType { private final AttributeUse attributeUses; public ComplexTypeAllowedContent(AttributeUse attributeUses) { this.attributeUses = attributeUses; } public AttributeUse getAttributeUses() { return attributeUses; } } ComplexTypeComplexContent.java000066400000000000000000000023001225366607500406620ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public class ComplexTypeComplexContent extends ComplexTypeAllowedContent { private final Particle particle; private final boolean mixed; /** * particle may be null */ public ComplexTypeComplexContent(AttributeUse attributeUses, Particle particle, boolean mixed) { super(attributeUses); this.particle = particle; this.mixed = mixed; } public Particle getParticle() { return particle; } public boolean isMixed() { return mixed; } public T accept(ComplexTypeVisitor visitor) { return visitor.visitComplexContent(this); } public boolean equals(Object obj) { if (!(obj instanceof ComplexTypeComplexContent)) return false; ComplexTypeComplexContent other = (ComplexTypeComplexContent)obj; if (particle == null) { if (other.particle != null) return false; } else if (!particle.equals(other.particle)) return false; return getAttributeUses().equals(other.getAttributeUses()) && mixed == other.mixed; } public int hashCode() { int hc = getAttributeUses().hashCode(); if (particle != null) hc ^= particle.hashCode(); return hc; } } ComplexTypeNotAllowedContent.java000066400000000000000000000004231225366607500413270ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public class ComplexTypeNotAllowedContent extends ComplexType { public ComplexTypeNotAllowedContent() { } public T accept(ComplexTypeVisitor visitor) { return visitor.visitNotAllowedContent(this); } } ComplexTypeSimpleContent.java000066400000000000000000000015651225366607500405200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public class ComplexTypeSimpleContent extends ComplexTypeAllowedContent { private final SimpleType simpleType; public ComplexTypeSimpleContent(AttributeUse attributeUses, SimpleType simpleType) { super(attributeUses); this.simpleType = simpleType; } public SimpleType getSimpleType() { return simpleType; } public T accept(ComplexTypeVisitor visitor) { return visitor.visitSimpleContent(this); } public boolean equals(Object obj) { if (!(obj instanceof ComplexTypeSimpleContent)) return false; ComplexTypeSimpleContent other = (ComplexTypeSimpleContent)obj; return this.getAttributeUses().equals(other.getAttributeUses()) && this.simpleType.equals(other.simpleType); } public int hashCode() { return getAttributeUses().hashCode() ^ simpleType.hashCode(); } } ComplexTypeVisitor.java000066400000000000000000000004071225366607500373650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface ComplexTypeVisitor { T visitComplexContent(ComplexTypeComplexContent t); T visitSimpleContent(ComplexTypeSimpleContent t); T visitNotAllowedContent(ComplexTypeNotAllowedContent t); } Definition.java000066400000000000000000000010711225366607500356220ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public abstract class Definition extends Annotated implements TopLevel { private final Schema parentSchema; private final String name; public Definition(SourceLocation location, Annotation annotation, Schema parentSchema, String name) { super(location, annotation); this.parentSchema = parentSchema; this.name = name; } public Schema getParentSchema() { return parentSchema; } public String getName() { return name; } } Element.java000066400000000000000000000021221225366607500351210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.xml.util.Name; import com.thaiopensource.relaxng.edit.SourceLocation; public class Element extends Particle implements Structure { private final Name name; private final ComplexType complexType; public Element(SourceLocation location, Annotation annotation, Name name, ComplexType complexType) { super(location, annotation); this.name = name; this.complexType = complexType; } public Name getName() { return name; } public ComplexType getComplexType() { return complexType; } public T accept(ParticleVisitor visitor) { return visitor.visitElement(this); } public T accept(StructureVisitor visitor) { return visitor.visitElement(this); } public boolean equals(Object obj) { if (!super.equals(obj)) return false; Element other = (Element)obj; return this.name.equals(other.name) && this.complexType.equals(other.complexType); } public int hashCode() { return super.hashCode() ^ name.hashCode() ^ complexType.hashCode(); } } Facet.java000066400000000000000000000025331225366607500345600ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.util.Equal; public class Facet extends Annotated { private final String name; private final String value; private final String prefix; private final String namespace; public Facet(SourceLocation location, Annotation annotation, String name, String value) { this(location, annotation, name, value, null, null); } public Facet(SourceLocation location, Annotation annotation, String name, String value, String prefix, String namespace) { super(location, annotation); this.name = name; this.value = value; this.prefix = prefix; this.namespace = namespace; } public String getName() { return name; } public String getValue() { return value; } public String getPrefix() { return prefix; } public String getNamespace() { return namespace; } public boolean equals(Object obj) { if (!super.equals(obj)) return false; Facet other = (Facet)obj; return (this.name.equals(other.name) && this.value.equals(other.value) && Equal.equal(this.prefix, other.prefix) && Equal.equal(this.namespace, other.namespace)); } public int hashCode() { return super.hashCode() ^ name.hashCode() ^ value.hashCode(); } } GroupDefinition.java000066400000000000000000000011661225366607500366440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class GroupDefinition extends Definition { private Particle particle; public GroupDefinition(SourceLocation location, Annotation annotation, Schema parentSchema, String name, Particle particle) { super(location, annotation, parentSchema, name); this.particle = particle; } public Particle getParticle() { return particle; } public void setParticle(Particle particle) { this.particle = particle; } public void accept(SchemaVisitor visitor) { visitor.visitGroup(this); } } GroupRef.java000066400000000000000000000012221225366607500352610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class GroupRef extends Particle { private final String name; public GroupRef(SourceLocation location, Annotation annotation, String name) { super(location, annotation); this.name = name; } public String getName() { return name; } public T accept(ParticleVisitor visitor) { return visitor.visitGroupRef(this); } public boolean equals(Object obj) { return super.equals(obj) && name.equals(((GroupRef)obj).name); } public int hashCode() { return super.hashCode() ^ name.hashCode(); } } Include.java000066400000000000000000000010271225366607500351160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class Include extends Annotated implements TopLevel { private final Schema includedSchema; public Include(SourceLocation location, Annotation annotation, Schema includedSchema) { super(location, annotation); this.includedSchema = includedSchema; } public Schema getIncludedSchema() { return includedSchema; } public void accept(SchemaVisitor visitor) { visitor.visitInclude(this); } } Located.java000066400000000000000000000005121225366607500351040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public abstract class Located { private final SourceLocation location; public Located(SourceLocation location) { this.location = location; } public SourceLocation getLocation() { return location; } } Occurs.java000066400000000000000000000025001225366607500347660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public class Occurs { private final int min; private final int max; static public final int UNBOUNDED = Integer.MAX_VALUE; static public final Occurs EXACTLY_ONE = new Occurs(1, 1); static public final Occurs ONE_OR_MORE = new Occurs(1, UNBOUNDED); static public final Occurs ZERO_OR_MORE = new Occurs(0, UNBOUNDED); static public final Occurs OPTIONAL = new Occurs(0, 1); public Occurs(int min, int max) { this.min = min; this.max = max; } public int getMin() { return min; } public int getMax() { return max; } public boolean equals(Object obj) { if (!(obj instanceof Occurs)) return false; return this.min == ((Occurs)obj).min && max == ((Occurs)obj).max; } public int hashCode() { return min ^ max; } static public Occurs add(Occurs occ1, Occurs occ2) { return new Occurs(occ1.min + occ2.min, occ1.max == UNBOUNDED || occ2.max == UNBOUNDED ? UNBOUNDED : occ1.max + occ2.max); } static public Occurs multiply(Occurs occ1, Occurs occ2) { return new Occurs(occ1.min * occ2.min, occ1.max == UNBOUNDED || occ2.max == UNBOUNDED ? UNBOUNDED : occ1.max * occ2.max); } } OptionalAttribute.java000066400000000000000000000025271225366607500372120ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.xml.util.Name; import com.thaiopensource.util.Equal; public class OptionalAttribute extends SingleAttributeUse { private final Attribute attribute; private final String defaultValue; public OptionalAttribute(SourceLocation location, Annotation annotation, Attribute attribute, String defaultValue) { super(location, annotation); this.attribute = attribute; this.defaultValue = defaultValue; } public Attribute getAttribute() { return attribute; } public T accept(AttributeUseVisitor visitor) { return visitor.visitOptionalAttribute(this); } public Name getName() { return attribute.getName(); } public SimpleType getType() { return attribute.getType(); } public String getDefaultValue() { return defaultValue; } public boolean isOptional() { return true; } public boolean equals(Object obj) { return (super.equals(obj) && ((OptionalAttribute)obj).attribute.equals(attribute) && Equal.equal(defaultValue, ((OptionalAttribute)obj).defaultValue)); } public int hashCode() { int hc = super.hashCode() ^ attribute.hashCode(); if (defaultValue != null) hc ^= defaultValue.hashCode(); return hc; } } Particle.java000066400000000000000000000005111225366607500352730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public abstract class Particle extends Annotated { public Particle(SourceLocation location, Annotation annotation) { super(location, annotation); } public abstract T accept(ParticleVisitor visitor); } ParticleAll.java000066400000000000000000000006441225366607500357330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; public class ParticleAll extends ParticleGroup { public ParticleAll(SourceLocation location, Annotation annotation, List children) { super(location, annotation, children); } public T accept(ParticleVisitor visitor) { return visitor.visitAll(this); } } ParticleChoice.java000066400000000000000000000006551225366607500364170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; public class ParticleChoice extends ParticleGroup { public ParticleChoice(SourceLocation location, Annotation annotation, List children) { super(location, annotation, children); } public T accept(ParticleVisitor visitor) { return visitor.visitChoice(this); } } ParticleGroup.java000066400000000000000000000013361225366607500363160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; import java.util.Collections; public abstract class ParticleGroup extends Particle { private final List children; public ParticleGroup(SourceLocation location, Annotation annotation, List children) { super(location, annotation); this.children = Collections.unmodifiableList(children); } public List getChildren() { return children; } public boolean equals(Object obj) { return super.equals(obj) && ((ParticleGroup)obj).children.equals(children); } public int hashCode() { return super.hashCode() ^ getChildren().hashCode(); } } ParticleRepeat.java000066400000000000000000000016471225366607500364470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class ParticleRepeat extends Particle { private final Particle child; private final Occurs occurs; public ParticleRepeat(SourceLocation location, Annotation annotation, Particle child, Occurs occurs) { super(location, annotation); this.child = child; this.occurs = occurs; } public Particle getChild() { return child; } public Occurs getOccurs() { return occurs; } public T accept(ParticleVisitor visitor) { return visitor.visitRepeat(this); } public boolean equals(Object obj) { if (!super.equals(obj)) return false; ParticleRepeat other = (ParticleRepeat)obj; return this.child.equals(other.child) && this.occurs.equals(other.occurs); } public int hashCode() { return super.hashCode() ^ child.hashCode() ^ occurs.hashCode(); } } ParticleSequence.java000066400000000000000000000006631225366607500367740ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; public class ParticleSequence extends ParticleGroup { public ParticleSequence(SourceLocation location, Annotation annotation, List children) { super(location, annotation, children); } public T accept(ParticleVisitor visitor) { return visitor.visitSequence(this); } } ParticleVisitor.java000066400000000000000000000005211225366607500366540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface ParticleVisitor { T visitElement(Element p); T visitWildcardElement(WildcardElement p); T visitRepeat(ParticleRepeat p); T visitSequence(ParticleSequence p); T visitChoice(ParticleChoice p); T visitAll(ParticleAll p); T visitGroupRef(GroupRef p); } RootDeclaration.java000066400000000000000000000011221225366607500366200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class RootDeclaration extends Annotated implements TopLevel { private Particle particle; public RootDeclaration(SourceLocation location, Annotation annotation, Particle particle) { super(location, annotation); this.particle = particle; } public Particle getParticle() { return particle; } public void setParticle(Particle particle) { this.particle = particle; } public void accept(SchemaVisitor visitor) { visitor.visitRoot(this); } } Schema.java000066400000000000000000000076701225366607500347450ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; public class Schema extends Annotated { private final String uri; private final String encoding; private Schema parent; private final List topLevel = new Vector(); private final Map groupMap; private final Map attributeGroupMap; private final Map simpleTypeMap; private final List subSchemas; private final List leadingComments = new Vector(); private final List trailingComments = new Vector(); public Schema(SourceLocation location, Annotation annotation, String uri, String encoding) { super(location, annotation); this.uri = uri; this.encoding = encoding; this.groupMap = new HashMap(); this.attributeGroupMap = new HashMap(); this.simpleTypeMap = new HashMap(); this.subSchemas = new Vector(); this.subSchemas.add(this); } private Schema(SourceLocation location, Annotation annotation, String uri, String encoding, Schema parent) { super(location, annotation); this.parent = parent; this.uri = uri; this.encoding = encoding; this.groupMap = parent.groupMap; this.attributeGroupMap = parent.attributeGroupMap; this.simpleTypeMap = parent.simpleTypeMap; this.subSchemas = parent.subSchemas; this.subSchemas.add(this); } public String getUri() { return uri; } public String getEncoding() { return encoding; } public Schema getParent() { return parent; } public void defineGroup(String name, Particle particle, SourceLocation location, Annotation annotation) { GroupDefinition def = new GroupDefinition(location, annotation, this, name, particle); topLevel.add(def); groupMap.put(name, def); } public void defineAttributeGroup(String name, AttributeUse attributeUses, SourceLocation location, Annotation annotation) { AttributeGroupDefinition def = new AttributeGroupDefinition(location, annotation, this, name, attributeUses); topLevel.add(def); attributeGroupMap.put(name, def); } public void defineSimpleType(String name, SimpleType simpleType, SourceLocation location, Annotation annotation) { SimpleTypeDefinition def = new SimpleTypeDefinition(location, annotation, this, name, simpleType); topLevel.add(def); simpleTypeMap.put(name, def); } public void addRoot(Particle particle, SourceLocation location, Annotation annotation) { topLevel.add(new RootDeclaration(location, annotation, particle)); } public Schema addInclude(String uri, String encoding, SourceLocation location, Annotation annotation) { Schema included = new Schema(location, annotation, uri, encoding, this); topLevel.add(new Include(location, annotation, included)); return included; } public void addComment(String content, SourceLocation location) { topLevel.add(new Comment(location, content)); } public GroupDefinition getGroup(String name) { return groupMap.get(name); } public SimpleTypeDefinition getSimpleType(String name) { return simpleTypeMap.get(name); } public AttributeGroupDefinition getAttributeGroup(String name) { return attributeGroupMap.get(name); } public void accept(SchemaVisitor visitor) { for (TopLevel t : this.topLevel) t.accept(visitor); } public List getSubSchemas() { return subSchemas; } public List getLeadingComments() { return leadingComments; } public List getTrailingComments() { return trailingComments; } public boolean equals(Object obj) { return obj == this; } public int hashCode() { return System.identityHashCode(this); } } SchemaTransformer.java000066400000000000000000000161771225366607500371720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import java.util.List; import java.util.Vector; public class SchemaTransformer implements SchemaVisitor, ParticleVisitor, ComplexTypeVisitor, AttributeUseVisitor, SimpleTypeVisitor { private final Schema schema; public SchemaTransformer(Schema schema) { this.schema = schema; } public Schema getSchema() { return schema; } public void transform() { schema.accept(this); } public void visitGroup(GroupDefinition def) { def.setParticle(def.getParticle().accept(this)); } public void visitAttributeGroup(AttributeGroupDefinition def) { def.setAttributeUses(def.getAttributeUses().accept(this)); } public void visitSimpleType(SimpleTypeDefinition def) { def.setSimpleType(def.getSimpleType().accept(this)); } public void visitRoot(RootDeclaration decl) { decl.setParticle(decl.getParticle().accept(this)); } public void visitInclude(Include include) { include.getIncludedSchema().accept(this); } public void visitComment(Comment comment) { } public Particle visitRepeat(ParticleRepeat p) { Particle child = p.getChild().accept(this); if (child == p.getChild()) return p; return new ParticleRepeat(p.getLocation(), p.getAnnotation(), child, p.getOccurs()); } public Particle visitGroupRef(GroupRef p) { return p; } public Particle visitElement(Element p) { ComplexType ct = p.getComplexType().accept(this); if (ct == p.getComplexType()) return p; return new Element(p.getLocation(), p.getAnnotation(), p.getName(), ct); } public Particle visitWildcardElement(WildcardElement p) { return p; } public Particle visitSequence(ParticleSequence p) { List children = transformParticleList(p.getChildren()); if (children == p.getChildren()) return p; if (children.size() == 1) return children.get(0); if (children.size() == 0) return null; return new ParticleSequence(p.getLocation(), p.getAnnotation(), children); } public Particle visitChoice(ParticleChoice p) { List children = transformParticleList(p.getChildren()); if (children == p.getChildren()) return p; return new ParticleChoice(p.getLocation(), p.getAnnotation(), children); } public Particle visitAll(ParticleAll p) { List children = transformParticleList(p.getChildren()); if (children == p.getChildren()) return p; return new ParticleAll(p.getLocation(), p.getAnnotation(), children); } public ComplexType visitComplexContent(ComplexTypeComplexContent t) { Particle particle = t.getParticle(); AttributeUse attributeUses = t.getAttributeUses().accept(this); if (particle != null) particle = particle.accept(this); if (particle == t.getParticle() && attributeUses == t.getAttributeUses()) return t; return new ComplexTypeComplexContent(attributeUses, particle, t.isMixed()); } public ComplexType visitSimpleContent(ComplexTypeSimpleContent t) { SimpleType simpleType = t.getSimpleType().accept(this); AttributeUse attributeUses = t.getAttributeUses().accept(this); if (simpleType == t.getSimpleType() && attributeUses == t.getAttributeUses()) return t; return new ComplexTypeSimpleContent(attributeUses, simpleType); } public ComplexType visitNotAllowedContent(ComplexTypeNotAllowedContent t) { return t; } public AttributeUse visitAttribute(Attribute a) { SimpleType type = a.getType(); if (type != null) { type = type.accept(this); if (type == null || type != a.getType()) return new Attribute(a.getLocation(), a.getAnnotation(), a.getName(), type); } return a; } public AttributeUse visitWildcardAttribute(WildcardAttribute a) { return a; } public AttributeUse visitAttributeGroupRef(AttributeGroupRef a) { return a; } public AttributeUse visitOptionalAttribute(OptionalAttribute a) { Attribute attribute = (Attribute)a.getAttribute().accept(this); if (attribute == a.getAttribute()) return a; return new OptionalAttribute(a.getLocation(), a.getAnnotation(), attribute, a.getDefaultValue()); } public AttributeUse visitAttributeGroup(AttributeGroup a) { List children = transformAttributeUseList(a.getChildren()); if (children == a.getChildren()) return a; return new AttributeGroup(a.getLocation(), a.getAnnotation(), children); } public AttributeUse visitAttributeUseChoice(AttributeUseChoice a) { List children = transformAttributeUseList(a.getChildren()); if (children == a.getChildren()) return a; return new AttributeUseChoice(a.getLocation(), a.getAnnotation(), children); } public SimpleType visitRestriction(SimpleTypeRestriction t) { return t; } public SimpleType visitUnion(SimpleTypeUnion t) { List children = transformSimpleTypeList(t.getChildren()); if (children == t.getChildren()) return t; return new SimpleTypeUnion(t.getLocation(), t.getAnnotation(), children); } public SimpleType visitList(SimpleTypeList t) { SimpleType itemType = t.getItemType().accept(this); if (itemType == t.getItemType()) return t; return new SimpleTypeList(t.getLocation(), t.getAnnotation(), itemType, t.getOccurs()); } public SimpleType visitRef(SimpleTypeRef t) { return t; } public List transformAttributeUseList(List list) { List transformed = null; for (int i = 0, len = list.size(); i < len; i++) { AttributeUse use = list.get(i).accept(this); if (transformed != null) transformed.add(use); else if (use != list.get(i)) { transformed = new Vector(); for (int j = 0; j < i; j++) transformed.add(list.get(j)); if (!use.equals(AttributeGroup.EMPTY)) transformed.add(use); } } if (transformed == null) return list; return transformed; } public List transformParticleList(List list) { List transformed = null; for (int i = 0, len = list.size(); i < len; i++) { Particle p = list.get(i).accept(this); if (transformed != null) { if (p != null) transformed.add(p); } else if (p != list.get(i)) { transformed = new Vector(); for (int j = 0; j < i; j++) transformed.add(list.get(j)); if (p != null) transformed.add(p); } } if (transformed == null) return list; return transformed; } public List transformSimpleTypeList(List list) { List transformed = null; for (int i = 0, len = list.size(); i < len; i++) { SimpleType st = list.get(i).accept(this); if (transformed != null) transformed.add(st); else if (st != list.get(i)) { transformed = new Vector(); for (int j = 0; j < i; j++) transformed.add(list.get(j)); transformed.add(st); } } if (transformed == null) return list; return transformed; } } SchemaVisitor.java000066400000000000000000000005411225366607500363130ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface SchemaVisitor { void visitGroup(GroupDefinition def); void visitAttributeGroup(AttributeGroupDefinition def); void visitSimpleType(SimpleTypeDefinition def); void visitRoot(RootDeclaration decl); void visitInclude(Include include); void visitComment(Comment comment); } SchemaWalker.java000066400000000000000000000062141225366607500361040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.util.VoidValue; public abstract class SchemaWalker implements ParticleVisitor, SimpleTypeVisitor, SchemaVisitor, ComplexTypeVisitor, AttributeUseVisitor { public VoidValue visitElement(Element p) { return p.getComplexType().accept(this); } public VoidValue visitWildcardElement(WildcardElement p) { return VoidValue.VOID; } public VoidValue visitRepeat(ParticleRepeat p) { return p.getChild().accept(this); } public VoidValue visitSequence(ParticleSequence p) { return visitGroup(p); } public VoidValue visitChoice(ParticleChoice p) { return visitGroup(p); } public VoidValue visitAll(ParticleAll p) { return visitGroup(p); } public VoidValue visitGroup(ParticleGroup p) { for (Particle child : p.getChildren()) child.accept(this); return VoidValue.VOID; } public VoidValue visitGroupRef(GroupRef p) { return VoidValue.VOID; } public VoidValue visitRestriction(SimpleTypeRestriction t) { return VoidValue.VOID; } public VoidValue visitUnion(SimpleTypeUnion t) { for (SimpleType child : t.getChildren()) child.accept(this); return VoidValue.VOID; } public VoidValue visitList(SimpleTypeList t) { return t.getItemType().accept(this); } public VoidValue visitRef(SimpleTypeRef t) { return VoidValue.VOID; } public void visitGroup(GroupDefinition def) { def.getParticle().accept(this); } public void visitAttributeGroup(AttributeGroupDefinition def) { def.getAttributeUses().accept(this); } public VoidValue visitAttribute(Attribute a) { if (a.getType() == null) return VoidValue.VOID; return a.getType().accept(this); } public VoidValue visitWildcardAttribute(WildcardAttribute a) { return VoidValue.VOID; } public VoidValue visitOptionalAttribute(OptionalAttribute a) { return a.getAttribute().accept(this); } public VoidValue visitAttributeGroupRef(AttributeGroupRef a) { return VoidValue.VOID; } public VoidValue visitAttributeGroup(AttributeGroup a) { for (AttributeUse child : a.getChildren()) child.accept(this); return VoidValue.VOID; } public VoidValue visitAttributeUseChoice(AttributeUseChoice a) { return visitAttributeGroup(a); } public void visitSimpleType(SimpleTypeDefinition def) { def.getSimpleType().accept(this); } public void visitRoot(RootDeclaration decl) { decl.getParticle().accept(this); } public void visitInclude(Include include) { include.getIncludedSchema().accept(this); } public void visitComment(Comment comment) { } public VoidValue visitComplexContent(ComplexTypeComplexContent t) { t.getAttributeUses().accept(this); if (t.getParticle() == null) return VoidValue.VOID; return t.getParticle().accept(this); } public VoidValue visitSimpleContent(ComplexTypeSimpleContent t) { t.getAttributeUses().accept(this); return t.getSimpleType().accept(this); } public VoidValue visitNotAllowedContent(ComplexTypeNotAllowedContent t) { return VoidValue.VOID; } } SimpleType.java000066400000000000000000000005171225366607500356310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public abstract class SimpleType extends Annotated { public SimpleType(SourceLocation location, Annotation annotation) { super(location, annotation); } public abstract T accept(SimpleTypeVisitor visitor); } SimpleTypeDefinition.java000066400000000000000000000012411225366607500376350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class SimpleTypeDefinition extends Definition { private SimpleType simpleType; public SimpleTypeDefinition(SourceLocation location, Annotation annotation, Schema parentSchema, String name, SimpleType simpleType) { super(location, annotation, parentSchema, name); this.simpleType = simpleType; } public SimpleType getSimpleType() { return simpleType; } public void setSimpleType(SimpleType simpleType) { this.simpleType = simpleType; } public void accept(SchemaVisitor visitor) { visitor.visitSimpleType(this); } } SimpleTypeList.java000066400000000000000000000017121225366607500364630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class SimpleTypeList extends SimpleType { private final SimpleType itemType; private final Occurs occurs; public SimpleTypeList(SourceLocation location, Annotation annotation, SimpleType itemType, Occurs occurs) { super(location, annotation); this.itemType = itemType; this.occurs = occurs; } public SimpleType getItemType() { return itemType; } public Occurs getOccurs() { return occurs; } public T accept(SimpleTypeVisitor visitor) { return visitor.visitList(this); } public boolean equals(Object obj) { if (!super.equals(obj)) return false; SimpleTypeList other = (SimpleTypeList)obj; return this.itemType.equals(other.itemType) && this.occurs.equals(other.occurs); } public int hashCode() { return super.hashCode() ^ itemType.hashCode() ^ occurs.hashCode(); } } SimpleTypeRef.java000066400000000000000000000012401225366607500362600ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class SimpleTypeRef extends SimpleType { private final String name; public SimpleTypeRef(SourceLocation location, Annotation annotation, String name) { super(location, annotation); this.name = name; } public String getName() { return name; } public T accept(SimpleTypeVisitor visitor) { return visitor.visitRef(this); } public boolean equals(Object obj) { return super.equals(obj) && ((SimpleTypeRef)obj).name.equals(name); } public int hashCode() { return super.hashCode() ^ name.hashCode(); } } SimpleTypeRestriction.java000066400000000000000000000021751225366607500400610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; import java.util.Collections; public class SimpleTypeRestriction extends SimpleType { private final String name; private final List facets; public SimpleTypeRestriction(SourceLocation location, Annotation annotation, String name, List facets) { super(location, annotation); this.name = name; this.facets = Collections.unmodifiableList(facets); } /** * Name is the name of a builtin simple type. * facets is a list of facets */ public String getName() { return name; } public List getFacets() { return facets; } public T accept(SimpleTypeVisitor visitor) { return visitor.visitRestriction(this); } public boolean equals(Object obj) { if (!super.equals(obj)) return false; SimpleTypeRestriction other = (SimpleTypeRestriction)obj; return this.name.equals(other.name) && this.facets.equals(other.facets); } public int hashCode() { return super.hashCode() ^ name.hashCode() ^ facets.hashCode(); } } SimpleTypeUnion.java000066400000000000000000000014761225366607500366470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import java.util.List; import java.util.Collections; public class SimpleTypeUnion extends SimpleType { private final List children; public SimpleTypeUnion(SourceLocation location, Annotation annotation, List children) { super(location, annotation); this.children = Collections.unmodifiableList(children); } public List getChildren() { return children; } public T accept(SimpleTypeVisitor visitor) { return visitor.visitUnion(this); } public boolean equals(Object obj) { return super.equals(obj) && children.equals(((SimpleTypeUnion)obj).children); } public int hashCode() { return super.hashCode() ^ children.hashCode(); } } SimpleTypeVisitor.java000066400000000000000000000003621225366607500372070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface SimpleTypeVisitor { T visitRestriction(SimpleTypeRestriction t); T visitUnion(SimpleTypeUnion t); T visitList(SimpleTypeList t); T visitRef(SimpleTypeRef t); } SingleAttributeUse.java000066400000000000000000000007701225366607500373210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.xml.util.Name; public abstract class SingleAttributeUse extends AttributeUse { public SingleAttributeUse(SourceLocation location, Annotation annotation) { super(location, annotation); } public abstract Name getName(); public abstract SimpleType getType(); public abstract boolean isOptional(); public String getDefaultValue() { return null; } } Structure.java000066400000000000000000000002761225366607500355400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.xml.util.Name; public interface Structure { Name getName(); T accept(StructureVisitor visitor); } StructureVisitor.java000066400000000000000000000002531225366607500371130ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface StructureVisitor { T visitElement(Element element); T visitAttribute(Attribute attribute); } TopLevel.java000066400000000000000000000001721225366607500352650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; public interface TopLevel { void accept(SchemaVisitor visitor); } Wildcard.java000066400000000000000000000050311225366607500352630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.xml.util.Name; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class Wildcard { private final boolean positive; private final Set namespaces; private final Set excludedNames; public Wildcard(boolean positive, Set namespaces, Set excludedNames) { this.positive = positive; this.namespaces = Collections.unmodifiableSet(namespaces); this.excludedNames = Collections.unmodifiableSet(excludedNames); } public boolean isPositive() { return positive; } public Set getNamespaces() { return namespaces; } public Set getExcludedNames() { return excludedNames; } public boolean equals(Object obj) { if (!(obj instanceof Wildcard)) return false; Wildcard other = (Wildcard)obj; return (this.positive == other.positive && this.namespaces.equals(other.namespaces) && this.excludedNames.equals(other.excludedNames)); } public int hashCode() { return namespaces.hashCode() ^ excludedNames.hashCode(); } public boolean contains(Name name) { return namespaces.contains(name.getNamespaceUri()) == positive && !excludedNames.contains(name); } public static Wildcard union(Wildcard wc1, Wildcard wc2) { boolean positive; Set namespaces = new HashSet(); if (wc1.isPositive() && wc2.isPositive()) { positive = true; namespaces.addAll(wc1.getNamespaces()); namespaces.addAll(wc2.getNamespaces()); } else { positive = false; if (!wc1.isPositive() && !wc2.isPositive()) { namespaces.addAll(wc1.getNamespaces()); namespaces.retainAll(wc2.getNamespaces()); } else if (!wc1.isPositive()) { namespaces.addAll(wc1.getNamespaces()); namespaces.removeAll(wc2.getNamespaces()); } else { namespaces.addAll(wc2.getNamespaces()); namespaces.removeAll(wc1.getNamespaces()); } } Set excludedNames = new HashSet(); addExcludedNames(excludedNames, wc1, wc2); addExcludedNames(excludedNames, wc2, wc1); return new Wildcard(positive, namespaces, excludedNames); } /** * Add to result all members of the excludedNames of wc1 that are not contained in wc2. */ private static void addExcludedNames(Set result, Wildcard wc1, Wildcard wc2) { for (Name name : wc1.getExcludedNames()) { if (!wc2.contains(name)) result.add(name); } } } WildcardAttribute.java000066400000000000000000000013501225366607500371470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class WildcardAttribute extends AttributeUse { private final Wildcard wildcard; public WildcardAttribute(SourceLocation location, Annotation annotation, Wildcard wildcard) { super(location, annotation); this.wildcard = wildcard; } public Wildcard getWildcard() { return wildcard; } public boolean equals(Object obj) { return super.equals(obj) && ((WildcardAttribute)obj).wildcard.equals(wildcard); } public int hashCode() { return super.hashCode() ^ wildcard.hashCode(); } public T accept(AttributeUseVisitor visitor) { return visitor.visitWildcardAttribute(this); } } WildcardElement.java000066400000000000000000000013301225366607500365730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/basicpackage com.thaiopensource.relaxng.output.xsd.basic; import com.thaiopensource.relaxng.edit.SourceLocation; public class WildcardElement extends Particle { private final Wildcard wildcard; public WildcardElement(SourceLocation location, Annotation annotation, Wildcard wildcard) { super(location, annotation); this.wildcard = wildcard; } public Wildcard getWildcard() { return wildcard; } public boolean equals(Object obj) { return super.equals(obj) && ((WildcardElement)obj).wildcard.equals(wildcard); } public int hashCode() { return super.hashCode() ^ wildcard.hashCode(); } public T accept(ParticleVisitor visitor) { return visitor.visitWildcardElement(this); } } resources/000077500000000000000000000000001225366607500336215ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsdMessages.properties000066400000000000000000000043371225366607500375150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/src/main/com/thaiopensource/relaxng/output/xsd/resourcesunsupported_datatype_library=cannot convert datatype library \"{0}\"; using datatype \"string\" undefined_reference=reference to undefined pattern \"{0}\" recursive_reference=illegal recursion through pattern \"{0}\" external_ref_not_supported=sorry, externalRef is not yet supported nested_grammar_not_supported=sorry, nested grammars are not yet supported parent_ref_no_grammar=parent reference with no applicable grammar missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything multiple_define=multiple definitions of \"{0}\" without \"combine\" attribute inconsistent_combine=inconsistent \"combine\" attributes for definition of \"{0}\" include_loop=infinite loop including URI \"{0}\" multiple_include=sorry, not supported: URI \"{0}\" included more than once any_name_attribute_not_repeated=\"attribute\" using \"anyName\" must be repeated ns_name_attribute_not_repeated=\"attribute\" using \"nsName\" must be repeated illegal_contains=restriction violation: {0} contains \"{1}\" not_in_list=\"{0}\" can contain typed data only inside a list group_data_other_children=\"{0}\" cannot combine typed data with text or elements group_data=grouping data is only allowed inside list interleave_data=typed data cannot be combined with \"interleave\" mixed_data=\"mixed\" cannot be applied to typed data attribute_child_choice=choice between attributes and children cannot be represented; approximating wildcard_attribute_value=cannot represent restriction on value of attributes matching wildcard; approximating wildcard_attribute_optional=cannot represent required wildcard attribute; approximating optional_attribute_group=cannot represent an optional group of attributes; approximating list_contains_text=a list pattern must not contain a text pattern list_contains_element=a list pattern must not contain an element pattern list_contains_attribute=a list pattern must not contain an attribute pattern # Contexts element_repeat_group=\"group\" inside \"oneOrMore\" or \"zeroOrMore\" element_repeat_interleave=\"interleave\" inside \"oneOrMore\" or \"zeroOrMore\" attribute=\"attribute\" list=\"list\" data_except=\"except\" in \"data\" start =\"start\" jing-trang-20131210+dfsg+1/mod/convert-to-xsd/test/000077500000000000000000000000001225366607500215265ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/convert-to-xsd/test/toxsdtest.xml000066400000000000000000002762151225366607500243260ustar00rootroot00000000000000 foo = xsd:token foo = xsd:token { minLength = "2" maxLength = "17" } foo = "stuff" foo = xsd:integer "1" | xsd:integer "2" foo = xsd:integer "1" | xsd:double "1.0" foo = list { xsd:int* } foo = list { xsd:int+ } foo = list { xsd:int, xsd:int+ } foo = list { empty } foo = list { notAllowed } | xsd:int foo = empty, xsd:int foo = xsd:int* foo = element foo { empty } foo = element foo { attribute bar { xsd:double }, (xsd:int | xsd:boolean) } foo = element foo { bar } bar = xsd:int | xsd:boolean bar = element bar { foo } foo = attribute foo { xsd:double } | element foo { xsd:double } start = foo foo = element foo { empty } start = root root = foo|bar foo = element foo { empty } bar = element bar { empty } element foo { empty } | element bar { empty } bar = element bar { empty } baz = element baz { empty } foo = element foo { bar | baz } include "bar.rnc" namespace eg = "http://www.example.com" element eg:foo { empty } default namespace = "http://www.example.com" element foo { empty } start = element foo { empty } default namespace = "http://www.example.com" include "foo.rnc" namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" element e1:x { element e2:y { empty } } namespace e1 = "http://www.example.com/1" element e1:x { element y { empty } } namespace e1 = "http://www.example.com/1" element e1:x { element y { element e1:z { empty } } } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" element e1:x { element e2:y { element e1:z { empty } } } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" element e1:x { empty } | element e2:y { empty } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" start = x | y x = element e1:x { y? } y = element e2:y { x? } namespace e1 = "http://www.example.com/1" element e1:x { attribute e1:a { text } } namespace e1 = "http://www.example.com/1" element x { empty } | element e1:y { empty } namespace eg = "http://www.example.com" start = element eg:y { x } x = element x { empty } include "example.rnc" namespace eg = "http://www.example.com" element x { attribute eg:y { text } } element foo|bar|baz { empty } start = root root = element foo|bar|baz { empty } element foo { attribute bar|baz { text } } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" element e1:x { element e2:y|e2:z { element e2:y { empty } } } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" namespace e3 = "http://www.example.com/3" element e1:x { element e2:y|e3:z { element e1:x|e1:v { empty } } } | element e1:w { element e2:y { text } } namespace e1 = "http://www.example.com/1" namespace e2 = "http://www.example.com/2" element e1:x { element e1:x|e2:y { element e1:x|e2:y { empty } } } start = element foo { bar } bar = element bar { bar* } element foo { attribute xml:lang { xsd:language } } | element bar { attribute xml:lang { xsd:language } } element foo { attribute bar { text }, xsd:float } start = element foo { int|double|float } int = attribute type { "int" }, xsd:int double = attribute type { "double" }, xsd:double float = attribute type { "float" }, xsd:float start = element foo { atts } | element bar { atts? } atts = attribute a1 { text }, more-atts more-atts = attribute a2 { text }? element foo { attribute bar { text } | attribute bar { xsd:float } } start = element foo { bar1 | bar2 } bar1 = attribute bar { text }, attribute baz1 { text }? bar2 = attribute bar { xsd:float }, attribute baz2 { text }? namespace eg = "http://www.example.com" namespace local = "" element eg:foo { attribute * - (eg:*|local:*) { text }* } namespace eg1 = "http://www.example.com/1" namespace eg2 = "http://www.example.com/2" start = element foo { eg1, eg2 } eg1 = attribute eg1:* { text } * eg2 = attribute eg2:* { text } * namespace eg1 = "http://www.example.com/1" namespace eg2 = "http://www.example.com/2" start = element foo { eg1, eg2 } eg1 = attribute eg1:*|eg2:* { text } * eg2 = attribute eg2:* { text } * namespace eg1 = "http://www.example.com/1" namespace eg2 = "http://www.example.com/2" start = element foo { eg1, eg2 } eg1 = attribute eg1:* { text } * eg2 = attribute eg1:*|eg2:* { text } * element foo { attribute * - bar { text }+, attribute bar { xsd:float } } namespace eg = "http://www.example.com" namespace local = "" element eg:foo { attribute * - (local:*|(eg:* - eg:bar)) { xsd:float }* } element foo { attribute * { text }* | attribute bar { xsd:string } } element foo { attribute * - bar { text }* | attribute bar { xsd:float } } namespace eg = "http://www.example.com" element foo { attribute eg:* { text }* | attribute bar { xsd:float } | attribute eg:bar { xsd:float } } element foo { element * { text } } foo2 = element foo2 { bar } namespace e2 = "http://www.example.com/2" bar = element e2:bar1 { element baz { empty } } | element e2:bar2 { element baz { text } } default namespace = "http://www.example.com/1" include "eg1.rnc" include "eg2.rnc" start = element foo1 { bar } | foo2 namespace eg1 = "http://www.example.com/1" namespace eg2 = "http://www.example.com/2" namespace eg3 = "http://www.example.com/3" element eg2:foo { element * - eg1:* { text }, element * - eg2:* { text }, element * - eg3:* { text } } datatypes x = "http://x.org" element foo { x:bar { pattern = "[a-zA-Z]*" } } element foo { attribute bar { xsd:integer? } } element foo { attribute bar { empty } } element foo { xsd:float? } element foo { attribute bar { text }, xsd:float? } element foo { notAllowed } namespace eg = "http://www.example.com" element eg:foo { element bar { notAllowed } | element baz { text } } element foo { attribute format { xsd:NOTATION "bar" }, text } element foo { attribute format { xsd:NOTATION }, text } element foo { xsd:QName "xyzzy" } default namespace = "http://www.example.com" element foo { xsd:QName "xyzzy" } namespace eg = "http://www.example.com" element foo { xsd:QName "eg:xyzzy" } namespace xs = "http://www.example.com" element foo { xsd:QName "xs:xyzzy" } element foo { xsd:QName "xyzzy" } start = element foo { x } x = element bar { empty }, x? start = element foo { empty } x = element bar { empty }, x? start = element foo { x } y = element bar { z } element foo { empty } externalRef "x.rnc" start = grammar { start = element foo { empty } } start = element foo { parent x } x = empty start = element foo { empty } include "foo.rnc" { start = element foo { text } } element foo { xsd:no-such-datatype } | element bar { xsd:string { pattrn = "[a-zA-Z]+" } } | element baz { xsd:string { maxLength = "2in" } } start = element foo { xsd:gdday-bruce } include "bad.rnc" element foo { empty } include "bad.rnc" start = element foo { xsd:gdday-bruce } include "bad.rnc" inline = element em { text } inline |= element code { text } inline = element b { text } inline = element em { text } inline |= element code { text } inline |= element code { text } inline = element em { text } inline |= element code { text } inline = element em { text } inline |= element b { text } include "foo.rnc" include "foo.rnc" foo |= element foo { empty } include "foo.rnc" include "foo.rnc" , except that # John Cowan retains the moral right to be known as the author. # This is draft 6.2 # Diff from 6.1: rel|rel now rel|rev, th|td@headers now IDREFS, # table width no longer an integer, non-basic table attrs gone, # rowspan and colspan must be non-negative # Diff from 6.0: added attributes to ul, comment about img, new meta # This is a RELAX NG schema which describes a subset of XHTML Basic for # use within other schemas. It is by intention equivalent # (within its scope) to -//W3C//DTD XHTML 1.1//EN, but is # not a derived work in the copyright sense. # It is often convenient for XML documents to have a bit of # documentation somewhere in them. In the absence of a schema like # this one, that documentation winds up being only, which is # a pity, because rich text adds measurably to the readability of # documents. By incorporating this schema by reference (as an # external parameter entity) into another schema, that schema inherits # the capabilities of this one. Using HTML-compatible elements # and attributes allows the documentation to be passed straight # through to HTML renderers. # Current HTML renderers can cope with most XML tags, but empty # tags require special treatment. Inserting a space before the # terminating "/>" usually makes the "/" (which is not HTML) # invisible. Using "" is not as effective, as the # latter is often misinterpreted as a second "". # Note that since the elements of this schema are intended to be # used within domain-specific elements of the surrounding DTD, # it is not necessary that every fragment begin with an "html" # element, as in HTML. Recommended s for elements # containing documentation are "horiz.model" for simple # text fragments and "struct.model" for documents in extenso. # Declarations datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" # Common attributes # All elements (except full-document elements) can have these attributes all = attribute id {xsd:ID}?, attribute class {token}?, attribute title {text}? # All non-empty elements can have these attributes i18n = attribute xml:lang {text}?, attribute dir {"ltr" | "rtl"}? basic = all, i18n # Models t = text horiz.model = basic & t & horiz* vert.model = basic & t & (horiz|vert)* struct.model = basic & vert* # Horizontal formatting elements horiz = a | br | horiz.other a = element a { attribute href {xsd:anyURI}?, attribute name {text}?, attribute rel | rev {xsd:anyURI}?, horiz.model } br = element br {all, empty} horiz.other = element abbr | acronym | cite | code | dfn | em | img | kbd | q | samp | span | strong | var {horiz.model} # Vertical formatting elements vert = header | List | table | vert.other header = element h1 | h2 | h3 {horiz.model} List = element dl {basic, element dt | dd {horiz.model}+ } | element ol|ul {basic, element li {horiz.model}+ } aligns = attribute align {"left" | "center" | "right" | "justified"}?, attribute valign {"top" | "middle" | "bottom" | "baseline"}? table = element table { basic, attribute summary {text}?, element caption {horiz.model}?, element tr { basic, aligns, tabledata+}+ } tabledata = element th | td { aligns, attribute abbr {text}?, attribute axis {text}?, attribute colspan {xsd:nonNegativeInteger}?, attribute headers {xsd:IDREFS}?, attribute rowspan {xsd:nonNegativeInteger}?, attribute scope {"row" | "col" | "rowgroup" | "colgroup"}?, vert.model } vert.other = element address {horiz.model} | element blockquote {attribute cite {xsd:anyURI}?, struct.model} | element div {struct.model} | element p {horiz.model} | element pre {horiz.model} # Support for complete HTML documents start = element html { i18n, attribute xml:base {xsd:anyURI}?, attribute xml:space {"preserve" | "default"}?, head, element body {basic, vert*} } head = element head { i18n, element title {i18n, text}, element meta { attribute name|http-equiv {token}?, attribute content {text}, empty }* } # END OF ibtwsh.rnc ]]> start = element foo { t } | element bar { t, attribute baz { text }? } t = attribute x { text }, xsd:float foo = element foo { bar } bar = element bar { text }* baz = element baz { bar, element xyzzy { text }* } foo = attribute foo { attribute bar { text } } foo = element foo { empty }, xsd:float start = attribute foo { text } start = element foo { text }? element foo { xsd:float, xsd:float } element foo { xsd:float* } foo = xsd:float* element foo { attribute bar { text } | element bar { text } } element foo { attribute bar { text } | text } element foo { attribute bar { text } | xsd:float } element foo { (attribute bar { text }, element bar { empty }) | attribute baz { text } } element foo { attribute * { xsd:float }* } start = element foo { attribute * { x }* } x = xsd:normalizedString element foo { attribute * { text } } element foo { attribute * { text }+ } element foo { (attribute bar { text }, attribute baz { text })? } ## This is a foo. element foo { empty } This is a foo. element foo { ## This is a bar. attribute bar { text } } This is a bar. element foo { ## The third random name. "baz" } The third random name. ## An x. x = element foo|bar { empty } An x. #0 grammar { #1 foo [] #2 div { #3 foo [] #4 foo = element foo { empty } } #5 foo[] #6 } #7 namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" element foo { [ a:defaultValue="xyzzy" ] attribute bar { text }? } namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" element foo { [ a:defaultValue="en" ] attribute xml:lang { xsd:language }? } value = element large { xsd:long } | element medium { xsd:int } | element small { xsd:short } value = element large { xsd:double } | element medium { xsd:int } | element small { xsd:short } c = element x { t, attribute att { text } } | element y { t } t = xsd:int c = element x { xsd:int, attribute att { text } } | element y { xsd:int } c = element x { t, attribute att { text } } | element y { t } t = element z { empty }* a = element z { empty }* b = a, attribute att { text } c = element x { a } | element y { b } a = element z { empty }* b = attribute att { text } c = element x { a } | element y { b } start = element e { a* } | element f { b* } a = element x | y | z { element v { empty }* } b = element x | y | z { element w { empty }* } element foo { list { xsd:int* } } c = element x { xsd:int { maxInclusive = "72" } } | element y { xsd:int } x = xsd:int y = x z = y c = element a { x } | element b { z } x = xsd:int y = x, attribute att { text } z = y c = element a { x } | element b { z } x = xsd:int, attribute att1 { text } y = xsd:int, attribute att2 { text } c = element a { x } | element b { y } element foo { attribute att { text } | attribute att { text }? } element foo { attribute att1 { text } | attribute att1 { string } | attribute att2 { text }? } jing-trang-20131210+dfsg+1/mod/convert-to-xsd/todo.txt000066400000000000000000000101631225366607500222560ustar00rootroot00000000000000Avoid making all element declarations global. We can get (x | (y | z)) if (y|z) was a name class. Simplify into x|y|z. Check for duplicate attributes. Check for violations of RELAX NG interleave restriction. Approximation warnings: - interleave - mixed text - list containing a group of two non-empty tokens - element wildcard with content that does not allow everything - wildcards with two or more negative namespaces - wildcards with negative single names - choice between attributes - choice between elements and data Provide annotation to control which target namespace is assigned to a file. Take advantage of minOccurs > 1 and 1 < maxOccurs < infinity. If expansion of a group causes the group to become unreferenced, then remove the group. If define referenced only in something that is unreachable because of notAllowed, remove the define. Use complexTypes for groups and simpleTypes with associated attributes, even if not all references can make use of them. Use the last component of the namespace URI in selecting prefix and generated schema file when no prefix is used in the RELAX NG. Try using default namespace declaration to refer to things in targetNamespace. Make choice of targetNamespace not depend on order of hash table iteration. Handle nested grammars (use different namespace for different grammars). Preserve definitions that are equivalent to empty or notAllowed. A define whose pattern is equivalent to notAllowed should be preserved in the intermediate form, since it may correspond to the abstract head of a substitution group (probably need an annotation to control this). Handle externalRef (remember problem with parentRef in externalRef) Interleave - Avoid introducing ambiguities when approximating , eg x & (y, y). - Optimize nested choices in expanding . - Optimize eg x* & (a, b, c) into x*, (a, x*), (b, x*), (c, x*) For a , map to NOTATION and generate an appropriate xs:notation declaration based on annotations. Deal with xsi attributes. Better support for combine="choice". Now that element substitution groups are supported, combine="choice" can be supported much better. Intermediate form needs support for combine="choice". If a combine="choice" turns out to be substitution group, then there's no problem. Otherwise we can distinguish three cases: - same file: choose one to be the main definition; for the others two strategies: (a) move into the main (b) modify the name and add reference to it to the main definition - same file, different target namespace: preserve separate definitions; either generate new definition in different namespace to combine them or choose on of the target namespaces to be the main one - same file, same target namespace: files are related by include; try to use redefine; can combine two definitions from include parent and include descendant, not two definitions from two include children; in this case, rename defines in childen and add define to parent. Deal with annotations (provide special support for xs:key/xs:keyRef/xs:unique). Better support for xsd:documentation: - copy xsd:documentation annotations - copy xml:lang attribute from a:documentation elements - allow multiple a:documentation elements Be more careful about preserving annotations. Deal with element type consistent restriction Deal with ambiguous content model restriction Avoid redundant imports and redundant namespace declarations. With combine attributes, maybe insert to preserve file structure. Deal with repeated inclusions of same file, by expanding. Add an annotation on elements to convey info. Handle the case where the head of a substitution group should be a non-abstract element (remember to deal with type derivation restriction). Deal with non top-level commments. Annotations to control block and final attributes. Consider turning attribute groups (without paired group or simple type) into complex type. Map element with only content onto element with simple type of string (or at least provide option for this). Option to strip prefix or suffix (e.g. suffix ".att") so as to take advantage of XSD's multiple namespaces. jing-trang-20131210+dfsg+1/mod/datatype/000077500000000000000000000000001225366607500174665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/mod.xml000066400000000000000000000000731225366607500207670ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/datatype/src/000077500000000000000000000000001225366607500202555ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/000077500000000000000000000000001225366607500212015ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/com/000077500000000000000000000000001225366607500217575ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/com/thaiopensource/000077500000000000000000000000001225366607500250075ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/com/thaiopensource/datatype/000077500000000000000000000000001225366607500266225ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/com/thaiopensource/datatype/Datatype2.java000066400000000000000000000002261225366607500313220ustar00rootroot00000000000000package com.thaiopensource.datatype; import org.relaxng.datatype.Datatype; public interface Datatype2 extends Datatype { boolean alwaysValid(); } DatatypeLibraryLoader.java000066400000000000000000000017441225366607500336430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/com/thaiopensource/datatypepackage com.thaiopensource.datatype; import com.thaiopensource.util.Service; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.DatatypeLibraryFactory; import java.util.Iterator; // We use this instead of the one in org.relaxng.datatype.helper because tools.jar in Java 6 includes // org.relaxng.datatype, which messes up class loading for the jing task in Ant, when Ant's class loader's // parent will have tools.jar in its classpath. public class DatatypeLibraryLoader implements DatatypeLibraryFactory { private final Service service = Service.newInstance(DatatypeLibraryFactory.class); public DatatypeLibrary createDatatypeLibrary(String uri) { for (Iterator iter = service.getProviders(); iter.hasNext();) { DatatypeLibraryFactory factory = iter.next(); DatatypeLibrary library = factory.createDatatypeLibrary(uri); if (library != null) return library; } return null; } } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/000077500000000000000000000000001225366607500217705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/000077500000000000000000000000001225366607500234305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/000077500000000000000000000000001225366607500252435ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/Datatype.java000066400000000000000000000171311225366607500276640ustar00rootroot00000000000000package org.relaxng.datatype; /** * Datatype object. * * This object has the following functionality: * *
      *
    1. functionality to identify a class of character sequences. This is * done through the isValid method. * *
    2. functionality to produce a "value object" from a character sequence and * context information. * *
    3. functionality to test the equality of two value objects. *
    * * This interface also defines the createStreamingValidator method, * which is intended to efficiently support the validation of * large character sequences. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface Datatype { /** * Checks if the specified 'literal' matches this Datatype * with respect to the current context. * * @param literal * the lexical representation to be checked. * @param context * If this datatype is context-dependent * (i.e. the {@link #isContextDependent} method returns true), * then the caller must provide a non-null valid context object. * Otherwise, the caller can pass null. * * @return * true if the 'literal' is a member of this Datatype; * false if it's not a member of this Datatype. */ boolean isValid( String literal, ValidationContext context ); /** * Similar to the isValid method but throws an exception with diagnosis * in case of errors. * *

    * If the specified 'literal' is a valid lexical representation for this * datatype, then this method must return without throwing any exception. * If not, the callee must throw an exception (with diagnosis message, * if possible.) * *

    * The application can use this method to provide detailed error message * to users. This method is kept separate from the isValid method to * achieve higher performance during normal validation. * * @exception DatatypeException * If the given literal is invalid, then this exception is thrown. * If the callee supports error diagnosis, then the exception should * contain a diagnosis message. */ void checkValid( String literal, ValidationContext context ) throws DatatypeException; /** * Creates an instance of a streaming validator for this type. * *

    * By using streaming validators instead of the isValid method, * the caller can avoid keeping the entire string, which is * sometimes quite big, in memory. * * @param context * If this datatype is context-dependent * (i.e. the {@link #isContextDependent} method returns true), * then the caller must provide a non-null valid context object. * Otherwise, the caller can pass null. * The callee may keep a reference to this context object * only while the returned streaming validator is being used. */ DatatypeStreamingValidator createStreamingValidator( ValidationContext context ); /** * Converts lexcial value and the current context to the corresponding * value object. * *

    * The caller cannot generally assume that the value object is * a meaningful Java object. For example, the caller cannot expect * this method to return java.lang.Number type for * the "integer" type of XML Schema Part 2. * *

    * Also, the caller cannot assume that the equals method and * the hashCode method of the value object are consistent with * the semantics of the datatype. For that purpose, the sameValue * method and the valueHashCode method have to be used. Note that * this means you cannot use classes like * java.util.Hashtable to store the value objects. * *

    * The returned value object should be used solely for the sameValue * and valueHashCode methods. * * @param context * If this datatype is context-dependent * (when the {@link #isContextDependent} method returns true), * then the caller must provide a non-null valid context object. * Otherwise, the caller can pass null. * * @return null * when the given lexical value is not a valid lexical * value for this type. */ Object createValue( String literal, ValidationContext context ); /** * Tests the equality of two value objects which were originally * created by the createValue method of this object. * * The behavior is undefined if objects not created by this type * are passed. It is the caller's responsibility to ensure that * value objects belong to this type. * * @return * true if two value objects are considered equal according to * the definition of this datatype; false if otherwise. */ boolean sameValue( Object value1, Object value2 ); /** * Computes the hash code for a value object, * which is consistent with the sameValue method. * * @return * hash code for the specified value object. */ int valueHashCode( Object value ); /** * Indicates that the datatype doesn't have ID/IDREF semantics. * * This value is one of the possible return values of the * {@link #getIdType} method. */ public static final int ID_TYPE_NULL = 0; /** * Indicates that RELAX NG compatibility processors should * treat this datatype as having ID semantics. * * This value is one of the possible return values of the * {@link #getIdType} method. */ public static final int ID_TYPE_ID = 1; /** * Indicates that RELAX NG compatibility processors should * treat this datatype as having IDREF semantics. * * This value is one of the possible return values of the * {@link #getIdType} method. */ public static final int ID_TYPE_IDREF = 2; /** * Indicates that RELAX NG compatibility processors should * treat this datatype as having IDREFS semantics. * * This value is one of the possible return values of the * {@link #getIdType} method. */ public static final int ID_TYPE_IDREFS = 3; /** * Checks if the ID/IDREF semantics is associated with this * datatype. * *

    * This method is introduced to support the RELAX NG DTD * compatibility spec. (Of course it's always free to use * this method for other purposes.) * *

    * If you are implementing a datatype library and have no idea about * the "RELAX NG DTD compatibility" thing, just return * ID_TYPE_NULL is fine. * * @return * If this datatype doesn't have any ID/IDREF semantics, * it returns {@link #ID_TYPE_NULL}. If it has such a semantics * (for example, XSD:ID, XSD:IDREF and comp:ID type), then * it returns {@link #ID_TYPE_ID}, {@link #ID_TYPE_IDREF} or * {@link #ID_TYPE_IDREFS}. */ public int getIdType(); /** * Checks if this datatype may need a context object for * the validation. * *

    * The callee must return true even when the context * is not always necessary. (For example, the "QName" type * doesn't need a context object when validating unprefixed * string. But nonetheless QName must return true.) * *

    * XSD's string and short types * are examples of context-independent datatypes. * Its QName and ENTITY types * are examples of context-dependent datatypes. * *

    * When a datatype is context-independent, then * the {@link #isValid} method, the {@link #checkValid} method, * the {@link #createStreamingValidator} method and * the {@link #createValue} method can be called without * providing a context object. * * @return * true if this datatype is context-dependent * (it needs a context object sometimes); * * false if this datatype is context-independent * (it never needs a context object). */ public boolean isContextDependent(); } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/DatatypeBuilder.java000066400000000000000000000030161225366607500311700ustar00rootroot00000000000000package org.relaxng.datatype; /** * Creates a user-defined type by adding parameters to * the pre-defined type. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface DatatypeBuilder { /** * Adds a new parameter. * * @param name * The name of the parameter to be added. * @param strValue * The raw value of the parameter. Caller may not normalize * this value because any white space is potentially significant. * @param context * The context information which can be used by the callee to * acquire additional information. This context object is * valid only during this method call. The callee may not * keep a reference to this object. * @exception DatatypeException * When the given parameter is inappropriate for some reason. * The callee is responsible to recover from this error. * That is, the object should behave as if no such error * was occured. */ void addParameter( String name, String strValue, ValidationContext context ) throws DatatypeException; /** * Derives a new Datatype from a Datatype by parameters that * were already set through the addParameter method. * * @exception DatatypeException * DatatypeException must be thrown if the derivation is * somehow invalid. For example, a required parameter is missing, * etc. The exception should contain a diagnosis message * if possible. */ Datatype createDatatype() throws DatatypeException; } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/DatatypeException.java000066400000000000000000000015471225366607500315470ustar00rootroot00000000000000package org.relaxng.datatype; /** * Signals Datatype related exceptions. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public class DatatypeException extends Exception { public DatatypeException( int index, String msg ) { super(msg); this.index = index; } public DatatypeException( String msg ) { this(UNKNOWN,msg); } /** * A constructor for those datatype libraries which don't support any * diagnostic information at all. */ public DatatypeException() { this(UNKNOWN,null); } private final int index; public static final int UNKNOWN = -1; /** * Gets the index of the content where the error occured. * UNKNOWN can be returned to indicate that no index information * is available. */ public int getIndex() { return index; } } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/DatatypeLibrary.java000066400000000000000000000016771225366607500312210ustar00rootroot00000000000000package org.relaxng.datatype; /** * A Datatype library * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface DatatypeLibrary { /** * Creates a new instance of DatatypeBuilder. * * The callee should throw a DatatypeException in case of an error. * * @param baseTypeLocalName * The local name of the base type. * * @return * A non-null valid datatype object. */ DatatypeBuilder createDatatypeBuilder( String baseTypeLocalName ) throws DatatypeException; /** * Gets or creates a pre-defined type. * * This is just a short-cut of * createDatatypeBuilder(typeLocalName).createDatatype(); * * The callee should throw a DatatypeException in case of an error. * * @return * A non-null valid datatype object. */ Datatype createDatatype( String typeLocalName ) throws DatatypeException; } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/DatatypeLibraryFactory.java000066400000000000000000000014421225366607500325370ustar00rootroot00000000000000package org.relaxng.datatype; /** * Factory class for the DatatypeLibrary class. * *

    * The datatype library should provide the implementation of * this interface if it wants to be found by the schema processors. * The implementor also have to place a file in your jar file. * See the reference datatype library implementation for detail. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface DatatypeLibraryFactory { /** * Creates a new instance of a DatatypeLibrary that supports * the specified namespace URI. * * @return * null if the specified namespace URI is not * supported. */ DatatypeLibrary createDatatypeLibrary( String namespaceURI ); } DatatypeStreamingValidator.java000066400000000000000000000024471225366607500333310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatypepackage org.relaxng.datatype; /** * Datatype streaming validator. * *

    * The streaming validator is an optional feature that is useful for * certain Datatypes. It allows the caller to incrementally provide * the literal. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface DatatypeStreamingValidator { /** * Passes an additional fragment of the literal. * *

    * The application can call this method several times, then call * the isValid method (or the checkValid method) to check the validity * of the accumulated characters. */ void addCharacters( char[] buf, int start, int len ); /** * Tells if the accumulated literal is valid with respect to * the underlying Datatype. * * @return * True if it is valid. False if otherwise. */ boolean isValid(); /** * Similar to the isValid method, but this method throws * Exception (with possibly diagnostic information), instead of * returning false. * * @exception DatatypeException * If the callee supports the diagnosis and the accumulated * literal is invalid, then this exception that possibly * contains diagnosis information is thrown. */ void checkValid() throws DatatypeException; } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/ValidationContext.java000066400000000000000000000033061225366607500315470ustar00rootroot00000000000000package org.relaxng.datatype; /** * An interface that must be implemented by caller to * provide context information that is necessary to * perform validation of some Datatypes. * * @author James Clark * @author Kohsuke KAWAGUCHI */ public interface ValidationContext { /** * Resolves a namespace prefix to the corresponding namespace URI. * * This method is used for validating the QName type, for example. * *

    * If the prefix is "" (empty string), it indicates * an unprefixed value. The callee * should resolve it as for an unprefixed * element, rather than for an unprefixed attribute. * *

    * If the prefix is "xml", then the callee must resolve * this prefix into "http://www.w3.org/XML/1998/namespace", * as defined in the XML Namespaces Recommendation. * * @return * namespace URI of this prefix. * If the specified prefix is not declared, * the implementation must return null. */ String resolveNamespacePrefix( String prefix ); /** * Returns the base URI of the context. The null string may be returned * if no base URI is known. */ String getBaseUri(); /** * Checks if an unparsed entity is declared with the * specified name. * * @return * true * if the DTD has an unparsed entity declaration for * the specified name. * false * otherwise. */ boolean isUnparsedEntity( String entityName ); /** * Checks if a notation is declared with the * specified name. * * @return * true * if the DTD has a notation declaration for the specified name. * false * otherwise. */ boolean isNotation( String notationName ); } jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/helpers/000077500000000000000000000000001225366607500267055ustar00rootroot00000000000000DatatypeLibraryLoader.java000066400000000000000000000173211225366607500337240ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/helpers/** * Copyright (c) 2001, Thai Open Source Software Center Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of the Thai Open Source Software Center Ltd nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.relaxng.datatype.helpers; import org.relaxng.datatype.DatatypeLibraryFactory; import org.relaxng.datatype.DatatypeLibrary; import java.util.Enumeration; import java.util.NoSuchElementException; import java.util.Vector; import java.io.Reader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; /** * Discovers the datatype library implementation from the classpath. * *

    * The call of the createDatatypeLibrary method finds an implementation * from a given datatype library URI at run-time. */ public class DatatypeLibraryLoader implements DatatypeLibraryFactory { private final Service service = new Service(DatatypeLibraryFactory.class); public DatatypeLibrary createDatatypeLibrary(String uri) { for (Enumeration e = service.getProviders(); e.hasMoreElements();) { DatatypeLibraryFactory factory = (DatatypeLibraryFactory)e.nextElement(); DatatypeLibrary library = factory.createDatatypeLibrary(uri); if (library != null) return library; } return null; } private static class Service { private final Class serviceClass; private final Enumeration configFiles; private Enumeration classNames = null; private final Vector providers = new Vector(); private Loader loader; private class ProviderEnumeration implements Enumeration { private int nextIndex = 0; public boolean hasMoreElements() { return nextIndex < providers.size() || moreProviders(); } public Object nextElement() { try { return providers.elementAt(nextIndex++); } catch (ArrayIndexOutOfBoundsException e) { throw new NoSuchElementException(); } } } private static class Singleton implements Enumeration { private Object obj; private Singleton(Object obj) { this.obj = obj; } public boolean hasMoreElements() { return obj != null; } public Object nextElement() { if (obj == null) throw new NoSuchElementException(); Object tem = obj; obj = null; return tem; } } // JDK 1.1 private static class Loader { Enumeration getResources(String resName) { ClassLoader cl = Loader.class.getClassLoader(); URL url; if (cl == null) url = ClassLoader.getSystemResource(resName); else url = cl.getResource(resName); return new Singleton(url); } Class loadClass(String name) throws ClassNotFoundException { return Class.forName(name); } } // JDK 1.2+ private static class Loader2 extends Loader { private ClassLoader cl; Loader2() { cl = Loader2.class.getClassLoader(); // If the thread context class loader has the class loader // of this class as an ancestor, use the thread context class // loader. Otherwise, the thread context class loader // probably hasn't been set up properly, so don't use it. ClassLoader clt = Thread.currentThread().getContextClassLoader(); for (ClassLoader tem = clt; tem != null; tem = tem.getParent()) if (tem == cl) { cl = clt; break; } } Enumeration getResources(String resName) { try { Enumeration resources = cl.getResources(resName); if (resources.hasMoreElements()) return resources; // Some application servers apparently do not implement findResources // in their class loaders, so fall back to getResource. return new Singleton(cl.getResource(resName)); } catch (IOException e) { return new Singleton(null); } } Class loadClass(String name) throws ClassNotFoundException { return Class.forName(name, true, cl); } } public Service(Class cls) { try { loader = new Loader2(); } catch (NoSuchMethodError e) { loader = new Loader(); } serviceClass = cls; String resName = "META-INF/services/" + serviceClass.getName(); configFiles = loader.getResources(resName); } public Enumeration getProviders() { return new ProviderEnumeration(); } synchronized private boolean moreProviders() { for (;;) { while (classNames == null) { if (!configFiles.hasMoreElements()) return false; classNames = parseConfigFile((URL)configFiles.nextElement()); } while (classNames.hasMoreElements()) { String className = (String)classNames.nextElement(); try { Class cls = loader.loadClass(className); Object obj = cls.newInstance(); if (serviceClass.isInstance(obj)) { providers.addElement(obj); return true; } } catch (ClassNotFoundException e) { } catch (InstantiationException e) { } catch (IllegalAccessException e) { } catch (LinkageError e) { } } classNames = null; } } private static final int START = 0; private static final int IN_NAME = 1; private static final int IN_COMMENT = 2; private static Enumeration parseConfigFile(URL url) { try { InputStream in = url.openStream(); Reader r; try { r = new InputStreamReader(in, "UTF-8"); } catch (UnsupportedEncodingException e) { r = new InputStreamReader(in, "UTF8"); } r = new BufferedReader(r); Vector tokens = new Vector(); StringBuffer tokenBuf = new StringBuffer(); int state = START; for (;;) { int n = r.read(); if (n < 0) break; char c = (char)n; switch (c) { case '\r': case '\n': state = START; break; case ' ': case '\t': break; case '#': state = IN_COMMENT; break; default: if (state != IN_COMMENT) { state = IN_NAME; tokenBuf.append(c); } break; } if (tokenBuf.length() != 0 && state != IN_NAME) { tokens.addElement(tokenBuf.toString()); tokenBuf.setLength(0); } } if (tokenBuf.length() != 0) tokens.addElement(tokenBuf.toString()); return tokens.elements(); } catch (IOException e) { return null; } } } } ParameterlessDatatypeBuilder.java000066400000000000000000000022011225366607500352760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/helperspackage org.relaxng.datatype.helpers; import org.relaxng.datatype.*; /** * Dummy implementation of {@link DatatypeBuilder}. * * This implementation can be used for Datatypes which have no parameters. * Any attempt to add parameters will be rejected. * *

    * Typical usage would be: *

    
     * class MyDatatypeLibrary implements DatatypeLibrary {
     *     ....
     *     DatatypeBuilder createDatatypeBuilder( String typeName ) {
     *         return new ParameterleessDatatypeBuilder(createDatatype(typeName));
     *     }
     *     ....
     * }
     * 
    * * @author Kohsuke KAWAGUCHI */ public final class ParameterlessDatatypeBuilder implements DatatypeBuilder { /** This type object is returned for the derive method. */ private final Datatype baseType; public ParameterlessDatatypeBuilder( Datatype baseType ) { this.baseType = baseType; } public void addParameter( String name, String strValue, ValidationContext context ) throws DatatypeException { throw new DatatypeException(); } public Datatype createDatatype() throws DatatypeException { return baseType; } } StreamingValidatorImpl.java000066400000000000000000000030741225366607500341160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/datatype/src/main/org/relaxng/datatype/helperspackage org.relaxng.datatype.helpers; import org.relaxng.datatype.*; /** * Dummy implementation of {@link DatatypeStreamingValidator}. * *

    * This implementation can be used as a quick hack when the performance * of streaming validation is not important. And this implementation * also shows you how to implement the DatatypeStreamingValidator interface. * *

    * Typical usage would be: *

    
     * class MyDatatype implements Datatype {
     *     ....
     *     public DatatypeStreamingValidator createStreamingValidator( ValidationContext context ) {
     *         return new StreamingValidatorImpl(this,context);
     *     }
     *     ....
     * }
     * 
    * * @author Kohsuke KAWAGUCHI */ public final class StreamingValidatorImpl implements DatatypeStreamingValidator { /** This buffer accumulates characters. */ private final StringBuffer buffer = new StringBuffer(); /** Datatype obejct that creates this streaming validator. */ private final Datatype baseType; /** The current context. */ private final ValidationContext context; public void addCharacters( char[] buf, int start, int len ) { // append characters to the current buffer. buffer.append(buf,start,len); } public boolean isValid() { return baseType.isValid(buffer.toString(),context); } public void checkValid() throws DatatypeException { baseType.checkValid(buffer.toString(),context); } public StreamingValidatorImpl( Datatype baseType, ValidationContext context ) { this.baseType = baseType; this.context = context; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/000077500000000000000000000000001225366607500175365ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/mod.xml000066400000000000000000000001321225366607500210330ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/dtd-parse/src/000077500000000000000000000000001225366607500203255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/000077500000000000000000000000001225366607500212515ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/000077500000000000000000000000001225366607500220275ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/000077500000000000000000000000001225366607500250575ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/000077500000000000000000000000001225366607500256575ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/000077500000000000000000000000001225366607500264325ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/000077500000000000000000000000001225366607500270455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Any.java000066400000000000000000000003571225366607500304440ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Any extends ModelGroup { public Any() { } public int getType() { return ANY; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.any(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/AttlistDecl.java000066400000000000000000000012571225366607500321310ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class AttlistDecl extends TopLevel { private final NameSpec elementNameSpec; private final AttributeGroup attributeGroup; public AttlistDecl(NameSpec elementNameSpec, AttributeGroup attributeGroup) { this.elementNameSpec = elementNameSpec; this.attributeGroup = attributeGroup; } public int getType() { return ATTLIST_DECL; } public NameSpec getElementNameSpec() { return elementNameSpec; } public AttributeGroup getAttributeGroup() { return attributeGroup; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.attlistDecl(elementNameSpec, attributeGroup); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Attribute.java000066400000000000000000000014741225366607500316610ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Attribute extends AttributeGroupMember { private final NameSpec nameSpec; private final Datatype datatype; private final AttributeDefault attributeDefault; public Attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) { this.nameSpec = nameSpec; this.datatype = datatype; this.attributeDefault = attributeDefault; } public NameSpec getNameSpec() { return nameSpec; } public Datatype getDatatype() { return datatype; } public AttributeDefault getAttributeDefault() { return attributeDefault; } public void accept(AttributeGroupVisitor visitor) throws Exception { visitor.attribute(nameSpec, datatype, attributeDefault); } public int getType() { return ATTRIBUTE; } } AttributeDefault.java000066400000000000000000000011311225366607500330750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public abstract class AttributeDefault { public static final int DEFAULT_VALUE = 0; public static final int FIXED_VALUE = 1; public static final int IMPLIED_VALUE = 2; public static final int REQUIRED_VALUE = 3; public static final int ATTRIBUTE_DEFAULT_REF = 4; public abstract int getType(); public abstract void accept(AttributeDefaultVisitor visitor) throws Exception; public boolean isRequired() { return false; } public String getDefaultValue() { return null; } public String getFixedValue() { return null; } } AttributeDefaultDef.java000066400000000000000000000010761225366607500335240ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class AttributeDefaultDef extends Def { private final AttributeDefault attributeDefault; public AttributeDefaultDef(String name, AttributeDefault attributeDefault) { super(name); this.attributeDefault = attributeDefault; } public int getType() { return ATTRIBUTE_DEFAULT_DEF; } public AttributeDefault getAttributeDefault() { return attributeDefault; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.attributeDefaultDef(getName(), attributeDefault); } } AttributeDefaultRef.java000066400000000000000000000016351225366607500335430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class AttributeDefaultRef extends AttributeDefault { private final String name; private final AttributeDefault attributeDefault; public AttributeDefaultRef(String name, AttributeDefault attributeDefault) { this.name = name; this.attributeDefault = attributeDefault; } public int getType() { return ATTRIBUTE_DEFAULT_REF; } public AttributeDefault getAttributeDefault() { return attributeDefault; } public String getName() { return name; } public void accept(AttributeDefaultVisitor visitor) throws Exception { visitor.attributeDefaultRef(name, attributeDefault); } public boolean isRequired() { return attributeDefault.isRequired(); } public String getDefaultValue() { return attributeDefault.getDefaultValue(); } public String getFixedValue() { return attributeDefault.getFixedValue(); } } AttributeDefaultVisitor.java000066400000000000000000000006021225366607500344570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public interface AttributeDefaultVisitor { public void defaultValue(String value) throws Exception; public void fixedValue(String value) throws Exception; public void impliedValue() throws Exception; public void requiredValue() throws Exception; public void attributeDefaultRef(String name, AttributeDefault ad) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/AttributeGroup.java000066400000000000000000000010711225366607500326670ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class AttributeGroup { private final AttributeGroupMember[] members; public AttributeGroup(AttributeGroupMember[] members) { this.members = members; } public AttributeGroupMember[] getMembers() { AttributeGroupMember[] tem = new AttributeGroupMember[members.length]; System.arraycopy(members, 0, tem, 0, members.length); return tem; } public void accept(AttributeGroupVisitor visitor) throws Exception { for (int i = 0; i < members.length; i++) members[i].accept(visitor); } } AttributeGroupDef.java000066400000000000000000000010421225366607500332250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class AttributeGroupDef extends Def { private final AttributeGroup attributeGroup; public AttributeGroupDef(String name, AttributeGroup attributeGroup) { super(name); this.attributeGroup = attributeGroup; } public int getType() { return ATTRIBUTE_GROUP_DEF; } public AttributeGroup getAttributeGroup() { return attributeGroup; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.attributeGroupDef(getName(), attributeGroup); } } AttributeGroupMember.java000066400000000000000000000004441225366607500337430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public abstract class AttributeGroupMember { public static final int ATTRIBUTE = 0; public static final int ATTRIBUTE_GROUP_REF = 1; public abstract int getType(); public abstract void accept(AttributeGroupVisitor visitor) throws Exception; } AttributeGroupRef.java000066400000000000000000000012101225366607500332400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class AttributeGroupRef extends AttributeGroupMember { private final String name; private final AttributeGroup attributeGroup; public AttributeGroupRef(String name, AttributeGroup attributeGroup) { this.name = name; this.attributeGroup = attributeGroup; } public int getType() { return ATTRIBUTE_GROUP_REF; } public AttributeGroup getAttributeGroup() { return attributeGroup; } public String getName() { return name; } public void accept(AttributeGroupVisitor visitor) throws Exception { visitor.attributeGroupRef(name, attributeGroup); } } AttributeGroupVisitor.java000066400000000000000000000004441225366607500341730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public interface AttributeGroupVisitor { void attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) throws Exception; void attributeGroupRef(String name, AttributeGroup attributeGroup) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/CdataDatatype.java000066400000000000000000000004111225366607500324140ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class CdataDatatype extends Datatype { public CdataDatatype() { } public int getType() { return CDATA; } public void accept(DatatypeVisitor visitor) throws Exception { visitor.cdataDatatype(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Choice.java000066400000000000000000000010151225366607500310770ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Choice extends ModelGroup { private final ModelGroup[] members; public Choice(ModelGroup[] members) { this.members = members; } public int getType() { return CHOICE; } public ModelGroup[] getMembers() { ModelGroup[] tem = new ModelGroup[members.length]; System.arraycopy(members, 0, tem, 0, members.length); return tem; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.choice(getMembers()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Comment.java000066400000000000000000000005741225366607500313200ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Comment extends TopLevel { private final String value; public Comment(String value) { this.value = value; } public int getType() { return COMMENT; } public String getValue() { return value; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.comment(value); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Datatype.java000066400000000000000000000006551225366607500314710ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class Datatype { public static final int CDATA = 0; public static final int TOKENIZED = 1; public static final int ENUM = 2; public static final int NOTATION = 3; public static final int DATATYPE_REF = 4; public abstract int getType(); public abstract void accept(DatatypeVisitor visitor) throws Exception; public Datatype deref() { return this; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/DatatypeDef.java000066400000000000000000000007151225366607500321050ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class DatatypeDef extends Def { private final Datatype datatype; public DatatypeDef(String name, Datatype datatype) { super(name); this.datatype = datatype; } public int getType() { return DATATYPE_DEF; } public Datatype getDatatype() { return datatype; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.datatypeDef(getName(), datatype); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/DatatypeRef.java000066400000000000000000000011371225366607500321220ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class DatatypeRef extends Datatype { private final String name; private final Datatype datatype; public DatatypeRef(String name, Datatype datatype) { this.name = name; this.datatype = datatype; } public int getType() { return DATATYPE_REF; } public Datatype getDatatype() { return datatype; } public String getName() { return name; } public void accept(DatatypeVisitor visitor) throws Exception { visitor.datatypeRef(name, datatype); } public Datatype deref() { return datatype.deref(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/DatatypeVisitor.java000066400000000000000000000005621225366607500330460ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public interface DatatypeVisitor { void cdataDatatype() throws Exception; void tokenizedDatatype(String typeName) throws Exception; void enumDatatype(EnumGroup enumGroup) throws Exception; void notationDatatype(EnumGroup enumGroup) throws Exception; void datatypeRef(String name, Datatype datatype) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Def.java000066400000000000000000000003401225366607500304030ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class Def extends TopLevel { private final String name; protected Def(String name) { this.name = name; } public String getName() { return name; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/DefaultValue.java000066400000000000000000000007321225366607500322730ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class DefaultValue extends AttributeDefault { private final String value; public DefaultValue(String value) { this.value = value; } public int getType() { return DEFAULT_VALUE; } public String getValue() { return value; } public void accept(AttributeDefaultVisitor visitor) throws Exception { visitor.defaultValue(value); } public String getDefaultValue() { return value; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Dtd.java000066400000000000000000000003041225366607500304200ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public interface Dtd { String getEncoding(); String getUri(); TopLevel[] getAllTopLevel(); void accept(TopLevelVisitor visitor) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/DtdParser.java000066400000000000000000000004201225366607500315740ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; import java.io.IOException; import com.thaiopensource.xml.em.*; public interface DtdParser { Dtd parse(String systemId, EntityManager em) throws IOException; Dtd parse(OpenEntity entity, EntityManager em) throws IOException; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ElementDecl.java000066400000000000000000000011261225366607500320710ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ElementDecl extends TopLevel { private final NameSpec nameSpec; private final ModelGroup modelGroup; public ElementDecl(NameSpec nameSpec, ModelGroup modelGroup) { this.nameSpec = nameSpec; this.modelGroup = modelGroup; } public int getType() { return ELEMENT_DECL; } public NameSpec getNameSpec() { return nameSpec; } public ModelGroup getModelGroup() { return modelGroup; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.elementDecl(nameSpec, modelGroup); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ElementRef.java000066400000000000000000000006501225366607500317370ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ElementRef extends ModelGroup { private final NameSpec nameSpec; public ElementRef(NameSpec nameSpec) { this.nameSpec = nameSpec; } public int getType() { return ELEMENT_REF; } public NameSpec getNameSpec() { return nameSpec; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.elementRef(nameSpec); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumDatatype.java000066400000000000000000000006501225366607500323110ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class EnumDatatype extends Datatype { private final EnumGroup enumGroup; public EnumDatatype(EnumGroup enumGroup) { this.enumGroup = enumGroup; } public int getType() { return ENUM; } public EnumGroup getEnumGroup() { return enumGroup; } public void accept(DatatypeVisitor visitor) throws Exception { visitor.enumDatatype(enumGroup); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumGroup.java000066400000000000000000000010211225366607500316230ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class EnumGroup { private final EnumGroupMember[] members; public EnumGroup(EnumGroupMember[] members) { this.members = members; } public EnumGroupMember[] getMembers() { EnumGroupMember[] tem = new EnumGroupMember[members.length]; System.arraycopy(members, 0, tem, 0, members.length); return tem; } public void accept(EnumGroupVisitor visitor) throws Exception { for (int i = 0; i < members.length; i++) members[i].accept(visitor); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumGroupDef.java000066400000000000000000000007341225366607500322540ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class EnumGroupDef extends Def { private final EnumGroup enumGroup; public EnumGroupDef(String name, EnumGroup enumGroup) { super(name); this.enumGroup = enumGroup; } public int getType() { return ENUM_GROUP_DEF; } public EnumGroup getEnumGroup() { return enumGroup; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.enumGroupDef(getName(), enumGroup); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumGroupMember.java000066400000000000000000000004261225366607500327630ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class EnumGroupMember { public static final int ENUM_VALUE = 0; public static final int ENUM_GROUP_REF = 1; public abstract int getType(); public abstract void accept(EnumGroupVisitor visitor) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumGroupRef.java000066400000000000000000000010701225366607500322640ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class EnumGroupRef extends EnumGroupMember { private final String name; private final EnumGroup enumGroup; public EnumGroupRef(String name, EnumGroup enumGroup) { this.name = name; this.enumGroup = enumGroup; } public int getType() { return ENUM_GROUP_REF; } public EnumGroup getEnumGroup() { return enumGroup; } public String getName() { return name; } public void accept(EnumGroupVisitor visitor) throws Exception { visitor.enumGroupRef(name, enumGroup); } } EnumGroupVisitor.java000066400000000000000000000003071225366607500331320ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public interface EnumGroupVisitor { void enumValue(String value) throws Exception; void enumGroupRef(String name, EnumGroup enumGroup) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/EnumValue.java000066400000000000000000000006141225366607500316120ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class EnumValue extends EnumGroupMember { private final String value; public EnumValue(String value) { this.value = value; } public String getValue() { return value; } public void accept(EnumGroupVisitor visitor) throws Exception { visitor.enumValue(value); } public int getType() { return ENUM_VALUE; } } ExternalEntityDecl.java000066400000000000000000000011771225366607500334060ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; import com.thaiopensource.xml.em.ExternalId; public class ExternalEntityDecl extends TopLevel { private final String name; private final ExternalId externalId; public ExternalEntityDecl(String name, ExternalId externalId) { this.name = name; this.externalId = externalId; } public int getType() { return EXTERNAL_ENTITY_DECL; } public String getName() { return name; } public ExternalId getExternalId() { return externalId; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.externalEntityDecl(name, externalId); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ExternalIdDef.java000066400000000000000000000010211225366607500323600ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; import com.thaiopensource.xml.em.ExternalId; public class ExternalIdDef extends Def { private final ExternalId externalId; public ExternalIdDef(String name, ExternalId externalId) { super(name); this.externalId = externalId; } public int getType() { return EXTERNAL_ID_DEF; } public ExternalId getExternalId() { return externalId; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.externalIdDef(getName(), externalId); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ExternalIdRef.java000066400000000000000000000022401225366607500324020ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; import com.thaiopensource.xml.em.ExternalId; public class ExternalIdRef extends TopLevel { private final String name; private final ExternalId externalId; private final String uri; private final String encoding; private final TopLevel[] contents; public ExternalIdRef(String name, ExternalId externalId, String uri, String encoding, TopLevel[] contents) { this.name = name; this.externalId = externalId; this.uri = uri; this.encoding = encoding; this.contents = contents; } public int getType() { return EXTERNAL_ID_REF; } public String getName() { return name; } public ExternalId getExternalId() { return externalId; } public String getUri() { return uri; } public String getEncoding() { return encoding; } public TopLevel[] getContents() { TopLevel[] tem = new TopLevel[contents.length]; System.arraycopy(contents, 0, tem, 0, contents.length); return tem; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.externalIdRef(name, externalId, uri, encoding, getContents()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/FixedValue.java000066400000000000000000000010131225366607500317370ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class FixedValue extends AttributeDefault { private final String value; public FixedValue(String value) { this.value = value; } public int getType() { return FIXED_VALUE; } public String getValue() { return value; } public void accept(AttributeDefaultVisitor visitor) throws Exception { visitor.fixedValue(value); } public String getDefaultValue() { return value; } public String getFixedValue() { return value; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Flag.java000066400000000000000000000004451225366607500305640ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class Flag { public static final int INCLUDE = 0; public static final int IGNORE = 0; public static final int FLAG_REF = 0; public abstract int getType(); public abstract void accept(FlagVisitor visitor) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/FlagDef.java000066400000000000000000000006251225366607500312030ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class FlagDef extends Def { private final Flag flag; public FlagDef(String name, Flag flag) { super(name); this.flag = flag; } public int getType() { return FLAG_DEF; } public Flag getFlag() { return flag; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.flagDef(getName(), flag); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/FlagRef.java000066400000000000000000000007361225366607500312240ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class FlagRef extends Flag { private final String name; private final Flag flag; public FlagRef(String name, Flag flag) { this.name = name; this.flag = flag; } public int getType() { return FLAG_REF; } public Flag getFlag() { return flag; } public String getName() { return name; } public void accept(FlagVisitor visitor) throws Exception { visitor.flagRef(name, flag); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/FlagVisitor.java000066400000000000000000000003071225366607500321410ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public interface FlagVisitor { void include() throws Exception; void ignore() throws Exception; void flagRef(String name, Flag flag) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Ignore.java000066400000000000000000000003261225366607500311340ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Ignore extends Flag { public int getType() { return IGNORE; } public void accept(FlagVisitor visitor) throws Exception { visitor.ignore(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/IgnoredSection.java000066400000000000000000000010401225366607500326170ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class IgnoredSection extends TopLevel { private final Flag flag; private final String contents; public IgnoredSection(Flag flag, String contents) { this.flag = flag; this.contents = contents; } public int getType() { return IGNORED_SECTION; } public Flag getFlag() { return flag; } public String getContents() { return contents; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.ignoredSection(flag, contents); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ImpliedValue.java000066400000000000000000000004001225366607500322620ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ImpliedValue extends AttributeDefault { public int getType() { return IMPLIED_VALUE; } public void accept(AttributeDefaultVisitor visitor) throws Exception { visitor.impliedValue(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Include.java000066400000000000000000000003311225366607500312700ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Include extends Flag { public int getType() { return INCLUDE; } public void accept(FlagVisitor visitor) throws Exception { visitor.include(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/IncludedSection.java000066400000000000000000000012401225366607500327610ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class IncludedSection extends TopLevel { private final Flag flag; private final TopLevel[] contents; public IncludedSection(Flag flag, TopLevel[] contents) { this.flag = flag; this.contents = contents; } public int getType() { return INCLUDED_SECTION; } public Flag getFlag() { return flag; } public TopLevel[] getContents() { TopLevel[] tem = new TopLevel[contents.length]; System.arraycopy(contents, 0, tem, 0, contents.length); return tem; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.includedSection(flag, getContents()); } } InternalEntityDecl.java000066400000000000000000000010411225366607500333660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class InternalEntityDecl extends TopLevel { private final String name; private final String value; public InternalEntityDecl(String name, String value) { this.name = name; this.value = value; } public int getType() { return INTERNAL_ENTITY_DECL; } public String getName() { return name; } public String getValue() { return value; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.internalEntityDecl(name, value); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ModelGroup.java000066400000000000000000000010521225366607500317630ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class ModelGroup { public static final int CHOICE = 1; public static final int SEQUENCE = 2; public static final int ONE_OR_MORE = 3; public static final int ZERO_OR_MORE = 4; public static final int OPTIONAL = 5; public static final int MODEL_GROUP_REF = 6; public static final int ELEMENT_REF = 7; public static final int PCDATA = 8; public static final int ANY = 9; public abstract int getType(); public abstract void accept(ModelGroupVisitor visitor) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ModelGroupDef.java000066400000000000000000000007521225366607500324100ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ModelGroupDef extends Def { private final ModelGroup modelGroup; public ModelGroupDef(String name, ModelGroup modelGroup) { super(name); this.modelGroup = modelGroup; } public int getType() { return MODEL_GROUP_DEF; } public ModelGroup getModelGroup() { return modelGroup; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.modelGroupDef(getName(), modelGroup); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ModelGroupRef.java000066400000000000000000000011021225366607500324140ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ModelGroupRef extends ModelGroup { private final String name; private final ModelGroup modelGroup; public ModelGroupRef(String name, ModelGroup modelGroup) { this.name = name; this.modelGroup = modelGroup; } public int getType() { return MODEL_GROUP_REF; } public ModelGroup getModelGroup() { return modelGroup; } public String getName() { return name; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.modelGroupRef(name, modelGroup); } } ModelGroupVisitor.java000066400000000000000000000010371225366607500332670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public interface ModelGroupVisitor { void choice(ModelGroup[] members) throws Exception; void sequence(ModelGroup[] members) throws Exception; void oneOrMore(ModelGroup member) throws Exception; void zeroOrMore(ModelGroup member) throws Exception; void optional(ModelGroup member) throws Exception; void modelGroupRef(String name, ModelGroup modelGroup) throws Exception; void elementRef(NameSpec name) throws Exception; void pcdata() throws Exception; void any() throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Name.java000066400000000000000000000005521225366607500305720ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Name extends NameSpec { private final String value; public Name(String value) { this.value = value; } public int getType() { return NAME; } public String getValue() { return value; } public void accept(NameSpecVisitor visitor) throws Exception { visitor.name(value); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/NameSpec.java000066400000000000000000000004541225366607500314060ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class NameSpec { public static final int NAME = 0; public static final int NAME_SPEC_REF = 1; public abstract int getType(); public abstract void accept(NameSpecVisitor visitor) throws Exception; public abstract String getValue(); } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/NameSpecDef.java000066400000000000000000000007071225366607500320260ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class NameSpecDef extends Def { private final NameSpec nameSpec; public NameSpecDef(String name, NameSpec nameSpec) { super(name); this.nameSpec = nameSpec; } public int getType() { return NAME_SPEC_DEF; } public NameSpec getNameSpec() { return nameSpec; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.nameSpecDef(getName(), nameSpec); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/NameSpecRef.java000066400000000000000000000011351225366607500320400ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class NameSpecRef extends NameSpec { private final String name; private final NameSpec nameSpec; public NameSpecRef(String name, NameSpec nameSpec) { this.name = name; this.nameSpec = nameSpec; } public int getType() { return NAME_SPEC_REF; } public String getName() { return name; } public NameSpec getNameSpec() { return nameSpec; } public void accept(NameSpecVisitor visitor) throws Exception { visitor.nameSpecRef(name, nameSpec); } public String getValue() { return nameSpec.getValue(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/NameSpecVisitor.java000066400000000000000000000002761225366607500327700ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public interface NameSpecVisitor { void name(String value) throws Exception; void nameSpecRef(String name, NameSpec nameSpec) throws Exception; } NotationDatatype.java000066400000000000000000000005211225366607500331160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class NotationDatatype extends EnumDatatype { public NotationDatatype(EnumGroup enumGroup) { super(enumGroup); } public int getType() { return NOTATION; } public void accept(DatatypeVisitor visitor) throws Exception { visitor.notationDatatype(getEnumGroup()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/NotationDecl.java000066400000000000000000000011461225366607500322750ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; import com.thaiopensource.xml.em.ExternalId; public class NotationDecl extends TopLevel { private final String name; private final ExternalId externalId; public NotationDecl(String name, ExternalId externalId) { this.name = name; this.externalId = externalId; } public int getType() { return NOTATION_DECL; } public String getName() { return name; } public ExternalId getExternalId() { return externalId; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.notationDecl(name, externalId); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/OneOrMore.java000066400000000000000000000006341225366607500315600ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class OneOrMore extends ModelGroup { private final ModelGroup member; public OneOrMore(ModelGroup member) { this.member = member; } public int getType() { return ONE_OR_MORE; } public ModelGroup getMember() { return member; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.oneOrMore(member); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Optional.java000066400000000000000000000006261225366607500315010ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Optional extends ModelGroup { private final ModelGroup member; public Optional(ModelGroup member) { this.member = member; } public int getType() { return OPTIONAL; } public ModelGroup getMember() { return member; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.optional(member); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/OverriddenDef.java000066400000000000000000000010261225366607500324270ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class OverriddenDef extends TopLevel { private final boolean duplicate; private final Def def; public OverriddenDef(Def def, boolean duplicate) { this.def = def; this.duplicate = duplicate; } public int getType() { return OVERRIDDEN_DEF; } public Def getDef() { return def; } public boolean isDuplicate() { return duplicate; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.overriddenDef(def, duplicate); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ParamDef.java000066400000000000000000000006401225366607500313670ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ParamDef extends Def { private final String value; public ParamDef(String name, String value) { super(name); this.value = value; } public int getType() { return PARAM_DEF; } public String getValue() { return value; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.paramDef(getName(), value); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Pcdata.java000066400000000000000000000003731225366607500311070ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Pcdata extends ModelGroup { public Pcdata() { } public int getType() { return PCDATA; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.pcdata(); } } ProcessingInstruction.java000066400000000000000000000010731225366607500342100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class ProcessingInstruction extends TopLevel { private final String target; private final String value; public ProcessingInstruction(String target, String value) { this.target = target; this.value = value; } public int getType() { return PROCESSING_INSTRUCTION; } public String getTarget() { return target; } public String getValue() { return value; } public void accept(TopLevelVisitor visitor) throws Exception { visitor.processingInstruction(target, value); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/RequiredValue.java000066400000000000000000000004711225366607500324670ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class RequiredValue extends AttributeDefault { public int getType() { return REQUIRED_VALUE; } public void accept(AttributeDefaultVisitor visitor) throws Exception { visitor.requiredValue(); } public boolean isRequired() { return true; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/Sequence.java000066400000000000000000000010251225366607500314560ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class Sequence extends ModelGroup { private final ModelGroup[] members; public Sequence(ModelGroup[] members) { this.members = members; } public int getType() { return SEQUENCE; } public ModelGroup[] getMembers() { ModelGroup[] tem = new ModelGroup[members.length]; System.arraycopy(members, 0, tem, 0, members.length); return tem; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.sequence(getMembers()); } } TokenizedDatatype.java000066400000000000000000000006541225366607500332660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/ompackage com.thaiopensource.xml.dtd.om; public class TokenizedDatatype extends Datatype { private final String typeName; public TokenizedDatatype(String typeName) { this.typeName = typeName; } public int getType() { return TOKENIZED; } public String getTypeName() { return typeName; } public void accept(DatatypeVisitor visitor) throws Exception { visitor.tokenizedDatatype(typeName); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/TopLevel.java000066400000000000000000000021451225366607500314440ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public abstract class TopLevel { public static final int ELEMENT_DECL = 1; public static final int ATTLIST_DECL = 2; public static final int PROCESSING_INSTRUCTION = 3; public static final int COMMENT = 4; public static final int NOTATION_DECL = 5; public static final int MODEL_GROUP_DEF = 6; public static final int ATTRIBUTE_GROUP_DEF = 7; public static final int DATATYPE_DEF = 8; public static final int ENUM_GROUP_DEF = 9; public static final int FLAG_DEF = 10; public static final int INCLUDED_SECTION = 11; public static final int IGNORED_SECTION = 12; public static final int INTERNAL_ENTITY_DECL = 13; public static final int EXTERNAL_ENTITY_DECL = 14; public static final int NAME_SPEC_DEF = 15; public static final int OVERRIDDEN_DEF = 16; public static final int EXTERNAL_ID_DEF = 17; public static final int EXTERNAL_ID_REF = 18; public static final int PARAM_DEF = 19; public static final int ATTRIBUTE_DEFAULT_DEF = 20; public abstract int getType(); public abstract void accept(TopLevelVisitor visitor) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/TopLevelVisitor.java000066400000000000000000000031431225366607500330230ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; import com.thaiopensource.xml.em.ExternalId; public interface TopLevelVisitor { void elementDecl(NameSpec nameSpec, ModelGroup modelGroup) throws Exception; void attlistDecl(NameSpec nameSpec, AttributeGroup attributeGroup) throws Exception; void processingInstruction(String target, String value) throws Exception; void comment(String value) throws Exception; void modelGroupDef(String name, ModelGroup modelGroup) throws Exception; void attributeGroupDef(String name, AttributeGroup attributeGroup) throws Exception; void enumGroupDef(String name, EnumGroup enumGroup) throws Exception; void datatypeDef(String name, Datatype datatype) throws Exception; void flagDef(String name, Flag flag) throws Exception; void includedSection(Flag flag, TopLevel[] contents) throws Exception; void ignoredSection(Flag flag, String contents) throws Exception; void internalEntityDecl(String name, String value) throws Exception; void externalEntityDecl(String name, ExternalId externalId) throws Exception; void notationDecl(String name, ExternalId externalId) throws Exception; void nameSpecDef(String name, NameSpec nameSpec) throws Exception; void overriddenDef(Def def, boolean isDuplicate) throws Exception; void externalIdDef(String name, ExternalId externalId) throws Exception; void externalIdRef(String name, ExternalId externalId, String uri, String encoding, TopLevel[] contents) throws Exception; void paramDef(String name, String value) throws Exception; void attributeDefaultDef(String name, AttributeDefault ad) throws Exception; } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/om/ZeroOrMore.java000066400000000000000000000006401225366607500317530ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.om; public class ZeroOrMore extends ModelGroup { private final ModelGroup member; public ZeroOrMore(ModelGroup member) { this.member = member; } public int getType() { return ZERO_OR_MORE; } public ModelGroup getMember() { return member; } public void accept(ModelGroupVisitor visitor) throws Exception { visitor.zeroOrMore(member); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/000077500000000000000000000000001225366607500275445ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Atom.java000066400000000000000000000020151225366607500313050ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; class Atom { private final int tokenType; private final String token; private final Entity entity; Atom(Entity entity) { this.entity = entity; this.tokenType = -1; this.token = null; } Atom(int tokenType, String token) { this.tokenType = tokenType; this.token = token; this.entity = null; } Atom(int tokenType, String token, Entity entity) { this.tokenType = tokenType; this.token = token; this.entity = entity; } final int getTokenType() { return tokenType; } final String getToken() { return token; } final Entity getEntity() { return entity; } public int hashCode() { return token.hashCode(); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof Atom)) return false; Atom other = (Atom)obj; if (this.entity != null) return this.entity == other.entity; else return this.tokenType == other.tokenType && this.token.equals(other.token); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/AtomParser.java000066400000000000000000000260451225366607500324730ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Vector; import com.thaiopensource.xml.tok.Tokenizer; class AtomParser { private final DtdBuilder db; private final AtomStream as; private final PrologParser pp; private final Vector v; private Particle group; AtomParser(DtdBuilder db, AtomStream as, PrologParser pp, Vector v) { this.db = db; this.as = as; this.pp = pp; this.v = v; } AtomParser(DtdBuilder db, AtomStream as, PrologParser pp, Particle group) { this.db = db; this.as = as; this.pp = pp; this.v = group.particles; this.group = group; } void parse() { try { parseDecls(); pp.end(); } catch (PrologSyntaxException e) { throw new Error("syntax error on reparse at end of file"); } } private void parseDecls() throws PrologSyntaxException { while (as.advance()) { Decl d = null; if (as.entity != null) { d = new Decl(Decl.REFERENCE); d.entity = as.entity; v.addElement(d); int start = v.size(); new AtomParser(db, new AtomStream(as.entity.atoms), pp, v).parseDecls(); d.entity.setParsed(Entity.DECL_LEVEL, v, start, v.size()); d = new Decl(Decl.REFERENCE_END); } else { doAction(); switch (as.tokenType) { case Tokenizer.TOK_COMMENT: d = new Decl(Decl.COMMENT); d.value = as.token.substring(4, as.token.length() - 3); break; case Tokenizer.TOK_PI: d = new Decl(Decl.PROCESSING_INSTRUCTION); d.value = as.token.substring(2, as.token.length() - 2); break; case Tokenizer.TOK_PROLOG_S: case Tokenizer.TOK_XML_DECL: break; case Tokenizer.TOK_DECL_OPEN: { int type; if (as.token.equals("= len) { eof = true; token = null; entity = null; tokenType = -1; return false; } Atom a = (Atom)v.elementAt(i); token = a.getToken(); tokenType = a.getTokenType(); entity = a.getEntity(); i++; return true; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Decl.java000066400000000000000000000205371225366607500312650ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import com.thaiopensource.xml.dtd.om.AttlistDecl; import com.thaiopensource.xml.dtd.om.AttributeDefaultDef; import com.thaiopensource.xml.dtd.om.AttributeGroupDef; import com.thaiopensource.xml.dtd.om.Comment; import com.thaiopensource.xml.dtd.om.DatatypeDef; import com.thaiopensource.xml.dtd.om.Def; import com.thaiopensource.xml.dtd.om.ElementDecl; import com.thaiopensource.xml.dtd.om.EnumGroupDef; import com.thaiopensource.xml.dtd.om.ExternalEntityDecl; import com.thaiopensource.xml.dtd.om.ExternalIdDef; import com.thaiopensource.xml.dtd.om.ExternalIdRef; import com.thaiopensource.xml.dtd.om.Flag; import com.thaiopensource.xml.dtd.om.FlagDef; import com.thaiopensource.xml.dtd.om.IgnoredSection; import com.thaiopensource.xml.dtd.om.IncludedSection; import com.thaiopensource.xml.dtd.om.InternalEntityDecl; import com.thaiopensource.xml.dtd.om.ModelGroupDef; import com.thaiopensource.xml.dtd.om.NameSpec; import com.thaiopensource.xml.dtd.om.NameSpecDef; import com.thaiopensource.xml.dtd.om.NotationDecl; import com.thaiopensource.xml.dtd.om.OverriddenDef; import com.thaiopensource.xml.dtd.om.ParamDef; import com.thaiopensource.xml.dtd.om.ProcessingInstruction; import com.thaiopensource.xml.dtd.om.TopLevel; import java.util.Enumeration; import java.util.Vector; class Decl { static final int REFERENCE = 0; // entity static final int REFERENCE_END = 1; static final int ELEMENT = 2; // params static final int ATTLIST = 3; // params static final int ENTITY = 4; // params static final int NOTATION = 5; // params static final int INCLUDE_SECTION = 6; // params + decls static final int IGNORE_SECTION = 7; // params + value static final int COMMENT = 8; // value static final int PROCESSING_INSTRUCTION = 9; // value Decl(int type) { this.type = type; } final int type; Vector params; String value; Entity entity; Vector decls; public boolean equals(Object obj) { if (obj == null || !(obj instanceof Decl)) return false; Decl other = (Decl)obj; if (this.type != other.type) return false; if (this.entity != other.entity) return false; if (this.value != null && !this.value.equals(other.value)) return false; if (this.params != null) { int n = this.params.size(); if (other.params.size() != n) return false; for (int i = 0; i < n; i++) if (!this.params.elementAt(i).equals(other.params.elementAt(i))) return false; } return true; } ElementDecl createElementDecl() { ParamStream ps = new ParamStream(params, true); NameSpec nameSpec = Param.paramsToNameSpec(ps); return new ElementDecl(nameSpec, Param.paramsToModelGroup(ps)); } AttlistDecl createAttlistDecl() { ParamStream ps = new ParamStream(params, true); NameSpec nameSpec = Param.paramsToNameSpec(ps); return new AttlistDecl(nameSpec, Param.paramsToAttributeGroup(ps)); } TopLevel createEntityDecl(DtdBuilder db) { ParamStream ps = new ParamStream(params); ps.advance(); if (ps.type != Param.PERCENT) return createGeneralEntityDecl(db, ps.value); ps.advance(); String name = ps.value; Entity entity = db.lookupParamEntity(name); if (entity.decl == null) { entity.decl = this; return createDef(entity); } else { Entity overridden = entity.overrides; while (overridden.decl != null) overridden = overridden.overrides; overridden.decl = this; return new OverriddenDef(createDef(overridden), entity.entityValue != null && entity.entityValue.equals(overridden.entityValue)); } } static Def createDef(Entity entity) { String name = entity.name; switch (entity.semantic) { case Entity.SEMANTIC_MODEL_GROUP: entity.modelGroup = entity.toModelGroup(); return new ModelGroupDef(name, entity.modelGroup); case Entity.SEMANTIC_ATTRIBUTE_GROUP: entity.attributeGroup = Param.paramsToAttributeGroup(entity.parsed); return new AttributeGroupDef(name, entity.attributeGroup); case Entity.SEMANTIC_DATATYPE: entity.datatype = Param.paramsToDatatype(entity.parsed); return new DatatypeDef(name, entity.datatype); case Entity.SEMANTIC_ENUM_GROUP: entity.enumGroup = entity.toEnumGroup(); return new EnumGroupDef(name, entity.enumGroup); case Entity.SEMANTIC_FLAG: entity.flag = Param.paramsToFlag(entity.parsed); return new FlagDef(name, entity.flag); case Entity.SEMANTIC_NAME_SPEC: entity.nameSpec = entity.toNameSpec(); return new NameSpecDef(name, entity.nameSpec); case Entity.SEMANTIC_ATTRIBUTE_DEFAULT: entity.attributeDefault = Param.paramsToAttributeDefault(entity.parsed); return new AttributeDefaultDef(name, entity.attributeDefault); } if (entity.problem == Entity.NO_PROBLEM && !entity.overridden) throw new RuntimeException("unexplained problem for entity " + entity.name); if (entity.text == null) return new ExternalIdDef(name, entity.getExternalId()); return new ParamDef(name, entity.entityValue); } TopLevel createGeneralEntityDecl(DtdBuilder db, String name) { Entity entity = db.lookupGeneralEntity(name); while (entity.decl != null) entity = entity.overrides; entity.decl = this; if (entity.text == null) return new ExternalEntityDecl(name, entity.getExternalId()); else return new InternalEntityDecl(name, new String(entity.text)); } IncludedSection createIncludedSection(DtdBuilder db) { Flag flag = Param.paramsToFlag(params); Vector contents = declsToTopLevel(db, decls.elements()); TopLevel[] tem = new TopLevel[contents.size()]; for (int i = 0; i < tem.length; i++) tem[i] = (TopLevel)contents.elementAt(i); return new IncludedSection(flag, tem); } static Vector declsToTopLevel(DtdBuilder db, Enumeration decls) { Vector v = new Vector(); int level = 0; while (decls.hasMoreElements()) { TopLevel t = null; Decl decl = (Decl)decls.nextElement(); switch (decl.type) { case COMMENT: t = new Comment(decl.value); break; case PROCESSING_INSTRUCTION: t = decl.createProcessingInstruction(); break; case NOTATION: t = decl.createNotationDecl(db); break; case ELEMENT: t = decl.createElementDecl(); break; case ATTLIST: t = decl.createAttlistDecl(); break; case ENTITY: t = decl.createEntityDecl(db); break; case INCLUDE_SECTION: t = decl.createIncludedSection(db); break; case IGNORE_SECTION: t = decl.createIgnoredSection(); break; case REFERENCE: if (decl.entity.text == null) t = decl.createExternalIdRef(db, decls); else level++; break; case REFERENCE_END: if (level == 0) return v; --level; break; } if (t != null) v.addElement(t); } return v; } ExternalIdRef createExternalIdRef(DtdBuilder db, Enumeration decls) { Vector v = declsToTopLevel(db, decls); TopLevel[] tem = new TopLevel[v.size()]; for (int i = 0; i < tem.length; i++) tem[i] = (TopLevel)v.elementAt(i); return new ExternalIdRef(entity.name, entity.getExternalId(), entity.uri, entity.encoding, tem); } IgnoredSection createIgnoredSection() { return new IgnoredSection(Param.paramsToFlag(params), value); } ProcessingInstruction createProcessingInstruction() { int len = value.length(); int i; for (i = 0; i < len && !isWS(value.charAt(i)); i++) ; String target = value.substring(0, i); if (i < len) { for (++i; i < len && isWS(value.charAt(i)); i++) ; } return new ProcessingInstruction(target, value.substring(i, len)); } static private boolean isWS(char c) { switch (c) { case '\n': case '\r': case '\t': case ' ': return true; } return false; } NotationDecl createNotationDecl(DtdBuilder db) { ParamStream ps = new ParamStream(params); ps.advance(); return new NotationDecl(ps.value, db.lookupNotation(ps.value).getExternalId()); } static void examineElementNames(DtdBuilder db, Enumeration decls) { while (decls.hasMoreElements()) { Decl decl = (Decl)decls.nextElement(); switch (decl.type) { case ELEMENT: case ATTLIST: Param.examineElementNames(db, decl.params.elements()); break; case INCLUDE_SECTION: examineElementNames(db, decl.decls.elements()); break; } } } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/DtdBuilder.java000066400000000000000000000110011225366607500324220ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; import com.thaiopensource.xml.tok.Tokenizer; class DtdBuilder { private final Vector atoms; private final Vector decls = new Vector(); private final Hashtable paramEntityTable = new Hashtable(); private final Hashtable generalEntityTable = new Hashtable(); private final Hashtable normalizedTable = new Hashtable(); private final Hashtable notationTable = new Hashtable(); private final Hashtable ambigNameTable = new Hashtable(); DtdBuilder(Vector atoms) { this.atoms = atoms; } Vector getDecls() { return decls; } Entity lookupParamEntity(String name) { return (Entity)paramEntityTable.get(name); } Entity createParamEntity(String name) { Entity e = new Entity(name, true); Entity prev = (Entity)paramEntityTable.get(name); if (prev != null) { while (prev.overrides != null) prev = prev.overrides; prev.overrides = e; e.overridden = true; } else paramEntityTable.put(name, e); return e; } Entity lookupGeneralEntity(String name) { return (Entity)generalEntityTable.get(name); } Entity createGeneralEntity(String name) { Entity e = new Entity(name, false); Entity prev = (Entity)generalEntityTable.get(name); if (prev != null) { while (prev.overrides != null) prev = prev.overrides; prev.overrides = e; e.overridden = true; } else generalEntityTable.put(name, e); return e; } Notation lookupNotation(String name) { return (Notation)notationTable.get(name); } Notation createNotation(String name) { Notation n = (Notation)notationTable.get(name); if (n != null) return null; n = new Notation(name); notationTable.put(name, n); return n; } void unexpandEntities() { for (Enumeration e = paramEntityTable.elements(); e.hasMoreElements();) ((Entity)e.nextElement()).unexpandEntities(); } void createDecls() { new AtomParser(this, new AtomStream(atoms), new PrologParser(PrologParser.EXTERNAL_ENTITY), decls).parse(); } void analyzeSemantics() { /* A parameter entity such as where n.foo is referenced only in model groups could either be a name spec for an undefined element or a model group. If the element name "foo" is always referenced via n.foo, then we assume it's a name spec, otherwise we take it to be a model group. */ for (Enumeration e = paramEntityTable.elements(); e.hasMoreElements();) { Entity ent = (Entity)e.nextElement(); String name = ent.ambiguousNameSpec(); if (name != null) { Entity prevEnt = (Entity)ambigNameTable.get(name); if (prevEnt != null) { prevEnt.maybeNameSpec = false; ent.maybeNameSpec = false; } else ambigNameTable.put(name, ent); } } Decl.examineElementNames(this, decls.elements()); for (Enumeration e = paramEntityTable.elements(); e.hasMoreElements();) ((Entity)e.nextElement()).analyzeSemantic(); } void noteElementName(String name, Entity entity) { Entity cur = (Entity)ambigNameTable.get(name); if (cur != null && cur != entity) cur.maybeNameSpec = false; } Vector createTopLevel() { return Decl.declsToTopLevel(this, decls.elements()); } void dump() { dumpEntity("#doc", atoms); } private static void dumpEntity(String name, Vector atoms) { System.out.println(""); dumpAtoms(atoms); System.out.println(""); } private static void dumpAtoms(Vector v) { int n = v.size(); for (int i = 0; i < n; i++) { Atom a = (Atom)v.elementAt(i); Entity e = a.getEntity(); if (e != null) dumpEntity(e.name, e.atoms); else if (a.getTokenType() != Tokenizer.TOK_PROLOG_S) { System.out.print(""); dumpString(a.getToken()); System.out.println(""); } } } private static void dumpString(String s) { int n = s.length(); for (int i = 0; i < n; i++) switch (s.charAt(i)) { case '<': System.out.print("<"); break; case '>': System.out.print(">"); break; case '&': System.out.print("&"); break; default: System.out.print(s.charAt(i)); break; } } void setNormalized(String origValue, String normalizedValue) { normalizedTable.put(origValue, normalizedValue); } String getNormalized(String origValue) { return (String)normalizedTable.get(origValue); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/DtdImpl.java000066400000000000000000000017261225366607500317520ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Vector; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.om.TopLevel; import com.thaiopensource.xml.dtd.om.TopLevelVisitor; class DtdImpl implements Dtd { private final Vector topLevel; private final String encoding; private final String uri; DtdImpl(Vector topLevel, String uri, String encoding) { this.topLevel = topLevel; this.uri = uri; this.encoding = encoding; } public String getUri() { return uri; } public String getEncoding() { return encoding; } public TopLevel[] getAllTopLevel() { TopLevel[] tem = new TopLevel[topLevel.size()]; for (int i = 0; i < tem.length; i++) tem[i] = (TopLevel)topLevel.elementAt(i); return tem; } public void accept(TopLevelVisitor visitor) throws Exception { int n = topLevel.size(); for (int i = 0; i < n; i++) ((TopLevel)topLevel.elementAt(i)).accept(visitor); } } DtdParserImpl.java000066400000000000000000000014061225366607500330430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parsepackage com.thaiopensource.xml.dtd.parse; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.om.DtdParser; import com.thaiopensource.xml.em.EntityManager; import com.thaiopensource.xml.em.OpenEntity; import java.io.IOException; public class DtdParserImpl implements DtdParser { public DtdParserImpl() { } public Dtd parse(String systemId, EntityManager em) throws IOException { return parse(em.open(systemId), em); } public Dtd parse(OpenEntity entity, EntityManager em) throws IOException { DtdBuilder db = new Parser(entity, em).parse(); db.unexpandEntities(); db.createDecls(); db.analyzeSemantics(); return new DtdImpl(db.createTopLevel(), entity.getBaseUri(), entity.getEncoding()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Entity.java000066400000000000000000000364351225366607500316760ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Vector; import com.thaiopensource.xml.tok.Tokenizer; import com.thaiopensource.xml.em.ExternalId; import com.thaiopensource.xml.dtd.om.*; class Entity { static class Reference { Reference(Entity entity, int start, int end) { this.entity = entity; this.start = start; this.end = end; } final Entity entity; final int start; final int end; } final String name; final boolean isParameter; Entity(String name, boolean isParameter) { this.name = name; this.isParameter = isParameter; } char[] text; String entityValue; String systemId; String publicId; String baseUri; String encoding; String uri; Entity overrides; boolean overridden; // Which parts of text came from references? Reference[] references; boolean open; String notationName; Vector atoms; boolean mustReparse; static final int NO_PROBLEM = 0; static final int INCONSISTENT_LEVEL_PROBLEM = 1; static final int INCONSISTENT_PARSE_PROBLEM = 2; static final int UNEXPAND_PROBLEM = 3; static final int UNKNOWN_SEMANTIC_PROBLEM = 4; static final int EMPTY_PARTICLE_PROBLEM = 5; static final int REPARSE_PROBLEM = 6; static final int UNREFERENCED_PROBLEM = 7; static final int INTERNAL_DECL_PROBLEM = 8; static final int NOT_PARSED_PROBLEM = 9; int problem = UNREFERENCED_PROBLEM; static final int INCONSISTENT_LEVEL = -1; static final int NO_LEVEL = 0; static final int DECL_LEVEL = 1; static final int PARAM_LEVEL = 2; static final int PARTICLE_LEVEL = 3; int referenceLevel = NO_LEVEL; static final int GROUP_CONTAINS_OR = 01; static final int GROUP_CONTAINS_SEQ = 02; static final int GROUP_CONTAINS_PCDATA = 04; static final int GROUP_CONTAINS_GROUP = 010; static final int GROUP_CONTAINS_ELEMENT_NAME = 020; static final int GROUP_CONTAINS_NMTOKEN = 040; int groupFlags = 0; static final int SEMANTIC_NONE = 0; static final int SEMANTIC_MODEL_GROUP = 1; static final int SEMANTIC_ATTRIBUTE_GROUP = 2; static final int SEMANTIC_ENUM_GROUP = 3; static final int SEMANTIC_DATATYPE = 4; static final int SEMANTIC_FLAG = 5; static final int SEMANTIC_NAME_SPEC = 6; static final int SEMANTIC_ATTRIBUTE_DEFAULT = 7; int semantic = SEMANTIC_NONE; boolean maybeNameSpec; ModelGroup modelGroup; AttributeGroup attributeGroup; EnumGroup enumGroup; Datatype datatype; Flag flag; NameSpec nameSpec; AttributeDefault attributeDefault; Decl decl; Vector parsed; void inconsistentParse() { parsed = null; referenceLevel = INCONSISTENT_LEVEL; problem = INCONSISTENT_PARSE_PROBLEM; } void setParsed(int level, Vector v, int start, int end) { if (referenceLevel < 0) return; if (level == referenceLevel) { if (!sliceEqual(parsed, v, start, end)) inconsistentParse(); return; } if (referenceLevel == NO_LEVEL) { parsed = new Vector(); appendSlice(parsed, v, start, end); referenceLevel = level; return; } if (parsed.size() == end - start) { if (level == PARAM_LEVEL && referenceLevel == PARTICLE_LEVEL) { if (paramsParticlesConsistent(v, start, parsed, 0, end - start)) { // For element name case, otherwise particle will be // ambiguous with model group. referenceLevel = PARAM_LEVEL; parsed = new Vector(); appendSlice(parsed, v, start, end); return; } } else if (level == PARTICLE_LEVEL && referenceLevel == PARAM_LEVEL) { if (paramsParticlesConsistent(parsed, 0, v, start, end - start)) return; } } problem = INCONSISTENT_LEVEL_PROBLEM; parsed = null; referenceLevel = INCONSISTENT_LEVEL; } static boolean paramsParticlesConsistent(Vector params, int i, Vector particles, int j, int n) { for (int k = 0; k < n; k++) if (!paramParticleConsistent((Param)params.elementAt(i + k), (Particle)particles.elementAt(j + k))) return false; return true; } static boolean paramParticleConsistent(Param param, Particle particle) { switch (param.type) { case Param.MODEL_GROUP: return param.group.equals(particle); case Param.ELEMENT_NAME: return particle.type == Particle.ELEMENT_NAME; case Param.REFERENCE: return particle.type == Particle.REFERENCE; case Param.REFERENCE_END: return particle.type == Particle.REFERENCE_END; } return false; } int textIndexToAtomIndexOccur(int ti) { if (ti == text.length) return -1; switch (text[ti]) { case '*': case '?': case '+': break; default: return -1; } return textIndexToAtomIndex(ti + 1); } int textIndexToAtomIndex(int ti) { int nAtoms = atoms.size(); int len = 0; int atomIndex = 0; for (;;) { if (len == ti) return atomIndex; if (atomIndex >= nAtoms) break; Atom a = (Atom)atoms.elementAt(atomIndex); len += a.getToken().length(); if (len > ti) break; atomIndex++; } return -1; } void unexpandEntities() { if (references == null || atoms == null) return; Vector newAtoms = null; int nCopiedAtoms = 0; for (int i = 0; i < references.length; i++) { int start = textIndexToAtomIndex(references[i].start); int end = textIndexToAtomIndex(references[i].end); if (start >= 0 && end >= 0 && !(start == end && atomMaybePasted(start)) && atomsAreProperlyNested(start, end, true)) { if (newAtoms == null) newAtoms = new Vector(); appendSlice(newAtoms, atoms, nCopiedAtoms, start); newAtoms.addElement(new Atom(references[i].entity)); if (references[i].entity.atoms == null) { Vector tem = new Vector(); references[i].entity.atoms = tem; appendSlice(tem, atoms, start, end); references[i].entity.unexpandEntities(); } nCopiedAtoms = end; } else if (start >= 0 && (end = textIndexToAtomIndexOccur(references[i].end)) >= 0 && atomsAreProperlyNested(start, end, false)) { // This deals with a case like %foo;* by turning it into (%foo;)*. if (newAtoms == null) newAtoms = new Vector(); Atom[] split = splitAtom((Atom)atoms.elementAt(end - 1)); appendSlice(newAtoms, atoms, nCopiedAtoms, start); newAtoms.addElement(new Atom(Tokenizer.TOK_OPEN_PAREN, "(")); newAtoms.addElement(new Atom(references[i].entity)); newAtoms.addElement(split[1]); if (references[i].entity.atoms == null) { Vector tem = new Vector(); references[i].entity.atoms = tem; appendSlice(tem, atoms, start, end - 1); tem.addElement(split[0]); references[i].entity.unexpandEntities(); } nCopiedAtoms = end; } else if (!overridden) references[i].entity.problem = UNEXPAND_PROBLEM; } if (newAtoms == null) return; appendSlice(newAtoms, atoms, nCopiedAtoms, atoms.size()); atoms = newAtoms; references = null; if (overrides != null) overrides.unexpandEntities(); } private static Atom[] splitAtom(Atom atom) { Atom[] split = new Atom[2]; switch (atom.getTokenType()) { case Tokenizer.TOK_NAME_QUESTION: split[1] = new Atom(Tokenizer.TOK_CLOSE_PAREN_QUESTION, ")?"); break; case Tokenizer.TOK_NAME_ASTERISK: split[1] = new Atom(Tokenizer.TOK_CLOSE_PAREN_ASTERISK, ")*"); break; case Tokenizer.TOK_NAME_PLUS: split[1] = new Atom(Tokenizer.TOK_CLOSE_PAREN_PLUS, ")+"); break; case Tokenizer.TOK_CLOSE_PAREN_QUESTION: case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: case Tokenizer.TOK_CLOSE_PAREN_PLUS: split[0] = new Atom(Tokenizer.TOK_CLOSE_PAREN, ")"); split[1] = atom; return split; } split[0] = new Atom(Tokenizer.TOK_NAME, atom.getToken().substring(0, atom.getToken().length() - 1)); return split; } private boolean atomsAreProperlyNested(int start, int end, boolean allowConnectors) { int level = 0; for (int i = start; i < end; i++) switch (((Atom)atoms.elementAt(i)).getTokenType()) { case Tokenizer.TOK_COND_SECT_OPEN: case Tokenizer.TOK_OPEN_PAREN: case Tokenizer.TOK_OPEN_BRACKET: case Tokenizer.TOK_DECL_OPEN: level++; break; case Tokenizer.TOK_CLOSE_PAREN: case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: case Tokenizer.TOK_CLOSE_PAREN_QUESTION: case Tokenizer.TOK_CLOSE_PAREN_PLUS: case Tokenizer.TOK_CLOSE_BRACKET: case Tokenizer.TOK_DECL_CLOSE: if (--level < 0) return false; break; case Tokenizer.TOK_COND_SECT_CLOSE: if ((level -= 2) < 0) return false; break; case Tokenizer.TOK_OR: case Tokenizer.TOK_COMMA: if (!allowConnectors && level == 0) return false; break; } return level == 0; } private boolean atomMaybePasted(int i) { if (i > 0) { switch (((Atom)atoms.elementAt(i - 1)).getTokenType()) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: case Tokenizer.TOK_NMTOKEN: return true; } } if (i < atoms.size()) { switch (((Atom)atoms.elementAt(i)).getTokenType()) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: case Tokenizer.TOK_NAME_QUESTION: case Tokenizer.TOK_NAME_ASTERISK: case Tokenizer.TOK_NAME_PLUS: case Tokenizer.TOK_NMTOKEN: return true; } } return false; } static boolean sliceEqual(Vector v1, Vector v2, int start, int end) { int n = v1.size(); if (end - start != n) return false; for (int i = 0; i < n; i++) if (!v1.elementAt(i).equals(v2.elementAt(start + i))) return false; return true; } static void appendSlice(Vector to, Vector from, int start, int end) { for (; start < end; start++) to.addElement(from.elementAt(start)); } void analyzeSemantic() { if (problem != NO_PROBLEM) return; switch (referenceLevel) { case PARAM_LEVEL: analyzeSemanticParam(); break; case PARTICLE_LEVEL: analyzeSemanticParticle(); break; case DECL_LEVEL: problem = INTERNAL_DECL_PROBLEM; break; case NO_LEVEL: problem = NOT_PARSED_PROBLEM; break; } for (Entity e = overrides; e != null; e = e.overrides) e.analyzeSemanticOverride(this); } private void analyzeSemanticOverride(Entity orig) { if (parsed == null || problem != NO_PROBLEM) return; switch (referenceLevel) { case PARAM_LEVEL: analyzeSemanticParam(); break; case PARTICLE_LEVEL: groupFlags = orig.groupFlags; analyzeSemanticParticle(); break; } if (semantic != orig.semantic) semantic = SEMANTIC_NONE; } private void analyzeSemanticParam() { if (isAttributeGroup()) semantic = SEMANTIC_ATTRIBUTE_GROUP; else if (isDatatype()) semantic = SEMANTIC_DATATYPE; else if (isFlag()) semantic = SEMANTIC_FLAG; else if (isModelGroup()) semantic = SEMANTIC_MODEL_GROUP; else if (isNameSpec()) semantic = SEMANTIC_NAME_SPEC; else if (isAttributeDefault()) semantic = SEMANTIC_ATTRIBUTE_DEFAULT; else if (isEnumGroup()) semantic = SEMANTIC_ENUM_GROUP; else problem = UNKNOWN_SEMANTIC_PROBLEM; } private boolean isAttributeGroup() { ParamStream ps = new ParamStream(parsed); if (!ps.advance()) return false; do { if (ps.type != Param.EMPTY_ATTRIBUTE_GROUP && (ps.type != Param.ATTRIBUTE_NAME || !ps.advance() || (ps.type == Param.ATTRIBUTE_TYPE_NOTATION && !ps.advance()) || !ps.advance() || (ps.type == Param.FIXED && !ps.advance()))) return false; } while (ps.advance()); return true; } private boolean isDatatype() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && (ps.type == Param.ATTRIBUTE_TYPE || ps.type == Param.ATTRIBUTE_VALUE_GROUP || (ps.type == Param.ATTRIBUTE_TYPE_NOTATION && ps.advance())) && !ps.advance()); } private boolean isAttributeDefault() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && (ps.type == Param.DEFAULT_ATTRIBUTE_VALUE || ps.type == Param.IMPLIED || ps.type == Param.REQUIRED || (ps.type == Param.FIXED && ps.advance())) && !ps.advance()); } private boolean isFlag() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && (ps.type == Param.INCLUDE || ps.type == Param.IGNORE) && !ps.advance()); } private boolean isModelGroup() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && (ps.type == Param.MODEL_GROUP || ps.type == Param.EMPTY || ps.type == Param.EMPTY) && !ps.advance()); } private boolean isNameSpec() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && (ps.type == Param.ELEMENT_NAME || ps.type == Param.ATTRIBUTE_NAME) && !ps.advance()); } private boolean isEnumGroup() { ParamStream ps = new ParamStream(parsed); return (ps.advance() && ps.type == Param.NOTATION_GROUP && !ps.advance()); } private void analyzeSemanticParticle() { if (maybeNameSpec) { semantic = SEMANTIC_NAME_SPEC; return; } int n = parsed.size(); if (n == 0) { analyzeEmptySemanticParticle(); return; } for (int i = 0; i < n; i++) { switch (((Particle)parsed.elementAt(i)).type) { case Particle.GROUP: case Particle.ELEMENT_NAME: case Particle.PCDATA: semantic = SEMANTIC_MODEL_GROUP; return; case Particle.NMTOKEN: semantic = SEMANTIC_ENUM_GROUP; return; } } problem = UNKNOWN_SEMANTIC_PROBLEM; } static final int GROUP_MODEL_GROUP_FLAGS = GROUP_CONTAINS_PCDATA|GROUP_CONTAINS_GROUP|GROUP_CONTAINS_ELEMENT_NAME; private void analyzeEmptySemanticParticle() { if ((groupFlags & GROUP_MODEL_GROUP_FLAGS) == 0) { semantic = SEMANTIC_ENUM_GROUP; return; } if ((groupFlags & GROUP_CONTAINS_NMTOKEN) == 0) { switch (groupFlags & (GROUP_CONTAINS_SEQ|GROUP_CONTAINS_OR)) { case 0: groupFlags |= GROUP_CONTAINS_OR; // fall through case GROUP_CONTAINS_SEQ: case GROUP_CONTAINS_OR: semantic = SEMANTIC_MODEL_GROUP; return; } } problem = EMPTY_PARTICLE_PROBLEM; } ModelGroup toModelGroup() { if (referenceLevel == PARAM_LEVEL) return Param.paramsToModelGroup(parsed); if (parsed.size() == 0) { if ((groupFlags & GROUP_CONTAINS_SEQ) != 0) return new Sequence(new ModelGroup[0]); else return new Choice(new ModelGroup[0]); } return Particle.particlesToModelGroup(parsed); } EnumGroup toEnumGroup() { if (referenceLevel == PARTICLE_LEVEL) return Particle.particlesToEnumGroup(parsed); else return Particle.particlesToEnumGroup(((Param)parsed.elementAt(0)).group.particles); } NameSpec toNameSpec() { if (referenceLevel == PARTICLE_LEVEL) return new Name(((Particle)parsed.elementAt(0)).value); else return Param.paramsToNameSpec(parsed); } ExternalId getExternalId() { return new ExternalId(systemId, publicId, baseUri); } void noteReferenced() { if (problem == UNREFERENCED_PROBLEM) problem = NO_PROBLEM; if (overrides != null) overrides.noteReferenced(); } String ambiguousNameSpec() { if (problem != NO_PROBLEM || referenceLevel != PARTICLE_LEVEL || parsed.size() != 1) return null; Particle p = (Particle)parsed.elementAt(0); if (p.type != Particle.ELEMENT_NAME) return null; maybeNameSpec = true; return p.value; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Notation.java000066400000000000000000000005141225366607500322020ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import com.thaiopensource.xml.em.ExternalId; class Notation { final String name; String systemId; String publicId; String baseUri; Notation(String name) { this.name = name; } ExternalId getExternalId() { return new ExternalId(systemId, publicId, baseUri); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Param.java000066400000000000000000000137671225366607500314650ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Vector; import java.util.Enumeration; import com.thaiopensource.xml.dtd.om.*; class Param { static final int REFERENCE = 0; static final int REFERENCE_END = 1; static final int LITERAL = 2; static final int MODEL_GROUP = 3; static final int PERCENT = 4; static final int IMPLIED = 5; // #IMPLIED static final int REQUIRED = 6; // #REQUIRED static final int FIXED = 7; // #REQUIRED static final int EMPTY = 8; static final int ANY = 9; static final int ELEMENT_NAME = 10; // name after 0) { int level = 0; for (;;) { p = (Param)v.elementAt(i++); if (p.type == Param.REFERENCE) level++; else if (p.type == Param.REFERENCE_END && level-- == 0) break; } return true; } break; case Param.REFERENCE_END: break; default: return true; } } type = -1; return false; } } ParseException.java000066400000000000000000000020471225366607500332640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parsepackage com.thaiopensource.xml.dtd.parse; import java.io.IOException; import com.thaiopensource.util.Localizer; public class ParseException extends IOException { private final Localizer localizer; private final String location; private final int lineNumber; private final int columnNumber; public ParseException(Localizer localizer, String message, String location, int lineNumber, int columnNumber) { super(message); this.localizer = localizer; this.lineNumber = lineNumber; this.columnNumber = columnNumber; this.location = location; } public int getLineNumber() { return lineNumber; } public int getColumnNumber() { return columnNumber; } public String getLocation() { return location; } public String getMessage() { return localizer.message("MESSAGE", new Object[] { super.getMessage(), location, new Integer(lineNumber), new Integer(columnNumber) }); } public String getMessageBody() { return super.getMessage(); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Parser.java000066400000000000000000000522641225366607500316540ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import com.thaiopensource.util.Localizer; import com.thaiopensource.xml.em.EntityManager; import com.thaiopensource.xml.em.ExternalId; import com.thaiopensource.xml.em.OpenEntity; import com.thaiopensource.xml.tok.EmptyTokenException; import com.thaiopensource.xml.tok.EndOfPrologException; import com.thaiopensource.xml.tok.ExtensibleTokenException; import com.thaiopensource.xml.tok.InvalidTokenException; import com.thaiopensource.xml.tok.PartialTokenException; import com.thaiopensource.xml.tok.Position; import com.thaiopensource.xml.tok.TextDecl; import com.thaiopensource.xml.tok.Token; import com.thaiopensource.xml.tok.Tokenizer; import java.io.IOException; import java.io.Reader; import java.util.Hashtable; import java.util.Vector; class Parser extends Token { static final Localizer localizer = new Localizer(Parser.class); private Parser parent; private Reader in; private char[] buf; private int bufStart = 0; private int bufEnd; private int currentTokenStart = 0; // The offset in buffer corresponding to pos. private int posOff = 0; private long bufEndStreamOffset = 0; private final Position pos = new Position(); private static final int READSIZE = 1024*8; // Some temporary buffers private final ReplacementTextBuffer valueBuf; private final DtdBuilder db; private final Vector atoms = new Vector(); private final boolean isInternal; private final String baseUri; private final EntityManager entityManager; // for error messages private String location; private final Hashtable atomTable; private final Hashtable elementTable; static class DeclState { Entity entity; Notation notation; } Parser(OpenEntity entity, EntityManager entityManager) { this.in = entity.getReader(); this.baseUri = entity.getBaseUri(); this.location = entity.getLocation(); this.entityManager = entityManager; this.buf = new char[READSIZE * 2]; this.valueBuf = new ReplacementTextBuffer(); this.bufEnd = 0; this.db = new DtdBuilder(atoms); this.isInternal = false; this.elementTable = new Hashtable(); this.atomTable = new Hashtable(); } private Parser(OpenEntity entity, Parser parent) { this.in = entity.getReader(); this.baseUri = entity.getBaseUri(); this.location = entity.getLocation(); this.entityManager = parent.entityManager; this.parent = parent; this.buf = new char[READSIZE * 2]; this.valueBuf = new ReplacementTextBuffer(); this.bufEnd = 0; this.db = parent.db; this.isInternal = false; this.elementTable = parent.elementTable; this.atomTable = parent.atomTable; } private Parser(char[] buf, String entityName, Parser parent) { // this.internalEntityName = entityName; this.buf = buf; this.parent = parent; this.baseUri = parent.baseUri; this.entityManager = parent.entityManager; this.bufEnd = buf.length; this.bufEndStreamOffset = buf.length; this.valueBuf = parent.valueBuf; this.db = parent.db; this.isInternal = true; this.elementTable = parent.elementTable; this.atomTable = parent.atomTable; } DtdBuilder parse() throws IOException { skipTextDecl(); parseDecls(false); return db; } private void parseDecls(boolean isInternal) throws IOException { PrologParser pp = new PrologParser(isInternal ? PrologParser.INTERNAL_ENTITY : PrologParser.EXTERNAL_ENTITY); DeclState declState = new DeclState(); try { for (;;) { int tok; try { tok = tokenizeProlog(); } catch (EndOfPrologException e) { fatal("SYNTAX_ERROR"); break; } catch (EmptyTokenException e) { pp.end(); break; } prologAction(tok, pp, declState); } } catch (PrologSyntaxException e) { fatal("SYNTAX_ERROR"); } finally { if (!isInternal && in != null) { in.close(); in = null; } } } private void prologAction(int tok, PrologParser pp, DeclState declState) throws IOException, PrologSyntaxException { Atom a = makeAtom(tok, currentTokenStart, bufStart); addAtom(a); String token = a.getToken(); int action = pp.action(tok, token); switch (action) { case PrologParser.ACTION_IGNORE_SECT: skipIgnoreSect(); break; case PrologParser.ACTION_GENERAL_ENTITY_NAME: declState.entity = db.createGeneralEntity(token); break; case PrologParser.ACTION_PARAM_ENTITY_NAME: declState.entity = db.createParamEntity(token); break; case PrologParser.ACTION_ENTITY_PUBLIC_ID: try { declState.entity.publicId = Tokenizer.getPublicId(buf, currentTokenStart, bufStart); } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); fatal("INVALID_PUBLIC_ID"); } break; case PrologParser.ACTION_ENTITY_SYSTEM_ID: declState.entity.systemId = token.substring(1, token.length() - 1); declState.entity.baseUri = baseUri; break; case PrologParser.ACTION_ENTITY_NOTATION_NAME: declState.entity.notationName = token; break; case PrologParser.ACTION_ENTITY_VALUE_WITH_PEREFS: makeReplacementText(); declState.entity.text = valueBuf.getChars(); declState.entity.entityValue = token.substring(1, token.length() - 1); declState.entity.mustReparse = valueBuf.getMustReparse(); declState.entity.references = valueBuf.getReferences(); if (declState.entity.mustReparse) declState.entity.problem = Entity.REPARSE_PROBLEM; else if (declState.entity.overridden && declState.entity.isParameter) declState.entity.atoms = tokenizeOverriddenEntity(declState.entity.text); break; case PrologParser.ACTION_INNER_PARAM_ENTITY_REF: case PrologParser.ACTION_OUTER_PARAM_ENTITY_REF: { int nameStart = currentTokenStart + 1; String name = new String(buf, nameStart, getNameEnd() - nameStart); Entity entity = db.lookupParamEntity(name); if (entity == null) { fatal("UNDEF_PEREF", name); break; } Parser parser = makeParserForEntity(entity, name); if (parser == null) { //XXX break; } entity.open = true; if (action == PrologParser.ACTION_OUTER_PARAM_ENTITY_REF) parser.parseDecls(entity.text != null); else parser.parseInnerParamEntity(pp, declState); entity.atoms = parser.atoms; setLastAtomEntity(entity); entity.open = false; break; } case PrologParser.ACTION_ELEMENT_NAME: if (elementTable.get(token) != null) fatal("DUPLICATE_ELEMENT", token); elementTable.put(token, token); break; case PrologParser.ACTION_NOTATION_NAME: declState.notation = db.createNotation(token); if (declState.notation == null) fatal("DUPLICATE_NOTATION", token); break; case PrologParser.ACTION_NOTATION_PUBLIC_ID: try { declState.notation.publicId = Tokenizer.getPublicId(buf, currentTokenStart, bufStart); } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); fatal("INVALID_PUBLIC_ID"); } break; case PrologParser.ACTION_NOTATION_SYSTEM_ID: declState.notation.systemId = token.substring(1, token.length() - 1); declState.notation.baseUri = baseUri; break; case PrologParser.ACTION_DEFAULT_ATTRIBUTE_VALUE: { String origValue = token.substring(1, token.length() - 1); if (db.getNormalized(origValue) != null) break; StringBuffer tem = new StringBuffer(); try { normalizeAttributeValue(buf, currentTokenStart + 1, bufStart - 1, tem); } catch (AttributeValueException e) { currentTokenStart = e.offset; if (e.arg != null) fatal(e.key, e.arg); else fatal(e.key); } db.setNormalized(origValue, tem.toString()); break; } } } void parseInnerParamEntity(PrologParser pp, DeclState declState) throws IOException { int groupLevel = pp.getGroupLevel(); try { for (;;) { int tok = tokenizeProlog(); prologAction(tok, pp, declState); switch (tok) { case Tokenizer.TOK_DECL_CLOSE: case Tokenizer.TOK_OPEN_BRACKET: fatal("PE_DECL_NESTING"); } } } catch (EndOfPrologException e) { fatal("SYNTAX_ERROR"); } catch (PrologSyntaxException e) { fatal("SYNTAX_ERROR"); } catch (EmptyTokenException e) { } if (pp.getGroupLevel() != groupLevel) fatal("PE_GROUP_NESTING"); } private Parser makeParserForEntity(Entity entity, String name) throws IOException { entity.noteReferenced(); if (entity.open) fatal("RECURSION"); if (entity.notationName != null) fatal("UNPARSED_REF"); if (entity.text != null) return new Parser(entity.text, name, this); OpenEntity openEntity = entityManager.open(new ExternalId(entity.systemId, entity.publicId, entity.baseUri), entity.isParameter, entity.name); if (openEntity == null) return null; entity.encoding = openEntity.getEncoding(); entity.uri = openEntity.getBaseUri(); Parser p = new Parser(openEntity, this); p.skipTextDecl(); return p; } /* * Make the replacement text for an entity out of the literal in the * current token. */ private void makeReplacementText() throws IOException { valueBuf.clear(); Token t = new Token(); int start = currentTokenStart + 1; final int end = bufStart - 1; try { for (;;) { int tok; int nextStart; try { tok = Tokenizer.tokenizeEntityValue(buf, start, end, t); nextStart = t.getTokenEnd(); } catch (ExtensibleTokenException e) { tok = e.getTokenType(); nextStart = end; } handleEntityValueToken(valueBuf, tok, start, nextStart, t); start = nextStart; } } catch (PartialTokenException e) { currentTokenStart = end; fatal("NOT_WELL_FORMED"); } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); reportInvalidToken(e); } catch (EmptyTokenException e) { } } private void parseEntityValue(ReplacementTextBuffer value) throws IOException { final Token t = new Token(); for (;;) { int tok; for (;;) { try { tok = Tokenizer.tokenizeEntityValue(buf, bufStart, bufEnd, t); currentTokenStart = bufStart; bufStart = t.getTokenEnd(); break; } catch (EmptyTokenException e) { if (!fill()) return; } catch (PartialTokenException e) { if (!fill()) { currentTokenStart = bufStart; bufStart = bufEnd; fatal("UNCLOSED_TOKEN"); } } catch (ExtensibleTokenException e) { if (!fill()) { currentTokenStart = bufStart; bufStart = bufEnd; tok = e.getTokenType(); break; } } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); reportInvalidToken(e); } } handleEntityValueToken(value, tok, currentTokenStart, bufStart, t); } } private void handleEntityValueToken(ReplacementTextBuffer value, int tok, int start, int end, Token t) throws IOException { switch (tok) { case Tokenizer.TOK_DATA_NEWLINE: if (!isInternal) { value.append('\n'); break; } // fall through case Tokenizer.TOK_DATA_CHARS: case Tokenizer.TOK_ENTITY_REF: case Tokenizer.TOK_MAGIC_ENTITY_REF: value.append(buf, start, end); break; case Tokenizer.TOK_CHAR_REF: { char c = t.getRefChar(); if (c == '&' || c == '%') value.setMustReparse(); value.append(t.getRefChar()); } break; case Tokenizer.TOK_CHAR_PAIR_REF: value.appendRefCharPair(t); break; case Tokenizer.TOK_PARAM_ENTITY_REF: String name = new String(buf, start + 1, end - start - 2); Entity entity = db.lookupParamEntity(name); if (entity == null) { fatal("UNDEF_PEREF", name); break; } if (entity.text != null && !entity.mustReparse) { entity.noteReferenced(); value.appendReplacementText(entity); } else { Parser parser = makeParserForEntity(entity, name); if (parser != null) { entity.open = true; parser.parseEntityValue(value); entity.open = false; } } break; default: throw new Error("replacement text botch"); } } private void skipTextDecl() throws IOException { try { if (tokenizeProlog() != Tokenizer.TOK_XML_DECL) { currentTokenStart = bufStart = 0; return; } try { new TextDecl(buf, currentTokenStart, bufStart); } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); fatal("INVALID_TEXT_DECL"); } } catch (EmptyTokenException e) { } catch (EndOfPrologException e) { } } private final int tokenizeProlog() throws IOException, EmptyTokenException, EndOfPrologException { for (;;) { try { int tok = Tokenizer.tokenizeProlog(buf, bufStart, bufEnd, this); currentTokenStart = bufStart; bufStart = getTokenEnd(); return tok; } catch (EmptyTokenException e) { if (!fill()) throw e; } catch (PartialTokenException e) { if (!fill()) { currentTokenStart = bufStart; bufStart = bufEnd; fatal("UNCLOSED_TOKEN"); } } catch (ExtensibleTokenException e) { if (!fill()) { currentTokenStart = bufStart; bufStart = bufEnd; return e.getTokenType(); } } catch (InvalidTokenException e) { bufStart = currentTokenStart = e.getOffset(); reportInvalidToken(e); } } } private final void skipIgnoreSect() throws IOException { for (;;) { try { int sectStart = bufStart; bufStart = Tokenizer.skipIgnoreSect(buf, bufStart, bufEnd); addAtom(new Atom(Tokenizer.TOK_COND_SECT_CLOSE, bufferString(sectStart, bufStart))); return; } catch (PartialTokenException e) { if (!fill()) { currentTokenStart = bufStart; fatal("UNCLOSED_CONDITIONAL_SECTION"); } } catch (InvalidTokenException e) { currentTokenStart = e.getOffset(); fatal("IGNORE_SECT_CHAR"); } } } private Vector tokenizeOverriddenEntity(char[] text) { Vector v = new Vector(); int level = 0; try { Token t = new Token(); int start = 0; for (;;) { int tok; int tokenEnd; try { tok = Tokenizer.tokenizeProlog(text, start, text.length, t); tokenEnd = t.getTokenEnd(); } catch (ExtensibleTokenException e) { tok = e.getTokenType(); tokenEnd = text.length; } switch (tok) { case Tokenizer.TOK_COND_SECT_OPEN: case Tokenizer.TOK_OPEN_PAREN: case Tokenizer.TOK_OPEN_BRACKET: case Tokenizer.TOK_DECL_OPEN: level++; break; case Tokenizer.TOK_CLOSE_PAREN: case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: case Tokenizer.TOK_CLOSE_PAREN_QUESTION: case Tokenizer.TOK_CLOSE_PAREN_PLUS: case Tokenizer.TOK_CLOSE_BRACKET: case Tokenizer.TOK_DECL_CLOSE: if (--level < 0) return null; break; case Tokenizer.TOK_COND_SECT_CLOSE: if ((level -= 2) < 0) return null; break; } v.addElement(new Atom(tok, new String(text, start, tokenEnd - start))); start = tokenEnd; } } catch (EmptyTokenException e) { if (level != 0) return null; return v; } catch (EndOfPrologException e) { } catch (PartialTokenException e) { } catch (InvalidTokenException e) { } return null; } /* The size of the buffer is always a multiple of READSIZE. We do reads so that a complete read would end at the end of the buffer. Unless there has been an incomplete read, we always read in multiples of READSIZE. */ private boolean fill() throws IOException { if (in == null) return false; if (bufEnd == buf.length) { Tokenizer.movePosition(buf, posOff, bufStart, pos); /* The last read was complete. */ int keep = bufEnd - bufStart; if (keep == 0) bufEnd = 0; else if (keep + READSIZE <= buf.length) { /* * There is space in the buffer for at least READSIZE bytes. * Choose bufEnd so that it is the least non-negative integer * greater than or equal to keep, such * bufLength - keep is a multiple of READSIZE. */ bufEnd = buf.length - (((buf.length - keep)/READSIZE) * READSIZE); for (int i = 0; i < keep; i++) buf[bufEnd - keep + i] = buf[bufStart + i]; } else { char newBuf[] = new char[buf.length << 1]; bufEnd = buf.length; System.arraycopy(buf, bufStart, newBuf, bufEnd - keep, keep); buf = newBuf; } bufStart = bufEnd - keep; posOff = bufStart; } int nChars = in.read(buf, bufEnd, buf.length - bufEnd); if (nChars < 0) { in.close(); in = null; return false; } bufEnd += nChars; bufEndStreamOffset += nChars; return true; } private void fatal(String key, String arg) throws ParseException { doFatal(localizer.message(key, arg)); } private void fatal(String key) throws ParseException { doFatal(localizer.message(key)); } private void doFatal(String message) throws ParseException { if (isInternal) parent.doFatal(message); if (posOff > currentTokenStart) throw new Error("positioning botch"); Tokenizer.movePosition(buf, posOff, currentTokenStart, pos); posOff = currentTokenStart; throw new ParseException(localizer, message, location, pos.getLineNumber(), pos.getColumnNumber()); } private void reportInvalidToken(InvalidTokenException e) throws ParseException { if (e.getType() == InvalidTokenException.XML_TARGET) fatal("XML_TARGET"); else fatal("ILLEGAL_CHAR"); } private void addAtom(Atom a) { atoms.addElement(a); } private void setLastAtomEntity(Entity e) { Atom a = (Atom)atoms.elementAt(atoms.size() - 1); atoms.setElementAt(new Atom(a.getTokenType(), a.getToken(), e), atoms.size() - 1); } private final String bufferString(int start, int end) { return normalizeNewlines(new String(buf, start, end - start)); } private final String normalizeNewlines(String str) { if (isInternal) return str; int i = str.indexOf('\r'); if (i < 0) return str; StringBuffer buf = new StringBuffer(); for (i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '\r') { buf.append('\n'); if (i + 1 < str.length() && str.charAt(i + 1) == '\n') i++; } else buf.append(c); } return buf.toString(); } static class AttributeValueException extends Exception { final int offset; final String key; final String arg; AttributeValueException(String key, int offset) { this.key = key; this.arg = null; this.offset = offset; } AttributeValueException(String key, String arg, int offset) { this.key = key; this.arg = arg; this.offset = offset; } } private void normalizeAttributeValue(char[] b, int start, int end, StringBuffer result) throws AttributeValueException { Token t = new Token(); for (;;) { int tok; int nextStart; try { tok = Tokenizer.tokenizeAttributeValue(b, start, end, t); nextStart = t.getTokenEnd(); } catch (PartialTokenException e) { throw new AttributeValueException("NOT_WELL_FORMED", end); } catch (InvalidTokenException e) { throw new AttributeValueException("ILLEGAL_CHAR", e.getOffset()); } catch (EmptyTokenException e) { return; } catch (ExtensibleTokenException e) { tok = e.getTokenType(); nextStart = end; } switch (tok) { case Tokenizer.TOK_DATA_NEWLINE: if (b == buf && !isInternal) result.append(' '); else { for (int i = start; i < nextStart; i++) result.append(' '); } break; case Tokenizer.TOK_DATA_CHARS: result.append(b, start, nextStart - start); break; case Tokenizer.TOK_MAGIC_ENTITY_REF: case Tokenizer.TOK_CHAR_REF: result.append(t.getRefChar()); break; case Tokenizer.TOK_CHAR_PAIR_REF: { char[] pair = new char[2]; t.getRefCharPair(pair, 0); result.append(pair); } break; case Tokenizer.TOK_ATTRIBUTE_VALUE_S: result.append(' '); break; case Tokenizer.TOK_ENTITY_REF: String name = new String(b, start + 1, nextStart - start - 2); Entity entity = db.lookupGeneralEntity(name); if (entity == null) throw new AttributeValueException("UNDEF_REF", name, start); if (entity.systemId != null) throw new AttributeValueException("EXTERN_REF_ATTVAL", name, start); try { if (entity.open) throw new AttributeValueException("RECURSION", start); entity.open = true; normalizeAttributeValue(entity.text, 0, entity.text.length, result); entity.open = false; } catch (AttributeValueException e) { throw new AttributeValueException(e.key, e.arg, start); } break; default: throw new Error("attribute value botch"); } start = nextStart; } } private Atom makeAtom(int tok, int start, int end) { String token = null; if (end - start == 1) { switch (buf[start]) { case ' ': token = " "; break; case '\t': token = "\t"; break; case '\n': token = "\n"; break; case ',': token = ","; break; case '|': token = "|"; break; case '(': token = "("; break; case ')': token = ")"; break; } } else if (end - start == 2 && buf[start] == '\r' && buf[start + 1] == '\n') token = "\n"; if (token == null) token = bufferString(start, end); Atom a = (Atom)atomTable.get(token); if (a == null) { a = new Atom(tok, token); atomTable.put(token, a); } return a; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/Particle.java000066400000000000000000000114601225366607500321540ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import java.util.Vector; import java.util.Enumeration; import com.thaiopensource.xml.dtd.om.*; class Particle { static final int REFERENCE = 0; // entity static final int GROUP = 1; // particles + occur static final int ELEMENT_NAME = 2; // value + occur static final int NMTOKEN = 3; // value static final int PCDATA = 4; static final int REFERENCE_END = 5; static final int CONNECT_OR = 6; static final int CONNECT_SEQ = 7; Particle(int type) { this.type = type; } final int type; char occur; // * ? + or 0 Vector particles; Entity entity; String value; public boolean equals(Object obj) { if (obj == null || !(obj instanceof Particle)) return false; Particle other = (Particle)obj; if (this.type != other.type) return false; if (this.occur != other.occur) return false; if (this.entity != other.entity) return false; if (this.value != null && !this.value.equals(other.value)) return false; if (this.particles != null) { int n = this.particles.size(); if (other.particles.size() != n) return false; for (int i = 0; i < n; i++) if (!this.particles.elementAt(i).equals(other.particles.elementAt(i))) return false; } return true; } ModelGroup createModelGroup() { ModelGroup mg; switch (type) { case GROUP: mg = particlesToModelGroup(particles); break; case ELEMENT_NAME: mg = new ElementRef(new Name(value)); break; case PCDATA: mg = new Pcdata(); break; default: return null; } switch (occur) { case '?': mg = new Optional(mg); break; case '+': mg = new OneOrMore(mg); break; case '*': mg = new ZeroOrMore(mg); break; } return mg; } static ModelGroup particlesToModelGroup(Vector v) { Vector mgs = new Vector(); int len = v.size(); boolean isSequence = false; for(int i = 0; i < len; i++) { ModelGroup mg = null; Particle p = (Particle)v.elementAt(i); switch (p.type) { case REFERENCE: switch (p.entity.semantic) { case Entity.SEMANTIC_MODEL_GROUP: mg = new ModelGroupRef(p.entity.name, p.entity.modelGroup); if (p.entity.parsed.size() == 0 && ((p.entity.groupFlags & Entity.GROUP_CONTAINS_SEQ) != 0)) isSequence = true; i = indexOfReferenceEnd(v, i); break; case Entity.SEMANTIC_NAME_SPEC: mg = new ElementRef(new NameSpecRef(p.entity.name, p.entity.nameSpec)); i = indexOfReferenceEnd(v, i); break; } break; case GROUP: case ELEMENT_NAME: case PCDATA: mg = p.createModelGroup(); break; case CONNECT_SEQ: isSequence = true; break; } if (mg != null) mgs.addElement(mg); } if (mgs.size() == 0) return null; if (mgs.size() == 1) return (ModelGroup)mgs.elementAt(0); ModelGroup[] tem = new ModelGroup[mgs.size()]; for (int i = 0; i < tem.length; i++) tem[i] = (ModelGroup)mgs.elementAt(i); if (isSequence) return new Sequence(tem); else return new Choice(tem); } private static int indexOfReferenceEnd(Vector v, int i) { int level = 0; for (;;) { Particle p = (Particle)v.elementAt(++i); if (p.type == REFERENCE) level++; else if (p.type == REFERENCE_END && level-- == 0) break; } return i; } static EnumGroup particlesToEnumGroup(Vector v) { int len = v.size(); Vector eg = new Vector(); for(int i = 0; i < len; i++) { EnumGroupMember egm = null; Particle p = (Particle)v.elementAt(i); switch (p.type) { case REFERENCE: if (p.entity.semantic == Entity.SEMANTIC_ENUM_GROUP) { egm = new EnumGroupRef(p.entity.name, p.entity.enumGroup); int level = 0; for (;;) { p = (Particle)v.elementAt(++i); if (p.type == REFERENCE) level++; else if (p.type == REFERENCE_END && level-- == 0) break; } } break; case NMTOKEN: egm = new EnumValue(p.value); break; } if (egm != null) eg.addElement(egm); } EnumGroupMember[] members = new EnumGroupMember[eg.size()]; for (int i = 0; i < members.length; i++) members[i] = (EnumGroupMember)eg.elementAt(i); return new EnumGroup(members); } static void examineElementNames(DtdBuilder db, Enumeration particles) { Entity prevEntity = null; while (particles.hasMoreElements()) { Particle particle = (Particle)particles.nextElement(); Entity curEntity = null; switch (particle.type) { case REFERENCE: curEntity = particle.entity; break; case ELEMENT_NAME: db.noteElementName(particle.value, prevEntity); break; case GROUP: examineElementNames(db, particle.particles.elements()); break; } prevEntity = curEntity; } } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/PrologParser.java000066400000000000000000000561211225366607500330330ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.parse; import com.thaiopensource.xml.tok.Tokenizer; /** * Parses the prolog of an XML document. * A PrologParser object represents the state of a parse * of the prolog. * It operates on the tokens returned * by Tokenizer.tokenizeProlog. * It does not build any data structures to represent the information * in the prolog; instead it tells the caller the action needed * for each token. * The state of the parse can be saved by using the clone * method. */ public class PrologParser implements Cloneable { public static final int ACTION_NONE = 0; public static final int ACTION_XML_DECL = ACTION_NONE + 1; public static final int ACTION_TEXT_DECL = ACTION_XML_DECL + 1; public static final int ACTION_PI = ACTION_TEXT_DECL + 1; public static final int ACTION_COMMENT = ACTION_PI + 1; public static final int ACTION_DOCTYPE_NAME = ACTION_COMMENT + 1; public static final int ACTION_DOCTYPE_SYSTEM_ID = ACTION_DOCTYPE_NAME + 1; public static final int ACTION_DOCTYPE_PUBLIC_ID = ACTION_DOCTYPE_SYSTEM_ID + 1; public static final int ACTION_DOCTYPE_SUBSET = ACTION_DOCTYPE_PUBLIC_ID + 1; public static final int ACTION_DOCTYPE_CLOSE = ACTION_DOCTYPE_SUBSET + 1; public static final int ACTION_GENERAL_ENTITY_NAME = ACTION_DOCTYPE_CLOSE + 1; public static final int ACTION_PARAM_ENTITY_NAME = ACTION_GENERAL_ENTITY_NAME + 1; public static final int ACTION_ENTITY_VALUE_WITH_PEREFS = ACTION_PARAM_ENTITY_NAME + 1; public static final int ACTION_ENTITY_VALUE_NO_PEREFS = ACTION_ENTITY_VALUE_WITH_PEREFS + 1; public static final int ACTION_ENTITY_SYSTEM_ID = ACTION_ENTITY_VALUE_NO_PEREFS + 1; public static final int ACTION_ENTITY_PUBLIC_ID = ACTION_ENTITY_SYSTEM_ID + 1; public static final int ACTION_ENTITY_NOTATION_NAME = ACTION_ENTITY_PUBLIC_ID + 1; public static final int ACTION_NOTATION_NAME = ACTION_ENTITY_NOTATION_NAME + 1; public static final int ACTION_NOTATION_SYSTEM_ID = ACTION_NOTATION_NAME + 1; public static final int ACTION_NOTATION_PUBLIC_ID = ACTION_NOTATION_SYSTEM_ID + 1; public static final int ACTION_ATTRIBUTE_NAME = ACTION_NOTATION_PUBLIC_ID + 1; public static final int ACTION_ATTRIBUTE_TYPE_CDATA = ACTION_ATTRIBUTE_NAME + 1; public static final int ACTION_ATTRIBUTE_TYPE_ID = ACTION_ATTRIBUTE_TYPE_CDATA + 1; public static final int ACTION_ATTRIBUTE_TYPE_IDREF = ACTION_ATTRIBUTE_TYPE_ID + 1; public static final int ACTION_ATTRIBUTE_TYPE_IDREFS = ACTION_ATTRIBUTE_TYPE_IDREF + 1; public static final int ACTION_ATTRIBUTE_TYPE_ENTITY = ACTION_ATTRIBUTE_TYPE_IDREFS + 1; public static final int ACTION_ATTRIBUTE_TYPE_ENTITIES = ACTION_ATTRIBUTE_TYPE_ENTITY + 1; public static final int ACTION_ATTRIBUTE_TYPE_NMTOKEN = ACTION_ATTRIBUTE_TYPE_ENTITIES + 1; public static final int ACTION_ATTRIBUTE_TYPE_NMTOKENS = ACTION_ATTRIBUTE_TYPE_NMTOKEN + 1; public static final int ACTION_ATTRIBUTE_TYPE_NOTATION = ACTION_ATTRIBUTE_TYPE_NMTOKENS + 1; public static final int ACTION_ATTRIBUTE_ENUM_VALUE = ACTION_ATTRIBUTE_TYPE_NOTATION + 1; public static final int ACTION_ATTRIBUTE_NOTATION_VALUE = ACTION_ATTRIBUTE_ENUM_VALUE + 1; public static final int ACTION_ATTLIST_ELEMENT_NAME = ACTION_ATTRIBUTE_NOTATION_VALUE + 1; public static final int ACTION_IMPLIED_ATTRIBUTE_VALUE = ACTION_ATTLIST_ELEMENT_NAME + 1; public static final int ACTION_REQUIRED_ATTRIBUTE_VALUE = ACTION_IMPLIED_ATTRIBUTE_VALUE + 1; public static final int ACTION_DEFAULT_ATTRIBUTE_VALUE = ACTION_REQUIRED_ATTRIBUTE_VALUE + 1; public static final int ACTION_FIXED_ATTRIBUTE_VALUE = ACTION_DEFAULT_ATTRIBUTE_VALUE + 1; public static final int ACTION_ELEMENT_NAME = ACTION_FIXED_ATTRIBUTE_VALUE + 1; public static final int ACTION_CONTENT_ANY = ACTION_ELEMENT_NAME + 1; public static final int ACTION_CONTENT_EMPTY = ACTION_CONTENT_ANY + 1; public static final int ACTION_CONTENT_PCDATA = ACTION_CONTENT_EMPTY + 1; public static final int ACTION_GROUP_OPEN = ACTION_CONTENT_PCDATA + 1; public static final int ACTION_GROUP_CLOSE = ACTION_GROUP_OPEN + 1; public static final int ACTION_GROUP_CLOSE_REP = ACTION_GROUP_CLOSE + 1; public static final int ACTION_GROUP_CLOSE_OPT = ACTION_GROUP_CLOSE_REP + 1; public static final int ACTION_GROUP_CLOSE_PLUS = ACTION_GROUP_CLOSE_OPT + 1; public static final int ACTION_GROUP_CHOICE = ACTION_GROUP_CLOSE_PLUS + 1; public static final int ACTION_GROUP_SEQUENCE = ACTION_GROUP_CHOICE + 1; public static final int ACTION_CONTENT_ELEMENT = ACTION_GROUP_SEQUENCE + 1; public static final int ACTION_CONTENT_ELEMENT_REP = ACTION_CONTENT_ELEMENT + 1; public static final int ACTION_CONTENT_ELEMENT_OPT = ACTION_CONTENT_ELEMENT_REP + 1; public static final int ACTION_CONTENT_ELEMENT_PLUS = ACTION_CONTENT_ELEMENT_OPT + 1; public static final int ACTION_OUTER_PARAM_ENTITY_REF = ACTION_CONTENT_ELEMENT_PLUS + 1; public static final int ACTION_INNER_PARAM_ENTITY_REF = ACTION_OUTER_PARAM_ENTITY_REF + 1; public static final int ACTION_IGNORE_SECT = ACTION_INNER_PARAM_ENTITY_REF + 1; public static final int ACTION_DECL_CLOSE = ACTION_IGNORE_SECT + 1; public static final int ACTION_ENUM_GROUP_OPEN = ACTION_DECL_CLOSE + 1; public static final int ACTION_NOTATION_GROUP_OPEN = ACTION_ENUM_GROUP_OPEN + 1; public static final int ACTION_SECTION_STATUS_IGNORE = ACTION_NOTATION_GROUP_OPEN + 1; public static final int ACTION_SECTION_STATUS_INCLUDE = ACTION_SECTION_STATUS_IGNORE + 1; private static final byte prolog0 = 0; private static final byte prolog1 = prolog0 + 1; private static final byte prolog2 = prolog1 + 1; private static final byte doctype0 = prolog2 + 1; private static final byte doctype1 = doctype0 + 1; private static final byte doctype2 = doctype1 + 1; private static final byte doctype3 = doctype2 + 1; private static final byte doctype4 = doctype3 + 1; private static final byte doctype5 = doctype4 + 1; private static final byte internalSubset = doctype5 + 1; private static final byte entity0 = internalSubset + 1; private static final byte entity1 = entity0 + 1; private static final byte entity2 = entity1 + 1; private static final byte entity3 = entity2 + 1; private static final byte entity4 = entity3 + 1; private static final byte entity5 = entity4 + 1; private static final byte entity6 = entity5 + 1; private static final byte entity7 = entity6 + 1; private static final byte entity8 = entity7 + 1; private static final byte entity9 = entity8 + 1; private static final byte notation0 = entity9 + 1; private static final byte notation1 = notation0 + 1; private static final byte notation2 = notation1 + 1; private static final byte notation3 = notation2 + 1; private static final byte notation4 = notation3 + 1; private static final byte attlist0 = notation4 + 1; private static final byte attlist1 = attlist0 + 1; private static final byte attlist2 = attlist1 + 1; private static final byte attlist3 = attlist2 + 1; private static final byte attlist4 = attlist3 + 1; private static final byte attlist5 = attlist4 + 1; private static final byte attlist6 = attlist5 + 1; private static final byte attlist7 = attlist6 + 1; private static final byte attlist8 = attlist7 + 1; private static final byte attlist9 = attlist8 + 1; private static final byte element0 = attlist9 + 1; private static final byte element1 = element0 + 1; private static final byte element2 = element1 + 1; private static final byte element3 = element2 + 1; private static final byte element4 = element3 + 1; private static final byte element5 = element4 + 1; private static final byte element6 = element5 + 1; private static final byte element7 = element6 + 1; private static final byte declClose = element7 + 1; private static final byte externalSubset0 = declClose + 1; private static final byte externalSubset1 = externalSubset0 + 1; private static final byte condSect0 = externalSubset1 + 1; private static final byte condSect1 = condSect0 + 1; private static final byte condSect2 = condSect1 + 1; private byte state; private int groupLevel; private int includeLevel; private byte connector[] = new byte[2]; private boolean documentEntity; public static final byte PROLOG = 0; public static final byte EXTERNAL_ENTITY = 1; public static final byte INTERNAL_ENTITY = 2; public PrologParser(byte type) { switch (type) { case PROLOG: documentEntity = true; state = prolog0; break; case EXTERNAL_ENTITY: documentEntity = false; state = externalSubset0; break; case INTERNAL_ENTITY: documentEntity = false; state = externalSubset1; break; default: throw new IllegalArgumentException(); } } public final void end() throws PrologSyntaxException { switch (state) { case prolog0: case prolog1: case prolog2: break; case externalSubset0: case externalSubset1: if (includeLevel == 0) break; /* fall through */ default: throw new PrologSyntaxException(); } } public int action(int tok, String token) throws PrologSyntaxException { switch (state) { case prolog0: state = prolog1; if (tok == Tokenizer.TOK_XML_DECL) return ACTION_XML_DECL; /* fall through */ case prolog1: if (tok == Tokenizer.TOK_DECL_OPEN && matches(token, 2, "DOCTYPE")) { state = doctype0; return ACTION_NONE; } /* fall through */ case prolog2: switch (tok) { case Tokenizer.TOK_PI: return ACTION_PI; case Tokenizer.TOK_COMMENT: return ACTION_COMMENT; } break; case doctype0: switch (tok) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = doctype1; return ACTION_DOCTYPE_NAME; } break; case doctype1: switch (tok) { case Tokenizer.TOK_OPEN_BRACKET: state = internalSubset; return ACTION_DOCTYPE_SUBSET; case Tokenizer.TOK_DECL_CLOSE: state = prolog2; return ACTION_DOCTYPE_CLOSE; case Tokenizer.TOK_NAME: if (token.equals("SYSTEM")) { state = doctype3; return ACTION_NONE; } if (token.equals("PUBLIC")) { state = doctype2; return ACTION_NONE; } break; } break; case doctype2: if (tok == Tokenizer.TOK_LITERAL) { state = doctype3; return ACTION_DOCTYPE_PUBLIC_ID; } break; case doctype3: if (tok == Tokenizer.TOK_LITERAL) { state = doctype4; return ACTION_DOCTYPE_SYSTEM_ID; } break; case doctype4: switch (tok) { case Tokenizer.TOK_OPEN_BRACKET: state = internalSubset; return ACTION_DOCTYPE_SUBSET; case Tokenizer.TOK_DECL_CLOSE: state = prolog2; return ACTION_DOCTYPE_CLOSE; } break; case doctype5: if (tok == Tokenizer.TOK_DECL_CLOSE) { state = prolog2; return ACTION_DOCTYPE_CLOSE; } break; case externalSubset0: state = externalSubset1; if (tok == Tokenizer.TOK_XML_DECL) return ACTION_TEXT_DECL; /* fall through */ case externalSubset1: switch (tok) { case Tokenizer.TOK_COND_SECT_OPEN: state = condSect0; return ACTION_NONE; case Tokenizer.TOK_COND_SECT_CLOSE: if (includeLevel == 0) break; --includeLevel; return ACTION_NONE; case Tokenizer.TOK_CLOSE_BRACKET: throw new PrologSyntaxException(); } /* fall through */ case internalSubset: switch (tok) { case Tokenizer.TOK_DECL_OPEN: if (matches(token, 2, "ENTITY")) { state = entity0; return ACTION_NONE; } if (matches(token, 2, "ATTLIST")) { state = attlist0; return ACTION_NONE; } if (matches(token, 2, "ELEMENT")) { state = element0; return ACTION_NONE; } if (matches(token, 2, "NOTATION")) { state = notation0; return ACTION_NONE; } break; case Tokenizer.TOK_PI: return ACTION_PI; case Tokenizer.TOK_COMMENT: return ACTION_COMMENT; case Tokenizer.TOK_PARAM_ENTITY_REF: return ACTION_OUTER_PARAM_ENTITY_REF; case Tokenizer.TOK_CLOSE_BRACKET: state = doctype5; return ACTION_NONE; } break; case entity0: switch (tok) { case Tokenizer.TOK_PERCENT: state = entity1; return ACTION_NONE; case Tokenizer.TOK_NAME: state = entity2; return ACTION_GENERAL_ENTITY_NAME; } break; case entity1: if (tok == Tokenizer.TOK_NAME) { state = entity7; return ACTION_PARAM_ENTITY_NAME; } break; case entity2: switch (tok) { case Tokenizer.TOK_NAME: if (token.equals("SYSTEM")) { state = entity4; return ACTION_NONE; } if (token.equals("PUBLIC")) { state = entity3; return ACTION_NONE; } break; case Tokenizer.TOK_LITERAL: state = declClose; return (documentEntity ? ACTION_ENTITY_VALUE_NO_PEREFS : ACTION_ENTITY_VALUE_WITH_PEREFS); } break; case entity3: if (tok == Tokenizer.TOK_LITERAL) { state = entity4; return ACTION_ENTITY_PUBLIC_ID; } break; case entity4: if (tok == Tokenizer.TOK_LITERAL) { state = entity5; return ACTION_ENTITY_SYSTEM_ID; } break; case entity5: switch (tok) { case Tokenizer.TOK_DECL_CLOSE: state = documentEntity ? internalSubset : externalSubset1; return ACTION_DECL_CLOSE; case Tokenizer.TOK_NAME: if (token.equals("NDATA")) { state = entity6; return ACTION_NONE; } break; } break; case entity6: switch (tok) { case Tokenizer.TOK_NAME: state = declClose; return ACTION_ENTITY_NOTATION_NAME; } break; case entity7: switch (tok) { case Tokenizer.TOK_NAME: if (token.equals("SYSTEM")) { state = entity9; return ACTION_NONE; } if (token.equals("PUBLIC")) { state = entity8; return ACTION_NONE; } break; case Tokenizer.TOK_LITERAL: state = declClose; return (documentEntity ? ACTION_ENTITY_VALUE_NO_PEREFS : ACTION_ENTITY_VALUE_WITH_PEREFS); } break; case entity8: if (tok == Tokenizer.TOK_LITERAL) { state = entity9; return ACTION_ENTITY_PUBLIC_ID; } break; case entity9: if (tok == Tokenizer.TOK_LITERAL) { state = declClose; return ACTION_ENTITY_SYSTEM_ID; } break; case notation0: if (tok == Tokenizer.TOK_NAME) { state = notation1; return ACTION_NOTATION_NAME; } break; case notation1: switch (tok) { case Tokenizer.TOK_NAME: if (token.equals("SYSTEM")) { state = notation3; return ACTION_NONE; } if (token.equals("PUBLIC")) { state = notation2; return ACTION_NONE; } break; } break; case notation2: if (tok == Tokenizer.TOK_LITERAL) { state = notation4; return ACTION_NOTATION_PUBLIC_ID; } break; case notation3: if (tok == Tokenizer.TOK_LITERAL) { state = declClose; return ACTION_NOTATION_SYSTEM_ID; } break; case notation4: switch (tok) { case Tokenizer.TOK_LITERAL: state = declClose; return ACTION_NOTATION_SYSTEM_ID; case Tokenizer.TOK_DECL_CLOSE: state = documentEntity ? internalSubset : externalSubset1; return ACTION_DECL_CLOSE; } break; case attlist0: switch (tok) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = attlist1; return ACTION_ATTLIST_ELEMENT_NAME; } break; case attlist1: switch (tok) { case Tokenizer.TOK_DECL_CLOSE: state = documentEntity ? internalSubset : externalSubset1; return ACTION_NONE; case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = attlist2; return ACTION_ATTRIBUTE_NAME; } break; case attlist2: switch (tok) { case Tokenizer.TOK_NAME: for (int i = 0; i < attributeTypes.length; i++) if (token.equals(attributeTypes[i])) { state = attlist8; return ACTION_ATTRIBUTE_TYPE_CDATA + i; } if (token.equals("NOTATION")) { state = attlist5; return ACTION_ATTRIBUTE_TYPE_NOTATION; } break; case Tokenizer.TOK_OPEN_PAREN: groupLevel = 1; state = attlist3; return ACTION_ENUM_GROUP_OPEN; } break; case attlist3: switch (tok) { case Tokenizer.TOK_NMTOKEN: case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = attlist4; return ACTION_ATTRIBUTE_ENUM_VALUE; } break; case attlist4: switch (tok) { case Tokenizer.TOK_CLOSE_PAREN: state = attlist8; groupLevel = 0; return ACTION_NONE; case Tokenizer.TOK_OR: state = attlist3; return ACTION_NONE; } break; case attlist5: if (tok == Tokenizer.TOK_OPEN_PAREN) { state = attlist6; groupLevel = 1; return ACTION_NOTATION_GROUP_OPEN; } break; case attlist6: if (tok == Tokenizer.TOK_NAME) { state = attlist7; return ACTION_ATTRIBUTE_NOTATION_VALUE; } break; case attlist7: switch (tok) { case Tokenizer.TOK_CLOSE_PAREN: groupLevel = 0; state = attlist8; return ACTION_NONE; case Tokenizer.TOK_OR: state = attlist6; return ACTION_NONE; } break; /* default value */ case attlist8: switch (tok) { case Tokenizer.TOK_POUND_NAME: if (matches(token, 1, "IMPLIED")) { state = attlist1; return ACTION_IMPLIED_ATTRIBUTE_VALUE; } if (matches(token, 1, "REQUIRED")) { state = attlist1; return ACTION_REQUIRED_ATTRIBUTE_VALUE; } if (matches(token, 1, "FIXED")) { state = attlist9; return ACTION_FIXED_ATTRIBUTE_VALUE; } break; case Tokenizer.TOK_LITERAL: state = attlist1; return ACTION_DEFAULT_ATTRIBUTE_VALUE; } break; case attlist9: if (tok == Tokenizer.TOK_LITERAL) { state = attlist1; return ACTION_DEFAULT_ATTRIBUTE_VALUE; } break; case element0: switch (tok) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = element1; return ACTION_ELEMENT_NAME; } break; case element1: switch (tok) { case Tokenizer.TOK_NAME: if (token.equals("EMPTY")) { state = declClose; return ACTION_CONTENT_EMPTY; } if (token.equals("ANY")) { state = declClose; return ACTION_CONTENT_ANY; } break; case Tokenizer.TOK_OPEN_PAREN: state = element2; groupLevel = 1; connector[0] = (byte)0; return ACTION_GROUP_OPEN; } break; case element2: switch (tok) { case Tokenizer.TOK_POUND_NAME: if (matches(token, 1, "PCDATA")) { state = element3; return ACTION_CONTENT_PCDATA; } break; case Tokenizer.TOK_OPEN_PAREN: groupLevel = 2; connector[1] = (byte)0; state = element6; return ACTION_GROUP_OPEN; case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = element7; return ACTION_CONTENT_ELEMENT; case Tokenizer.TOK_NAME_QUESTION: state = element7; return ACTION_CONTENT_ELEMENT_OPT; case Tokenizer.TOK_NAME_ASTERISK: state = element7; return ACTION_CONTENT_ELEMENT_REP; case Tokenizer.TOK_NAME_PLUS: state = element7; return ACTION_CONTENT_ELEMENT_PLUS; } break; case element3: switch (tok) { case Tokenizer.TOK_CLOSE_PAREN: case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: groupLevel = 0; state = declClose; return ACTION_GROUP_CLOSE_REP; case Tokenizer.TOK_OR: state = element4; return ACTION_GROUP_CHOICE; } break; case element4: switch (tok) { case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = element5; return ACTION_CONTENT_ELEMENT; } break; case element5: switch (tok) { case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: groupLevel = 0; state = declClose; return ACTION_GROUP_CLOSE_REP; case Tokenizer.TOK_OR: state = element4; return ACTION_GROUP_CHOICE; } break; case element6: switch (tok) { case Tokenizer.TOK_OPEN_PAREN: if (groupLevel >= connector.length) { byte[] tem = new byte[connector.length << 1]; System.arraycopy(connector, 0, tem, 0, connector.length); connector = tem; } connector[groupLevel] = (byte)0; groupLevel += 1; return ACTION_GROUP_OPEN; case Tokenizer.TOK_NAME: case Tokenizer.TOK_PREFIXED_NAME: state = element7; return ACTION_CONTENT_ELEMENT; case Tokenizer.TOK_NAME_QUESTION: state = element7; return ACTION_CONTENT_ELEMENT_OPT; case Tokenizer.TOK_NAME_ASTERISK: state = element7; return ACTION_CONTENT_ELEMENT_REP; case Tokenizer.TOK_NAME_PLUS: state = element7; return ACTION_CONTENT_ELEMENT_PLUS; } break; case element7: switch (tok) { case Tokenizer.TOK_CLOSE_PAREN: groupLevel -= 1; if (groupLevel == 0) state = declClose; return ACTION_GROUP_CLOSE; case Tokenizer.TOK_CLOSE_PAREN_ASTERISK: groupLevel -= 1; if (groupLevel == 0) state = declClose; return ACTION_GROUP_CLOSE_REP; case Tokenizer.TOK_CLOSE_PAREN_QUESTION: groupLevel -= 1; if (groupLevel == 0) state = declClose; return ACTION_GROUP_CLOSE_OPT; case Tokenizer.TOK_CLOSE_PAREN_PLUS: groupLevel -= 1; if (groupLevel == 0) state = declClose; return ACTION_GROUP_CLOSE_PLUS; case Tokenizer.TOK_COMMA: state = element6; if (connector[groupLevel - 1] == (byte)'|') break; connector[groupLevel - 1] = (byte)','; return ACTION_GROUP_SEQUENCE; case Tokenizer.TOK_OR: state = element6; if (connector[groupLevel - 1] == (byte)',') break; connector[groupLevel - 1] = (byte)'|'; return ACTION_GROUP_CHOICE; } break; case declClose: if (tok == Tokenizer.TOK_DECL_CLOSE) { state = documentEntity ? internalSubset : externalSubset1; return ACTION_DECL_CLOSE; } break; case condSect0: if (tok == Tokenizer.TOK_NAME) { if (token.equals("INCLUDE")) { state = condSect1; return ACTION_SECTION_STATUS_INCLUDE; } if (token.equals("IGNORE")) { state = condSect2; return ACTION_SECTION_STATUS_IGNORE; } } break; case condSect1: if (tok == Tokenizer.TOK_OPEN_BRACKET) { state = externalSubset1; includeLevel++; return ACTION_NONE; } break; case condSect2: if (tok == Tokenizer.TOK_OPEN_BRACKET) { state = externalSubset1; return ACTION_IGNORE_SECT; } break; } if (tok == Tokenizer.TOK_PROLOG_S) return ACTION_NONE; if (tok == Tokenizer.TOK_PARAM_ENTITY_REF && !documentEntity) return ACTION_INNER_PARAM_ENTITY_REF; throw new PrologSyntaxException(); } public Object clone() { try { PrologParser copy = (PrologParser)super.clone(); copy.connector = new byte[connector.length]; System.arraycopy(connector, 0, copy.connector, 0, groupLevel); return copy; } catch (CloneNotSupportedException e) { throw new InternalError(); } } public boolean isCompatible(PrologParser orig) { if (groupLevel > 0 && connector[groupLevel - 1] != 0 && connector[groupLevel - 1] != orig.connector[groupLevel - 1]) return false; return true; } public final int getGroupLevel() { return groupLevel; } public boolean expectingAttributeName() { return state == attlist1; } private static boolean matches(String token, int off, String key) { int keyLen = key.length(); if (token.length() - off != keyLen) return false; return token.regionMatches(off, key, 0, keyLen); } private static final String[] attributeTypes = { "CDATA", "ID", "IDREF", "IDREFS", "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS", }; } PrologSyntaxException.java000066400000000000000000000002651225366607500346630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parsepackage com.thaiopensource.xml.dtd.parse; /** * Thrown for a syntax error in parsing the prolog. * @see PrologParser */ public class PrologSyntaxException extends Exception { } ReplacementTextBuffer.java000066400000000000000000000042131225366607500345660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parsepackage com.thaiopensource.xml.dtd.parse; import com.thaiopensource.xml.tok.Token; class ReplacementTextBuffer { private static final int INIT_SIZE = 64; private char[] buf = new char[INIT_SIZE]; private int len; private boolean mustReparse = false; private Entity.Reference[] refs = new Entity.Reference[2]; int nRefs; public void clear() { len = 0; mustReparse = false; nRefs = 0; } public void setMustReparse() { mustReparse = true; } public boolean getMustReparse() { return mustReparse; } public void appendReplacementText(Entity entity) { appendEntityReference(new Entity.Reference(entity, len, len + entity.text.length)); append(entity.text, 0, entity.text.length); } private void appendEntityReference(Entity.Reference r) { if (nRefs == refs.length) { Entity.Reference[] tem = refs; refs = new Entity.Reference[tem.length << 1]; System.arraycopy(tem, 0, refs, 0, tem.length); } refs[nRefs++] = r; } public Entity.Reference[] getReferences() { if (nRefs == 0) return null; Entity.Reference[] r = new Entity.Reference[nRefs]; System.arraycopy(refs, 0, r, 0, nRefs); return r; } public void append(char c) { need(1); buf[len++] = c; } public void appendRefCharPair(Token t) { need(2); t.getRefCharPair(buf, len); len += 2; } public void append(char[] cbuf, int start, int end) { need(end - start); for (int i = start; i < end; i++) buf[len++] = cbuf[i]; } private void need(int n) { if (len + n <= buf.length) return; char[] tem = buf; if (n > tem.length) buf = new char[n * 2]; else buf = new char[tem.length << 1]; System.arraycopy(tem, 0, buf, 0, tem.length); } public char[] getChars() { char[] text = new char[len]; System.arraycopy(buf, 0, text, 0, len); return text; } public String toString() { return new String(buf, 0, len); } public int length() { return len; } public char charAt(int i) { if (i >= len) throw new IndexOutOfBoundsException(); return buf[i]; } public void chop() { --len; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/resources/000077500000000000000000000000001225366607500315565ustar00rootroot00000000000000Messages.properties000066400000000000000000000021101225366607500353560ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/dtd/parse/resources# Properties file specifying messages SYNTAX_ERROR=syntax error UNDEF_PEREF=reference to undefined parameter entity \"{0}\" UNDEF_REF=reference to undefined general entity \"{0}\" EXTERN_REF_ATTVAL=reference to external entity \"{0}\" in attribute value PE_DECL_NESTING=parameter entity not properly nested with declarations PE_GROUP_NESTING=parameter entities not properly nested with parentheses RECURSION=recursive entity reference UNPARSED_REF=reference to unparsed entity NOT_WELL_FORMED=not well-formed UNCLOSED_TOKEN=unclosed token UNCLOSED_CONDITIONAL_SECTION=unclosed conditional section IGNORE_SECT_CHAR=invalid character in ignored conditional section XML_TARGET=target of a processing instruction must not be [Xx][Mm][Ll] ILLEGAL_CHAR=character not allowed INVALID_TEXT_DECL=invalid text declaration DUPLICATE_NOTATION=duplicate declaration of notation \"{0}\" DUPLICATE_ELEMENT=duplicate declaration of element \"{0}\" INVALID_PUBLIC_ID=invalid character in public identifier # 0 = message, 1 = location, 2 = lineNumber, 3 = columnNumber MESSAGE={0} at \"{1}\", line {2}, column {3} jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/000077500000000000000000000000001225366607500262605ustar00rootroot00000000000000EncodingDetectInputStream.java000066400000000000000000000135021225366607500341200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/empackage com.thaiopensource.xml.em; import com.thaiopensource.xml.tok.InvalidTokenException; import com.thaiopensource.xml.tok.TextDecl; import java.io.CharConversionException; import java.io.IOException; import java.io.InputStream; public class EncodingDetectInputStream extends InputStream { private final InputStream in; private byte[] buf; private int avail = 0; private int start = 0; public EncodingDetectInputStream(InputStream in) { this.in = in; } private static final short[] detectProg = { // num bytes, bytes,..., loByteIndex, bytesPerChar, bomLength, encType, 4, 0x00, 0x00, 0xFE, 0xFF, 3, 4, 4, 0, 4, 0xFF, 0xFE, 0x00, 0x00, 0, 4, 4, 0, 4, 0x00, 0x00, 0xFF, 0xFE, 2, 4, 4, 0, 4, 0xFE, 0xFF, 0x00, 0x00, 1, 4, 4, 0, 2, 0xFE, 0xFF, 1, 2, 2, 0, 2, 0xFF, 0xFE, 0, 2, 2, 0, 3, 0xEF, 0xBB, 0xBF, 0, 1, 3, 0, 4, 0x00, 0x00, 0x00, 0x3C, 3, 4, 0, 0, 4, 0x3C, 0x00, 0x00, 0x00, 0, 4, 0, 0, 4, 0x00, 0x00, 0x3C, 0x00, 2, 4, 0, 0, 4, 0x00, 0x3C, 0x00, 0x00, 1, 4, 0, 0, 4, 0x00, 0x3C, 0x00, 0x3F, 1, 2, 0, 0, 4, 0x3C, 0x00, 0x3F, 0x00, 0, 2, 0, 0, 4, 0x3C, 0x3F, 0x78, 0x6D, 0, 1, 0, 0, 4, 0x4C, 0x6F, 0xA7, 0x94, 0, 1, 0, 1 }; static final int NPARMS = 4; /** * Detects the encoding based on the bytes following the current * position of the stream. Returns the name of the encoding. * Skips past any byte order mark with UTF-8. */ private static final String OPEN = "= nBytes) { boolean match = true; for (int i = 0; i < nBytes; i++) if ((buf[start + i] & 0xFF) != detectProg[pc + i]) { match = false; break; } if (match) { pc += nBytes; loByteIndex = detectProg[pc++]; bytesPerChar = detectProg[pc++]; bomLength = detectProg[pc++]; encType = detectProg[pc++]; break; } } pc += nBytes + NPARMS; } int chIndex = 0; boolean prevCharQuestion = false; boolean gotXmlDecl = false; while (makeAvailable((chIndex + 1)*bytesPerChar + bomLength)) { byte b = buf[start + bomLength +chIndex*bytesPerChar + loByteIndex]; for (int i = 0; i < bytesPerChar; i++) if (i != loByteIndex && buf[start + bomLength + chIndex*bytesPerChar + i] != 0) throw new CharConversionException("non-ASCII character in encoding declaration"); char ch = convertByte(b, encType); if (ch >= 0x80) throw new CharConversionException("non-ASCII character in encoding declaration"); if (chIndex < OPEN.length()) { if (ch != OPEN.charAt(chIndex)) break; } else if (ch == '?') prevCharQuestion = true; else if (ch =='>' && prevCharQuestion == true) { gotXmlDecl = true; chIndex++; break; } else prevCharQuestion = false; ++chIndex; } String enc = null; if (gotXmlDecl) { char[] b = new char[chIndex]; for (int i = 0; i < chIndex; i++) b[i] = convertByte(buf[start + bomLength + i*bytesPerChar + loByteIndex], encType); try { TextDecl decl = new TextDecl(b, 0, b.length); enc = decl.getEncoding(); } catch (InvalidTokenException e) { throw new CharConversionException("invalid text declaration"); } } // Skip the BOM for UTF-8 if (bytesPerChar == 1) { start += bomLength; avail -= bomLength; } if (enc == null) { if ((bytesPerChar == 2 && bomLength == 0) || bytesPerChar > 2 || encType != 0) throw new CharConversionException("missing encoding declaration"); if (bytesPerChar == 2) return "UTF-16"; return "UTF-8"; } return enc; } static final String EBCDIC_ENCODING = "Cp037"; static private char convertByte(byte b, int encType) throws IOException { if (encType == 1) { String s = new String(new byte[]{b}, EBCDIC_ENCODING); if (s.length() != 1) throw new CharConversionException(); return s.charAt(0); } return (char)(b & 0xFF); } private static final int INIT_BUF_SIZE = 80; private boolean makeAvailable(int required) throws IOException { if (avail >= required) return true; if (buf == null) buf = new byte[required > INIT_BUF_SIZE ? required : INIT_BUF_SIZE]; else if (required > buf.length - start) { if (buf.length >= required) { // move the available bytes for (int i = 0; i < avail; i++) buf[i] = buf[i + start]; start = 0; } else { // reallocate int newBufSize = buf.length * 2; newBufSize = required > newBufSize ? required : newBufSize; byte[] newBuf = new byte[newBufSize]; System.arraycopy(buf, start, newBuf, 0, avail); buf = newBuf; } } do { int nRead = in.read(buf, start + avail, buf.length - start - avail); if (nRead == -1) return false; avail += nRead; } while (avail < required); return true; } public int read() throws IOException { if (avail > 0) { --avail; return buf[start++] & 0xFF; } return in.read(); } public int read(byte[] b, int off, int len) throws IOException { if (avail > 0) { if (avail >= len) { if (b != null) System.arraycopy(buf, start, b, off, len); start += len; avail -= len; return len; } else { // avail < len if (b != null) System.arraycopy(buf, start, b, off, avail); int n = read(b, off + avail, len - avail); if (n < 0) n = avail; else n += avail; avail = 0; return n; } } return in.read(b, off, len); } public static void main(String[] args) throws Exception { System.out.println(new EncodingDetectInputStream(new java.io.FileInputStream(args[0])).detectEncoding()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/EntityManager.java000066400000000000000000000020661225366607500316760ustar00rootroot00000000000000package com.thaiopensource.xml.em; import com.thaiopensource.xml.util.EncodingMap; import java.io.IOException; import java.io.InputStream; import java.io.BufferedReader; import java.io.InputStreamReader; /** * This class is used by the parser to access external entities. */ public abstract class EntityManager { /** * Opens an external entity with the specified external identifier. */ public abstract OpenEntity open(ExternalId xid, boolean isParameterEntity, String entityName) throws IOException; /** * Open the top-level entity. * @param systemId * @return * @throws IOException */ public abstract OpenEntity open(String systemId) throws IOException; protected OpenEntity detectEncoding(InputStream input, String systemId) throws IOException { EncodingDetectInputStream in = new EncodingDetectInputStream(input); String enc = in.detectEncoding(); String javaEnc = EncodingMap.getJavaName(enc); return new OpenEntity(new BufferedReader(new InputStreamReader(in, javaEnc)), systemId, systemId, enc); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/ExternalId.java000066400000000000000000000011051225366607500311570ustar00rootroot00000000000000package com.thaiopensource.xml.em; public final class ExternalId { private final String systemId; private final String publicId; private final String baseUri; public ExternalId(String systemId, String publicId, String baseUri) { this.systemId = systemId; this.publicId = publicId; this.baseUri = baseUri; } public ExternalId(String systemId) { this(systemId, null, null); } public String getSystemId() { return systemId; } public String getPublicId() { return publicId; } public String getBaseUri() { return baseUri; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/FileEntityManager.java000066400000000000000000000015241225366607500324740ustar00rootroot00000000000000package com.thaiopensource.xml.em; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class FileEntityManager extends EntityManager { public OpenEntity open(ExternalId xid, boolean isParameterEntity, String entityName) throws IOException { String systemId = xid.getSystemId(); File file = new File(systemId); if (!file.isAbsolute()) { String baseUri = xid.getBaseUri(); if (baseUri != null) { String dir = new File(baseUri).getParent(); if (dir != null) file = new File(dir, systemId); } } return openFile(file); } public OpenEntity open(String systemId) throws IOException { return openFile(new File(systemId)); } private OpenEntity openFile(File file) throws IOException { return detectEncoding(new FileInputStream(file), file.toString()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/OpenEntity.java000066400000000000000000000026641225366607500312310ustar00rootroot00000000000000package com.thaiopensource.xml.em; import java.io.Reader; /** * Information about an open external entity. * This is used to by EntityManager to return * information about an external entity that is has opened. * @see EntityManager */ public class OpenEntity { private final Reader reader; private final String baseUri; private final String location; private final String encoding; /** * Creates and initializes an OpenEntity. which uses */ public OpenEntity(Reader reader, String location, String baseUri, String encoding) { this.reader = reader; this.location = location; this.baseUri = baseUri; this.encoding = encoding; } /** * Returns an Reader containing the entity's bytes. * If this is called more than once on the same * OpenEntity, it will return the same Reader. */ public final Reader getReader() { return reader; } /** * Returns the URI to use as the base URI for resolving relative URIs * contained in the entity. */ public final String getBaseUri() { return baseUri; } /** * Returns a string representation of the location of the entity * suitable for use in error messages. */ public final String getLocation() { return location; } /** * Returns the encoding used by the entity or null if the encoding * that was used is unknown. */ public final String getEncoding() { return encoding; } } ResolverUriEntityManager.java000066400000000000000000000054511225366607500340220ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/empackage com.thaiopensource.xml.em; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalEntityIdentifier; /** * Extends the UriEntityManager to use a Resolver. */ public class ResolverUriEntityManager extends UriEntityManager { private final Resolver resolver; public ResolverUriEntityManager(Resolver resolver) { this.resolver = resolver; } public OpenEntity open(String systemId) throws IOException { Input input = new Input(); input.setUri(systemId); try { return open(input); } catch (ResolverException e) { throw toIOException(e); } } public OpenEntity open(ExternalId xid, boolean isParameterEntity, String entityName) throws IOException { Input input = new Input(); String resolverEntityName = entityName; if (isParameterEntity) resolverEntityName = "%" + entityName; try { resolver.resolve(new ExternalEntityIdentifier(xid.getSystemId(), xid.getBaseUri(), xid.getPublicId(), resolverEntityName), input); if (input.isResolved()) return open(input); else return super.open(xid, isParameterEntity, entityName); } catch (ResolverException e) { throw toIOException(e); } } private OpenEntity open(Input input) throws ResolverException, IOException { resolver.open(input); if (!input.isOpen()) throw new ResolverException("could not open input"); Reader reader = input.getCharacterStream(); String encoding = input.getEncoding(); String systemId = input.getUri(); if (reader != null) { if (encoding == null) encoding = "UTF-8"; // XXX not sure if it's safe to pass null here return new OpenEntity(reader, systemId, systemId, encoding); } InputStream in = input.getByteStream(); if (encoding != null) return new OpenEntity(new InputStreamReader(in, encoding), systemId, systemId, encoding); return detectEncoding(in, systemId); } private static IOException toIOException(ResolverException e) { String message = e.getMessage(); Throwable cause = e.getCause(); if (message == null) { if (cause instanceof IOException) return (IOException)cause; // Avoid IOException(Throwable) because it's 1.6 return new IOException(cause.getMessage()); } // Avoid IOException(String, Throwable) because it's 1.6 return new IOException(message); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/em/UriEntityManager.java000066400000000000000000000012551225366607500323550ustar00rootroot00000000000000package com.thaiopensource.xml.em; import java.io.IOException; import java.net.URL; public class UriEntityManager extends EntityManager { public OpenEntity open(ExternalId xid, boolean isParameterEntity, String entityName) throws IOException { String systemId = xid.getSystemId(); String baseUri = xid.getBaseUri(); URL u; if (baseUri != null) u = new URL(new URL(baseUri), systemId); else u = new URL(systemId); return open(u); } public OpenEntity open(String uri) throws IOException { return open(new URL(uri)); } private OpenEntity open(URL u) throws IOException { return detectEncoding(u.openStream(), u.toString()); } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/000077500000000000000000000000001225366607500264545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/ContentToken.java000066400000000000000000000072361225366607500317420ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * Represents information returned by Tokenizer.tokenizeContent. * @see Tokenizer#tokenizeContent */ public class ContentToken extends Token { private static final int INIT_ATT_COUNT = 8; private int attCount = 0; private int[] attNameStart = new int[INIT_ATT_COUNT]; private int[] attNameEnd = new int[INIT_ATT_COUNT]; private int[] attValueStart = new int[INIT_ATT_COUNT]; private int[] attValueEnd = new int[INIT_ATT_COUNT]; private boolean[] attNormalized = new boolean[INIT_ATT_COUNT]; /** * Returns the number of attributes specified in the start-tag * or empty element tag. */ public final int getAttributeSpecifiedCount() { return attCount; } /** * Returns the index of the first character of the name of the * attribute index i. */ public final int getAttributeNameStart(int i) { if (i >= attCount) throw new IndexOutOfBoundsException(); return attNameStart[i]; } /** * Returns the index following the last character of the name of the * attribute index i. */ public final int getAttributeNameEnd(int i) { if (i >= attCount) throw new IndexOutOfBoundsException(); return attNameEnd[i]; } /** * Returns the index of the character following the opening quote of * attribute index i. */ public final int getAttributeValueStart(int i) { if (i >= attCount) throw new IndexOutOfBoundsException(); return attValueStart[i]; } /** * Returns the index of the closing quote attribute index i. */ public final int getAttributeValueEnd(int i) { if (i >= attCount) throw new IndexOutOfBoundsException(); return attValueEnd[i]; } /** * Returns true if attribute index i does not need to * be normalized. This is an optimization that allows further processing * of the attribute to be avoided when it is known that normalization * cannot change the value of the attribute. */ public final boolean isAttributeNormalized(int i) { if (i >= attCount) throw new IndexOutOfBoundsException(); return attNormalized[i]; } final void clearAttributes() { attCount = 0; } final void appendAttribute(int nameStart, int nameEnd, int valueStart, int valueEnd, boolean normalized) { if (attCount == attNameStart.length) { attNameStart = grow(attNameStart); attNameEnd = grow(attNameEnd); attValueStart = grow(attValueStart); attValueEnd = grow(attValueEnd); attNormalized = grow(attNormalized); } attNameStart[attCount] = nameStart; attNameEnd[attCount] = nameEnd; attValueStart[attCount] = valueStart; attValueEnd[attCount] = valueEnd; attNormalized[attCount] = normalized; ++attCount; } final void checkAttributeUniqueness(char[] buf) throws InvalidTokenException { for (int i = 1; i < attCount; i++) { int len = attNameEnd[i] - attNameStart[i]; for (int j = 0; j < i; j++) { if (attNameEnd[j] - attNameStart[j] == len) { int n = len; int s1 = attNameStart[i]; int s2 = attNameStart[j]; do { if (--n < 0) throw new InvalidTokenException(attNameStart[i], InvalidTokenException.DUPLICATE_ATTRIBUTE); } while (buf[s1++] == buf[s2++]); } } } } private static final int[] grow(int[] v) { int[] tem = v; v = new int[tem.length << 1]; System.arraycopy(tem, 0, v, 0, tem.length); return v; } private static final boolean[] grow(boolean[] v) { boolean[] tem = v; v = new boolean[tem.length << 1]; System.arraycopy(tem, 0, v, 0, tem.length); return v; } } EmptyTokenException.java000066400000000000000000000002531225366607500332160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the subarray being tokenized is empty. */ public class EmptyTokenException extends TokenException { } EndOfPrologException.java000066400000000000000000000003171225366607500332760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the end of the prolog has been detected. * @see Tokenizer#tokenizeProlog */ public class EndOfPrologException extends TokenException { } ExtensibleTokenException.java000066400000000000000000000011541225366607500342230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the char subarray being tokenized is a legal XML * token, but that subsequent chars in the same entity could be part of * the token. For example, Tokenizer.tokenizeProlog * would throw this if the char subarray consists of a legal XML name. */ public class ExtensibleTokenException extends TokenException { private final int tokType; ExtensibleTokenException(int tokType) { this.tokType = tokType; } /** * Returns the type of token in the byte subarrary. */ public int getTokenType() { return tokType; } } InvalidTokenException.java000066400000000000000000000021071225366607500335060ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the byte subarray being tokenized does not start * with a legal XML token and cannot start one if more bytes are added. */ public class InvalidTokenException extends TokenException { private final int offset; /** * The character or byte at the specified offset is not allowed * at that point. */ public static final byte ILLEGAL_CHAR = 0; /** * The target of a processing instruction was XML. */ public static final byte XML_TARGET = 1; /** * A duplicate attribute was specified. */ public static final byte DUPLICATE_ATTRIBUTE = 2; private final byte type; InvalidTokenException(int offset, byte type) { this.offset = offset; this.type = type; } InvalidTokenException(int offset) { this.offset = offset; this.type = ILLEGAL_CHAR; } /** * Returns the offset after the longest initial subarray * which could start a legal XML token. */ public final int getOffset() { return offset; } public final byte getType() { return type; } } PartialCharException.java000066400000000000000000000011011225366607500333020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the subarray being tokenized is not the * complete encoding of one or more XML characters, but might be if * more chars were added. */ public class PartialCharException extends PartialTokenException { private final int leadCharIndex; PartialCharException(int leadCharIndex) { this.leadCharIndex = leadCharIndex; } /** * Returns the index of the first char that is not part of the complete * encoding of a character. */ public int getLeadCharIndex() { return leadCharIndex; } } PartialTokenException.java000066400000000000000000000004011225366607500335070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tokpackage com.thaiopensource.xml.tok; /** * Thrown to indicate that the byte subarray being tokenized does not start * with a legal XML token but might be one if the subarray were extended. */ public class PartialTokenException extends TokenException { } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/Position.java000066400000000000000000000017411225366607500311260ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * Represents a position in an entity. * A position can be modified by Tokenizer.movePosition. * @see Tokenizer#movePosition */ public final class Position implements Cloneable { int lineNumber; int columnNumber; /** * Creates a position for the start of an entity: the line number is * 1 and the column number is 0. */ public Position() { lineNumber = 1; columnNumber = 0; } /** * Returns the line number. * The first line number is 1. */ public int getLineNumber() { return lineNumber; } /** * Returns the column number. * The first column number is 0. * A tab character is not treated specially. */ public int getColumnNumber() { return columnNumber; } /** * Returns a copy of this position. */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/TextDecl.java000066400000000000000000000121731225366607500310370ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * An XML TextDecl. */ public class TextDecl { private String version; private String encoding; /** * Creates a TextDecl from the specified char subarray. * The char subarray should be a TOK_XML_DECL token * returned from Tokenizer.tokenizeProlog or Tokenizer.tokenizeContent, * starting with <? and ending with ?>. * @exception InvalidTokenException if the specified char subarray * is not a legal XML TextDecl. */ public TextDecl(char[] buf, int off, int end) throws InvalidTokenException { init(false, buf, off, end); } /** * Return the encoding specified in the declaration, or null * if no encoding was specified. */ public String getEncoding() { return encoding; } /** * Return the version specified in the declaration, or null * if no version was specified. */ public String getVersion() { return version; } TextDecl() { } boolean init(boolean isXmlDecl, char[] buf, int off, int end) throws InvalidTokenException { // Skip end -= 2; ContentToken ct = new ContentToken(); int firstErrorIndex = -1; try { parsePseudoAttributes(buf, off, end, ct); } catch (InvalidTokenException e) { firstErrorIndex = e.getOffset(); } int nAtts = ct.getAttributeSpecifiedCount(); if (nAtts == 0) { if (firstErrorIndex == -1) firstErrorIndex = end; throw new InvalidTokenException(firstErrorIndex); } String[] names = new String[nAtts]; String[] values = new String[nAtts]; for (int i = 0; i < nAtts; i++) { int s = ct.getAttributeNameStart(i); int e = ct.getAttributeNameEnd(i); names[i] = new String(buf, s, e - s); s = ct.getAttributeValueStart(i); e = ct.getAttributeValueEnd(i); values[i] = new String(buf, s, e - s); } int att = 0; if (names[0].equals("version")) { version = values[0]; att++; } if ((att == 1 || !isXmlDecl) && att < nAtts && names[att].equals("encoding")) { encoding = values[att]; if (values[att].length() == 0 || !Character.isLetter(values[att].charAt(0)) || values[att].indexOf(':') >= 0) { int k = ct.getAttributeValueStart(att); if (firstErrorIndex == -1 || k < firstErrorIndex) firstErrorIndex = k; } att++; } else if (!isXmlDecl) firstErrorIndex = end; // encoding is required in a TextDecl boolean standalone = false; if (isXmlDecl && att > 0 && att < nAtts && names[att].equals("standalone")) { if (values[att].equals("yes")) standalone = true; else if (!values[att].equals("no")) { int k = ct.getAttributeValueStart(att); if (firstErrorIndex == -1 || k < firstErrorIndex) firstErrorIndex = k; } att++; } if (att < nAtts) { int k = ct.getAttributeNameStart(att); if (firstErrorIndex == -1 || k < firstErrorIndex) firstErrorIndex = k; } if (firstErrorIndex != -1) throw new InvalidTokenException(firstErrorIndex); return standalone; } private final void parsePseudoAttributes(char[] buf, int off, int end, ContentToken ct) throws InvalidTokenException { for (;;) { off = skipWS(buf, off, end); if (off == end) break; int nameStart = off; int nameEnd; nameLoop: for (;;) { switch (Tokenizer.charType(buf[off])) { case Tokenizer.CT_NMSTRT: break; case Tokenizer.CT_EQUALS: nameEnd = off; break nameLoop; case Tokenizer.CT_S: case Tokenizer.CT_LF: case Tokenizer.CT_CR: nameEnd = off; off += 1; off = skipWS(buf, off, end); if (off == end || buf[off] != '=') throw new InvalidTokenException(off); break nameLoop; default: throw new InvalidTokenException(off); } off += 1; if (off == end) throw new InvalidTokenException(off); } off += 1; off = skipWS(buf, off, end); if (off == end || !(buf[off] == '\'' || buf[off] == '"')) throw new InvalidTokenException(off); off += 1; int valueStart = off; valueLoop: for (;;) { if (off == end) throw new InvalidTokenException(off); switch (Tokenizer.charType(buf[off])) { case Tokenizer.CT_NMSTRT: case Tokenizer.CT_NAME: case Tokenizer.CT_MINUS: if ((buf[off] & ~0x7F) != 0) throw new InvalidTokenException(off); off += 1; break; case Tokenizer.CT_QUOT: case Tokenizer.CT_APOS: if (buf[off] != buf[valueStart - 1]) throw new InvalidTokenException(off); break valueLoop; default: throw new InvalidTokenException(off); } } ct.appendAttribute(nameStart, nameEnd, valueStart, off, true); off += 1; if (off == end) break; switch (buf[off]) { case ' ': case '\r': case '\n': case '\t': off += 1; break; default: throw new InvalidTokenException(off); } } } private static int skipWS(char[] buf, int off, int end) { loop: while (off != end) { switch (buf[off]) { case ' ': case '\r': case '\n': case '\t': off += 1; break; default: break loop; } } return off; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/Token.java000066400000000000000000000014621225366607500304020ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * Represents information returned by the tokenizing methods in * Tokenizer. * * @see Tokenizer#tokenizeContent * @see Tokenizer#tokenizeProlog * @see Tokenizer#tokenizeAttributeValue * @see Tokenizer#tokenizeEntityValue */ public class Token { int tokenEnd = -1; int nameEnd = -1; char refChar1 = 0; char refChar2 = 0; public final int getTokenEnd() { return tokenEnd; } protected final void setTokenEnd(int i) { tokenEnd = i; } public final int getNameEnd() { return nameEnd; } protected final void setNameEnd(int i) { nameEnd = i; } public final char getRefChar() { return refChar1; } public final void getRefCharPair(char[] ch, int off) { ch[off] = refChar1; ch[off + 1] = refChar2; } } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/TokenException.java000066400000000000000000000003201225366607500322510ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * The superclass of all checked exceptions thrown by methods in * Tokenizer. * * @see Tokenizer */ public class TokenException extends Exception { } jing-trang-20131210+dfsg+1/mod/dtd-parse/src/main/com/thaiopensource/xml/tok/Tokenizer.java000066400000000000000000002005001225366607500312660ustar00rootroot00000000000000package com.thaiopensource.xml.tok; /** * It provides operations on char arrays * that represent all or part of a parsed XML entity. *

    * Several methods operate on char subarrays. The subarray is specified * by a char array buf and two integers, * off and end; off * gives the index in buf of the first char of the subarray * and end gives the * index in buf of the char immediately after the last char. *

    * The main operations provided by Tokenizer are * tokenizeProlog, tokenizeContent and * tokenizeCdataSection; * these are used to divide up an XML entity into tokens. * tokenizeProlog is used for the prolog of an XML document * as well as for the external subset and parameter entities (except * when referenced in an EntityValue); * it can also be used for parsing the Misc* that follows * the document element. * tokenizeContent is used for the document element and for * parsed general entities that are referenced in content * except for CDATA sections. * tokenizeCdataSection is used for CDATA sections, following * the <![CDATA[ up to and including the ]]>. *

    * tokenizeAttributeValue and tokenizeEntityValue * are used to further divide up tokens returned by tokenizeProlog * and tokenizeContent; they are also used to divide up entities * referenced in attribute values or entity values. */ public class Tokenizer { /** * Represents one or more characters of data. */ public static final int TOK_DATA_CHARS = 0; /** * Represents a newline (CR, LF or CR followed by LF) in data. */ public static final int TOK_DATA_NEWLINE = TOK_DATA_CHARS + 1; /** * Represents a complete start-tag <name>, * that doesn't have any attribute specifications. */ public static final int TOK_START_TAG_NO_ATTS = TOK_DATA_NEWLINE + 1; /** * Represents a complete start-tag <name att="val">, * that contains one or more attribute specifications. */ public static final int TOK_START_TAG_WITH_ATTS = TOK_START_TAG_NO_ATTS + 1; /** * Represents an empty element tag <name/>, * that doesn't have any attribute specifications. */ public static final int TOK_EMPTY_ELEMENT_NO_ATTS = TOK_START_TAG_WITH_ATTS + 1; /** * Represents an empty element tag <name att="val"/>, * that contains one or more attribute specifications. */ public static final int TOK_EMPTY_ELEMENT_WITH_ATTS = TOK_EMPTY_ELEMENT_NO_ATTS + 1; /** * Represents a complete end-tag </name>. */ public static final int TOK_END_TAG = TOK_EMPTY_ELEMENT_WITH_ATTS + 1; /** * Represents the start of a CDATA section <![CDATA[. */ public static final int TOK_CDATA_SECT_OPEN = TOK_END_TAG + 1; /** * Represents the end of a CDATA section ]]>. */ public static final int TOK_CDATA_SECT_CLOSE = TOK_CDATA_SECT_OPEN + 1; /** * Represents a general entity reference. */ public static final int TOK_ENTITY_REF = TOK_CDATA_SECT_CLOSE + 1; /** * Represents a general entity reference to a one of the 5 predefined * entities amp, lt, gt, * quot, apos. */ public static final int TOK_MAGIC_ENTITY_REF = TOK_ENTITY_REF + 1; /** * Represents a numeric character reference (decimal or hexadecimal), * when the referenced character is less than or equal to 0xFFFF * and so is represented by a single char. */ public static final int TOK_CHAR_REF = TOK_MAGIC_ENTITY_REF + 1; /** * Represents a numeric character reference (decimal or hexadecimal), * when the referenced character is greater than 0xFFFF and so is * represented by a pair of chars. */ public static final int TOK_CHAR_PAIR_REF = TOK_CHAR_REF + 1; /** * Represents a processing instruction. */ public static final int TOK_PI = TOK_CHAR_PAIR_REF + 1; /** * Represents an XML declaration or text declaration (a processing * instruction whose target is xml). */ public static final int TOK_XML_DECL = TOK_PI + 1; /** * Represents a comment <!-- comment -->. * This can occur both in the prolog and in content. */ public static final int TOK_COMMENT = TOK_XML_DECL + 1; /** * Represents a white space character in an attribute value, * excluding white space characters that are part of line boundaries. */ public static final int TOK_ATTRIBUTE_VALUE_S = TOK_COMMENT + 1; /** * Represents a parameter entity reference in the prolog. */ public static final int TOK_PARAM_ENTITY_REF = TOK_ATTRIBUTE_VALUE_S + 1; /** * Represents whitespace in the prolog. * The token contains one whitespace character. */ public static final int TOK_PROLOG_S = TOK_PARAM_ENTITY_REF + 1; /** * Represents <!NAME in the prolog. */ public static final int TOK_DECL_OPEN = TOK_PROLOG_S + 1; /** * Represents > in the prolog. */ public static final int TOK_DECL_CLOSE = TOK_DECL_OPEN + 1; /** * Represents an unprefixed name in the prolog. */ public static final int TOK_NAME = TOK_DECL_CLOSE + 1; /** * Represents a name with a prefix. */ public static final int TOK_PREFIXED_NAME = TOK_NAME + 1; /** * Represents a name token in the prolog that is not a name. */ public static final int TOK_NMTOKEN = TOK_PREFIXED_NAME + 1; /** * Represents #NAME in the prolog. */ public static final int TOK_POUND_NAME = TOK_NMTOKEN + 1; /** * Represents | in the prolog. */ public static final int TOK_OR = TOK_POUND_NAME + 1; /** * Represents a % in the prolog that does not start * a parameter entity reference. * This can occur in an entity declaration. */ public static final int TOK_PERCENT = TOK_OR + 1; /** * Represents a ( in the prolog. */ public static final int TOK_OPEN_PAREN = TOK_PERCENT + 1; /** * Represents a ) in the prolog that is not * followed immediately by any of * *, + or ?. */ public static final int TOK_CLOSE_PAREN = TOK_OPEN_PAREN + 1; /** * Represents [ in the prolog. */ public static final int TOK_OPEN_BRACKET = TOK_CLOSE_PAREN + 1; /** * Represents ] in the prolog. */ public static final int TOK_CLOSE_BRACKET = TOK_OPEN_BRACKET + 1; /** * Represents a literal (EntityValue, AttValue, SystemLiteral or * PubidLiteral). */ public static final int TOK_LITERAL = TOK_CLOSE_BRACKET + 1; /** * Represents a name followed immediately by ?. */ public static final int TOK_NAME_QUESTION = TOK_LITERAL + 1; /** * Represents a name followed immediately by *. */ public static final int TOK_NAME_ASTERISK = TOK_NAME_QUESTION + 1; /** * Represents a name followed immediately by +. */ public static final int TOK_NAME_PLUS = TOK_NAME_ASTERISK + 1; /** * Represents <![ in the prolog. */ public static final int TOK_COND_SECT_OPEN = TOK_NAME_PLUS + 1; /** * Represents ]]> in the prolog. */ public static final int TOK_COND_SECT_CLOSE = TOK_COND_SECT_OPEN + 1; /** * Represents )? in the prolog. */ public static final int TOK_CLOSE_PAREN_QUESTION = TOK_COND_SECT_CLOSE + 1; /** * Represents )* in the prolog. */ public static final int TOK_CLOSE_PAREN_ASTERISK = TOK_CLOSE_PAREN_QUESTION + 1; /** * Represents )+ in the prolog. */ public static final int TOK_CLOSE_PAREN_PLUS = TOK_CLOSE_PAREN_ASTERISK + 1; /** * Represents , in the prolog. */ public static final int TOK_COMMA = TOK_CLOSE_PAREN_PLUS + 1; // Chars with type < 0 may not be data in content. // The negation of the lead char type gives the total number of chars. static final int CT_LEAD2 = -2; static final int CT_NONXML = CT_LEAD2 - 1; static final int CT_MALFORM = CT_NONXML - 1; static final int CT_LT = CT_MALFORM - 1; static final int CT_AMP = CT_LT - 1; static final int CT_RSQB = CT_AMP - 1; static final int CT_CR = CT_RSQB - 1; static final int CT_LF = CT_CR - 1; // Chars with type >= 0 are treated as data in content. static final int CT_GT = 0; static final int CT_QUOT = CT_GT + 1; static final int CT_APOS = CT_QUOT + 1; static final int CT_EQUALS = CT_APOS + 1; static final int CT_QUEST = CT_EQUALS + 1; static final int CT_EXCL = CT_QUEST + 1; static final int CT_SOL = CT_EXCL + 1; static final int CT_SEMI = CT_SOL + 1; static final int CT_NUM = CT_SEMI + 1; static final int CT_LSQB = CT_NUM + 1; static final int CT_S = CT_LSQB + 1; static final int CT_NMSTRT = CT_S + 1; static final int CT_COLON = CT_NMSTRT + 1; static final int CT_NAME = CT_COLON + 1; static final int CT_MINUS = CT_NAME + 1; static final int CT_OTHER = CT_MINUS + 1; static final int CT_PERCNT = CT_OTHER + 1; static final int CT_LPAR = CT_PERCNT + 1; static final int CT_RPAR = CT_LPAR + 1; static final int CT_AST = CT_RPAR + 1; static final int CT_PLUS = CT_AST + 1; static final int CT_COMMA = CT_PLUS + 1; static final int CT_VERBAR = CT_COMMA + 1; final static byte[] asciiTypeTable = { /* 0x00 */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x04 */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x08 */ CT_NONXML, CT_S, CT_LF, CT_NONXML, /* 0x0C */ CT_NONXML, CT_CR, CT_NONXML, CT_NONXML, /* 0x10 */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x14 */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x18 */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x1C */ CT_NONXML, CT_NONXML, CT_NONXML, CT_NONXML, /* 0x20 */ CT_S, CT_EXCL, CT_QUOT, CT_NUM, /* 0x24 */ CT_OTHER, CT_PERCNT, CT_AMP, CT_APOS, /* 0x28 */ CT_LPAR, CT_RPAR, CT_AST, CT_PLUS, /* 0x2C */ CT_COMMA, CT_MINUS, CT_NAME, CT_SOL, /* 0x30 */ CT_NAME, CT_NAME, CT_NAME, CT_NAME, /* 0x34 */ CT_NAME, CT_NAME, CT_NAME, CT_NAME, /* 0x38 */ CT_NAME, CT_NAME, CT_COLON, CT_SEMI, /* 0x3C */ CT_LT, CT_EQUALS, CT_GT, CT_QUEST, /* 0x40 */ CT_OTHER, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x44 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x48 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x4C */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x50 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x54 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x58 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_LSQB, /* 0x5C */ CT_OTHER, CT_RSQB, CT_OTHER, CT_NMSTRT, /* 0x60 */ CT_OTHER, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x64 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x68 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x6C */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x70 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x74 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, /* 0x78 */ CT_NMSTRT, CT_NMSTRT, CT_NMSTRT, CT_OTHER, /* 0x7C */ CT_VERBAR, CT_OTHER, CT_OTHER, CT_OTHER }; /** * Moves a position forward. * On entry, pos gives the position of the char at index * off in buf. * On exit, it pos will give the position of the char at index * end, which must be greater than or equal to off. * The chars between off and end must encode * one or more complete characters. * A carriage return followed by a line feed will be treated as a single * line delimiter provided that they are given to movePosition * together. */ public static void movePosition(final char[] buf, int off, int end, Position pos) { int lineNumber = pos.lineNumber; /* Maintain invariant: off - colStart = colNumber */ int colStart = off - pos.columnNumber; while (off != end) { switch (buf[off++]) { case '\n': lineNumber++; colStart = off; break; case '\r': if (off != end && buf[off] == '\n') off += 1; lineNumber++; colStart = off; break; } } pos.lineNumber = lineNumber; pos.columnNumber = off - colStart; } private static void checkCharMatches(char[] buf, int off, char c) throws InvalidTokenException { if (buf[off] != c) throw new InvalidTokenException(off); } /* off points to character following "'); token.tokenEnd = off + 1; return TOK_COMMENT; } break; default: off += 1; break; } } } throw new PartialTokenException(); } /* off points to character following " */ switch (charType(buf[off + 1])) { case CT_S: case CT_CR: case CT_LF: case CT_PERCNT: throw new InvalidTokenException(off); } /* fall through */ case CT_S: case CT_CR: case CT_LF: token.tokenEnd = off; return TOK_DECL_OPEN; case CT_NMSTRT: off += 1; break; default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } private static boolean targetIsXml(char[] buf, int off, int end) throws InvalidTokenException { boolean upper = false; if (end - off != 3) return false; switch (buf[off]) { case 'x': break; case 'X': upper = true; break; default: return false; } off += 1; switch (buf[off]) { case 'm': break; case 'M': upper = true; break; default: return false; } off += 1; switch (buf[off]) { case 'l': break; case 'L': upper = true; break; default: return false; } if (upper) throw new InvalidTokenException(off, InvalidTokenException.XML_TARGET); return true; } /* off points to character following "') { token.tokenEnd = off + 1; if (isXml) return TOK_XML_DECL; else return TOK_PI; } break; default: off += 1; break; } } throw new PartialTokenException(); case CT_QUEST: token.nameEnd = off; off += 1; if (off == end) throw new PartialTokenException(); checkCharMatches(buf, off, '>'); token.tokenEnd = off + 1; return (targetIsXml(buf, target, token.nameEnd) ? TOK_XML_DECL : TOK_PI); default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } /* off points to character following " *

  • TOK_DATA_CHARS *
  • TOK_DATA_NEWLINE *
  • TOK_CDATA_SECT_CLOSE * *

    * Information about the token is stored in token. *

    * After TOK_CDATA_SECT_CLOSE is returned, the application * should use tokenizeContent. * * @exception EmptyTokenException if the subarray is empty * @exception PartialTokenException if the subarray contains only part of * a legal token * @exception InvalidTokenException if the subarrary does not start * with a legal token or part of one * @exception ExtensibleTokenException if the subarray encodes just a carriage * return ('\r') * * @see #TOK_DATA_CHARS * @see #TOK_DATA_NEWLINE * @see #TOK_CDATA_SECT_CLOSE * @see Token * @see EmptyTokenException * @see PartialTokenException * @see InvalidTokenException * @see ExtensibleTokenException * @see #tokenizeContent */ public static int tokenizeCdataSection(char[] buf, int off, int end, Token token) throws EmptyTokenException, PartialTokenException, InvalidTokenException, ExtensibleTokenException { if (off == end) throw new EmptyTokenException(); switch (charType(buf[off])) { case CT_RSQB: off += 1; if (off == end) throw new PartialTokenException(); if (buf[off] != ']') break; off += 1; if (off == end) throw new PartialTokenException(); if (buf[off] != '>') { off -= 1; break; } token.tokenEnd = off + 1; return TOK_CDATA_SECT_CLOSE; case CT_CR: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_NEWLINE); if (charType(buf[off]) == CT_LF) off += 1; token.tokenEnd = off; return TOK_DATA_NEWLINE; case CT_LF: token.tokenEnd = off + 1; return TOK_DATA_NEWLINE; case CT_NONXML: case CT_MALFORM: throw new InvalidTokenException(off); case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); check2(buf, off); off += 2; break; default: off += 1; break; } token.tokenEnd = extendCdata(buf, off, end); return TOK_DATA_CHARS; } private static int extendCdata(final char[] buf, int off, final int end) throws InvalidTokenException { while (off != end) { switch (charType(buf[off])) { case CT_LEAD2: if (end - off < 2) return off; check2(buf, off); off += 2; break; case CT_RSQB: case CT_NONXML: case CT_MALFORM: case CT_CR: case CT_LF: return off; default: off += 1; break; } } return off; } /* off points to character following "= 0x110000) throw new InvalidTokenException(off); } } throw new PartialTokenException(); } /* off points to character following "&#" */ private static int scanCharRef(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException { if (off != end) { int c = buf[off]; switch (c) { case 'x': return scanHexCharRef(buf, off + 1, end, token); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: throw new InvalidTokenException(off); } int num = c - '0'; for (off += 1; off != end; off += 1) { c = buf[off]; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': num = num * 10 + (c - '0'); if (num < 0x110000) break; /* fall through */ default: throw new InvalidTokenException(off); case ';': token.tokenEnd = off + 1; return setRefChar(num, token); } } } throw new PartialTokenException(); } /* num is known to be < 0x110000; return the token code */ private static int setRefChar(int num, Token token) throws InvalidTokenException { if (num < 0x10000) { switch (charTypeTable[num >> 8][num & 0xFF]) { case CT_NONXML: case CT_LEAD2: case CT_MALFORM: throw new InvalidTokenException(token.tokenEnd - 1); } token.refChar1 = (char)num; return TOK_CHAR_REF; } else { num -= 0x10000; token.refChar1 = (char)((num >> 10) + 0xD800); token.refChar2 = (char)((num & ((1 << 10) - 1)) + 0xDC00); return TOK_CHAR_PAIR_REF; } } private static boolean isMagicEntityRef(char[] buf, int off, int end, Token token) { switch (buf[off]) { case 'a': if (end - off < 4) break; switch (buf[off + 1]) { case 'm': if (buf[off + 2] == 'p' && buf[off + 3] == ';') { token.tokenEnd = off + 4; token.refChar1 = '&'; return true; } break; case 'p': if (end - off >= 5 && buf[off + 2] == 'o' && buf[off + 3] == 's' && buf[off + 4] == ';') { token.tokenEnd = off + 5; token.refChar1 = '\''; return true; } break; } break; case 'l': if (end - off >= 3 && buf[off + 1] == 't' && buf[off + 2] == ';') { token.tokenEnd = off + 3; token.refChar1 = '<'; return true; } break; case 'g': if (end - off >= 3 && buf[off + 1] == 't' && buf[off + 2] == ';') { token.tokenEnd = off + 3; token.refChar1 = '>'; return true; } break; case 'q': if (end - off >= 5 && buf[off + 1] == 'u' && buf[off + 2] == 'o' && buf[off + 3] == 't' && buf[off + 4] == ';') { token.tokenEnd = off + 5; token.refChar1 = '"'; return true; } break; } return false; } /* off points to character following "&" */ private static int scanRef(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException { if (off == end) throw new PartialTokenException(); if (isMagicEntityRef(buf, off, end, token)) return TOK_MAGIC_ENTITY_REF; switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; case CT_NUM: return scanCharRef(buf, off + 1, end, token); default: throw new InvalidTokenException(off); } while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_SEMI: token.nameEnd = off; token.tokenEnd = off + 1; return TOK_ENTITY_REF; default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } /* off points to character following first character of attribute name */ private static int scanAtts(int nameStart, char[] buf, int off, int end, ContentToken token) throws PartialTokenException, InvalidTokenException { boolean hadColon = false; int nameEnd = -1; while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_COLON: if (hadColon) throw new InvalidTokenException(off); hadColon = true; off += 1; if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; default: throw new InvalidTokenException(off); } break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_S: case CT_CR: case CT_LF: nameEnd = off; loop: for (;;) { off += 1; if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_EQUALS: break loop; case CT_S: case CT_LF: case CT_CR: break; default: throw new InvalidTokenException(off); } } /* fall through */ case CT_EQUALS: { if (nameEnd < 0) nameEnd = off; int open; hadColon = false; for (;;) { off += 1; if (off == end) throw new PartialTokenException(); open = charType(buf[off]); if (open == CT_QUOT || open == CT_APOS) break; switch (open) { case CT_S: case CT_LF: case CT_CR: break; default: throw new InvalidTokenException(off); } } off += 1; int valueStart = off; boolean normalized = true; /* in attribute value */ for (;;) { int t; if (off == end) throw new PartialTokenException(); t = charType(buf[off]); if (t == open) break; switch (t) { case CT_NONXML: case CT_MALFORM: throw new InvalidTokenException(off); case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); check2(buf, off); off += 2; break; case CT_AMP: { normalized = false; int saveNameEnd = token.nameEnd; scanRef(buf, off + 1, end, token); token.nameEnd = saveNameEnd; off = token.tokenEnd; break; } case CT_S: if (normalized && (off == valueStart || buf[off] != ' ' || (off + 1 != end && (buf[off + 1] == ' ' || charType(buf[off + 1]) == open)))) normalized = false; off += 1; break; case CT_LT: throw new InvalidTokenException(off); case CT_LF: case CT_CR: normalized = false; /* fall through */ default: off += 1; break; } } token.appendAttribute(nameStart, nameEnd, valueStart, off, normalized); off += 1; if (off == end) throw new PartialTokenException(); int t = charType(buf[off]); switch (t) { case CT_S: case CT_CR: case CT_LF: off += 1; if (off == end) throw new PartialTokenException(); t = charType(buf[off]); break; case CT_GT: case CT_SOL: break; default: throw new InvalidTokenException(off); } /* off points to closing quote */ skipToName: for (;;) { switch (t) { case CT_NMSTRT: nameStart = off; off += 1; break skipToName; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); nameStart = off; off += 2; break skipToName; case CT_S: case CT_CR: case CT_LF: break; case CT_GT: token.checkAttributeUniqueness(buf); token.tokenEnd = off + 1; return TOK_START_TAG_WITH_ATTS; case CT_SOL: off += 1; if (off == end) throw new PartialTokenException(); checkCharMatches(buf, off, '>'); token.checkAttributeUniqueness(buf); token.tokenEnd = off + 1; return TOK_EMPTY_ELEMENT_WITH_ATTS; default: throw new InvalidTokenException(off); } off += 1; if (off == end) throw new PartialTokenException(); t = charType(buf[off]); } nameEnd = -1; break; } default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } /* off points to character following "<" */ private static int scanLt(char[] buf, int off, int end, ContentToken token) throws PartialTokenException, InvalidTokenException { if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; case CT_EXCL: if (++off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_MINUS: return scanComment(buf, off + 1, end, token); case CT_LSQB: return scanCdataSection(buf, off + 1, end, token); } throw new InvalidTokenException(off); case CT_QUEST: return scanPi(buf, off + 1, end, token); case CT_SOL: return scanEndTag(buf, off + 1, end, token); default: throw new InvalidTokenException(off); } /* we have a start-tag */ boolean hadColon = false; token.nameEnd = -1; token.clearAttributes(); while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_COLON: if (hadColon) throw new InvalidTokenException(off); hadColon = true; off += 1; if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; default: throw new InvalidTokenException(off); } break; case CT_S: case CT_CR: case CT_LF: token.nameEnd = off; off += 1; loop: for (;;) { if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: return scanAtts(off, buf, off + 1, end, token); case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); return scanAtts(off, buf, off + 2, end, token); case CT_GT: case CT_SOL: break loop; case CT_S: case CT_CR: case CT_LF: off += 1; break; default: throw new InvalidTokenException(off); } } break; case CT_GT: if (token.nameEnd < 0) token.nameEnd = off; token.tokenEnd = off + 1; return TOK_START_TAG_NO_ATTS; case CT_SOL: if (token.nameEnd < 0) token.nameEnd = off; off += 1; if (off == end) throw new PartialTokenException(); checkCharMatches(buf, off, '>'); token.tokenEnd = off + 1; return TOK_EMPTY_ELEMENT_NO_ATTS; default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } /** * Scans the first token of a char subarrary that contains content. * Returns one of the following integers according to the type of token * that the subarray starts with: *

      *
    • TOK_START_TAG_NO_ATTS *
    • TOK_START_TAG_WITH_ATTS *
    • TOK_EMPTY_ELEMENT_NO_ATTS *
    • TOK_EMPTY_ELEMENT_WITH_ATTS *
    • TOK_END_TAG *
    • TOK_DATA_CHARS *
    • TOK_DATA_NEWLINE *
    • TOK_CDATA_SECT_OPEN *
    • TOK_ENTITY_REF *
    • TOK_MAGIC_ENTITY_REF *
    • TOK_CHAR_REF *
    • TOK_CHAR_PAIR_REF *
    • TOK_PI *
    • TOK_XML_DECL *
    • TOK_COMMENT *
    *

    * Information about the token is stored in token. *

    * When TOK_CDATA_SECT_OPEN is returned, * tokenizeCdataSection should be called until * it returns TOK_CDATA_SECT. * * @exception EmptyTokenException if the subarray is empty * @exception PartialTokenException if the subarray contains only part of * a legal token * @exception InvalidTokenException if the subarrary does not start * with a legal token or part of one * @exception ExtensibleTokenException if the subarray encodes just a carriage * return ('\r') * * @see #TOK_START_TAG_NO_ATTS * @see #TOK_START_TAG_WITH_ATTS * @see #TOK_EMPTY_ELEMENT_NO_ATTS * @see #TOK_EMPTY_ELEMENT_WITH_ATTS * @see #TOK_END_TAG * @see #TOK_DATA_CHARS * @see #TOK_DATA_NEWLINE * @see #TOK_CDATA_SECT_OPEN * @see #TOK_ENTITY_REF * @see #TOK_MAGIC_ENTITY_REF * @see #TOK_CHAR_REF * @see #TOK_CHAR_PAIR_REF * @see #TOK_PI * @see #TOK_XML_DECL * @see #TOK_COMMENT * @see ContentToken * @see EmptyTokenException * @see PartialTokenException * @see InvalidTokenException * @see ExtensibleTokenException * @see #tokenizeCdataSection */ public static int tokenizeContent(char[] buf, int off, int end, ContentToken token) throws PartialTokenException, InvalidTokenException, EmptyTokenException, ExtensibleTokenException { if (off == end) throw new EmptyTokenException(); switch (charType(buf[off])) { case CT_LT: return scanLt(buf, off + 1, end, token); case CT_AMP: return scanRef(buf, off + 1, end, token); case CT_CR: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_NEWLINE); if (charType(buf[off]) == CT_LF) off += 1; token.tokenEnd = off; return TOK_DATA_NEWLINE; case CT_LF: token.tokenEnd = off + 1; return TOK_DATA_NEWLINE; case CT_RSQB: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_CHARS); if (buf[off] != ']') break; off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_CHARS); if (buf[off] != '>') { off -= 1; break; } throw new InvalidTokenException(off); case CT_NONXML: case CT_MALFORM: throw new InvalidTokenException(off); case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); check2(buf, off); off += 2; break; default: off += 1; break; } token.tokenEnd = extendData(buf, off, end); return TOK_DATA_CHARS; } private static int extendData(final char[] buf, int off, final int end) throws InvalidTokenException { while (off != end) { switch (charType(buf[off])) { case CT_LEAD2: if (end - off < 2) return off; check2(buf, off); off += 2; break; case CT_RSQB: case CT_AMP: case CT_LT: case CT_NONXML: case CT_MALFORM: case CT_CR: case CT_LF: return off; default: off += 1; break; } } return off; } /* off points to character following "%" */ private static int scanPercent(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException { if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; case CT_S: case CT_LF: case CT_CR: case CT_PERCNT: token.tokenEnd = off; return TOK_PERCENT; default: throw new InvalidTokenException(off); } while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_SEMI: token.nameEnd = off; token.tokenEnd = off + 1; return TOK_PARAM_ENTITY_REF; default: throw new InvalidTokenException(off); } } throw new PartialTokenException(); } private static int scanPoundName(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException, ExtensibleTokenException { if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (charType2(buf, off) != CT_NMSTRT) throw new InvalidTokenException(off); off += 2; break; default: throw new InvalidTokenException(off); } while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_CR: case CT_LF: case CT_S: case CT_RPAR: case CT_GT: case CT_PERCNT: case CT_VERBAR: token.tokenEnd = off; return TOK_POUND_NAME; default: throw new InvalidTokenException(off); } } throw new ExtensibleTokenException(TOK_POUND_NAME); } private static int scanLit(int open, char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException, ExtensibleTokenException { while (off != end) { int t = charType(buf[off]); switch (t) { case CT_LEAD2: if (end - off < 2) throw new PartialTokenException(); check2(buf, off); off += 2; break; case CT_NONXML: case CT_MALFORM: throw new InvalidTokenException(off); case CT_QUOT: case CT_APOS: off += 1; if (t != open) break; if (off == end) throw new ExtensibleTokenException(TOK_LITERAL); switch (charType(buf[off])) { case CT_S: case CT_CR: case CT_LF: case CT_GT: case CT_PERCNT: case CT_LSQB: token.tokenEnd = off; return TOK_LITERAL; default: throw new InvalidTokenException(off); } default: off += 1; break; } } throw new PartialTokenException(); } /** * Scans the first token of a char subarray that contains part of a * prolog. * Returns one of the following integers according to the type of token * that the subarray starts with: *

      *
    • TOK_PI *
    • TOK_XML_DECL *
    • TOK_COMMENT *
    • TOK_PARAM_ENTITY_REF *
    • TOK_PROLOG_S *
    • TOK_DECL_OPEN *
    • TOK_DECL_CLOSE *
    • TOK_NAME *
    • TOK_NMTOKEN *
    • TOK_POUND_NAME *
    • TOK_OR *
    • TOK_PERCENT *
    • TOK_OPEN_PAREN *
    • TOK_CLOSE_PAREN *
    • TOK_OPEN_BRACKET *
    • TOK_CLOSE_BRACKET *
    • TOK_LITERAL *
    • TOK_NAME_QUESTION *
    • TOK_NAME_ASTERISK *
    • TOK_NAME_PLUS *
    • TOK_COND_SECT_OPEN *
    • TOK_COND_SECT_CLOSE *
    • TOK_CLOSE_PAREN_QUESTION *
    • TOK_CLOSE_PAREN_ASTERISK *
    • TOK_CLOSE_PAREN_PLUS *
    • TOK_COMMA *
    * @exception EmptyTokenException if the subarray is empty * @exception PartialTokenException if the subarray contains only part of * a legal token * @exception InvalidTokenException if the subarrary does not start * with a legal token or part of one * @exception EndOfPrologException if the subarray starts with the document * element; tokenizeContent should be used on the remainder * of the entity * @exception ExtensibleTokenException if the subarray is a legal token * but subsequent chars in the same entity could be part of the token * @see #TOK_PI * @see #TOK_XML_DECL * @see #TOK_COMMENT * @see #TOK_PARAM_ENTITY_REF * @see #TOK_PROLOG_S * @see #TOK_DECL_OPEN * @see #TOK_DECL_CLOSE * @see #TOK_NAME * @see #TOK_NMTOKEN * @see #TOK_POUND_NAME * @see #TOK_OR * @see #TOK_PERCENT * @see #TOK_OPEN_PAREN * @see #TOK_CLOSE_PAREN * @see #TOK_OPEN_BRACKET * @see #TOK_CLOSE_BRACKET * @see #TOK_LITERAL * @see #TOK_NAME_QUESTION * @see #TOK_NAME_ASTERISK * @see #TOK_NAME_PLUS * @see #TOK_COND_SECT_OPEN * @see #TOK_COND_SECT_CLOSE * @see #TOK_CLOSE_PAREN_QUESTION * @see #TOK_CLOSE_PAREN_ASTERISK * @see #TOK_CLOSE_PAREN_PLUS * @see #TOK_COMMA * @see ContentToken * @see EmptyTokenException * @see PartialTokenException * @see InvalidTokenException * @see ExtensibleTokenException * @see EndOfPrologException */ public static int tokenizeProlog(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException, EmptyTokenException, ExtensibleTokenException, EndOfPrologException { int tok; if (off == end) throw new EmptyTokenException(); switch (charType(buf[off])) { case CT_QUOT: return scanLit(CT_QUOT, buf, off + 1, end, token); case CT_APOS: return scanLit(CT_APOS, buf, off + 1, end, token); case CT_LT: { off += 1; if (off == end) throw new PartialTokenException(); switch (charType(buf[off])) { case CT_EXCL: return scanDecl(buf, off + 1, end, token); case CT_QUEST: return scanPi(buf, off + 1, end, token); case CT_NMSTRT: case CT_LEAD2: token.tokenEnd = off - 1; throw new EndOfPrologException(); } throw new InvalidTokenException(off); } case CT_CR: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_PROLOG_S); if (charType(buf[off]) == CT_LF) off += 1; token.tokenEnd = off; return TOK_PROLOG_S; case CT_S: case CT_LF: token.tokenEnd = off + 1; return TOK_PROLOG_S; case CT_PERCNT: return scanPercent(buf, off + 1, end, token); case CT_COMMA: token.tokenEnd = off + 1; return TOK_COMMA; case CT_LSQB: token.tokenEnd = off + 1; return TOK_OPEN_BRACKET; case CT_RSQB: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_CLOSE_BRACKET); if (buf[off] == ']') { if (off + 1 == end) throw new PartialTokenException(); if (buf[off + 1] == '>') { token.tokenEnd = off + 2; return TOK_COND_SECT_CLOSE; } } token.tokenEnd = off; return TOK_CLOSE_BRACKET; case CT_LPAR: token.tokenEnd = off + 1; return TOK_OPEN_PAREN; case CT_RPAR: off += 1; if (off == end) throw new ExtensibleTokenException(TOK_CLOSE_PAREN); switch (charType(buf[off])) { case CT_AST: token.tokenEnd = off + 1; return TOK_CLOSE_PAREN_ASTERISK; case CT_QUEST: token.tokenEnd = off + 1; return TOK_CLOSE_PAREN_QUESTION; case CT_PLUS: token.tokenEnd = off + 1; return TOK_CLOSE_PAREN_PLUS; case CT_CR: case CT_LF: case CT_S: case CT_GT: case CT_COMMA: case CT_VERBAR: case CT_RPAR: token.tokenEnd = off; return TOK_CLOSE_PAREN; } throw new InvalidTokenException(off); case CT_VERBAR: token.tokenEnd = off + 1; return TOK_OR; case CT_GT: token.tokenEnd = off + 1; return TOK_DECL_CLOSE; case CT_NUM: return scanPoundName(buf, off + 1, end, token); case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); switch (charType2(buf, off)) { case CT_NMSTRT: off += 2; tok = TOK_NAME; break; case CT_NAME: off += 2; tok = TOK_NMTOKEN; break; default: throw new InvalidTokenException(off); } break; case CT_NMSTRT: tok = TOK_NAME; off += 1; break; case CT_NAME: case CT_MINUS: case CT_COLON: tok = TOK_NMTOKEN; off += 1; break; default: throw new InvalidTokenException(off); } while (off != end) { switch (charType(buf[off])) { case CT_NMSTRT: case CT_NAME: case CT_MINUS: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (!isNameChar2(buf, off)) throw new InvalidTokenException(off); off += 2; break; case CT_GT: case CT_RPAR: case CT_COMMA: case CT_VERBAR: case CT_LSQB: case CT_PERCNT: case CT_S: case CT_CR: case CT_LF: token.tokenEnd = off; return tok; case CT_COLON: off += 1; switch (tok) { case TOK_NAME: if (off == end) throw new PartialCharException(off); tok = TOK_PREFIXED_NAME; switch (charType(buf[off])) { case CT_NMSTRT: off += 1; break; case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); if (isNameChar2(buf, off)) { off += 2; break; } // fall through default: tok = TOK_NMTOKEN; break; } break; case TOK_PREFIXED_NAME: tok = TOK_NMTOKEN; break; } break; case CT_PLUS: if (tok == TOK_NMTOKEN) throw new InvalidTokenException(off); token.tokenEnd = off + 1; return TOK_NAME_PLUS; case CT_AST: if (tok == TOK_NMTOKEN) throw new InvalidTokenException(off); token.tokenEnd = off + 1; return TOK_NAME_ASTERISK; case CT_QUEST: if (tok == TOK_NMTOKEN) throw new InvalidTokenException(off); token.tokenEnd = off + 1; return TOK_NAME_QUESTION; default: throw new InvalidTokenException(off); } } throw new ExtensibleTokenException(tok); } /** * Scans the first token of a char subarrary that contains part of * literal attribute value. The opening and closing delimiters * are not included in the subarrary. * Returns one of the following integers according to the type of * token that the subarray starts with: *
      *
    • TOK_DATA_CHARS *
    • TOK_DATA_NEWLINE *
    • TOK_ATTRIBUTE_VALUE_S *
    • TOK_MAGIC_ENTITY_REF *
    • TOK_ENTITY_REF *
    • TOK_CHAR_REF *
    • TOK_CHAR_PAIR_REF *
    * @exception EmptyTokenException if the subarray is empty * @exception PartialTokenException if the subarray contains only part of * a legal token * @exception InvalidTokenException if the subarrary does not start * with a legal token or part of one * @exception ExtensibleTokenException if the subarray encodes just a carriage * return ('\r') * @see #TOK_DATA_CHARS * @see #TOK_DATA_NEWLINE * @see #TOK_ATTRIBUTE_VALUE_S * @see #TOK_MAGIC_ENTITY_REF * @see #TOK_ENTITY_REF * @see #TOK_CHAR_REF * @see #TOK_CHAR_PAIR_REF * @see Token * @see EmptyTokenException * @see PartialTokenException * @see InvalidTokenException * @see ExtensibleTokenException */ public static int tokenizeAttributeValue(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException, EmptyTokenException, ExtensibleTokenException { if (off == end) throw new EmptyTokenException(); int start = off; while (off != end) { switch (charType(buf[off])) { case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); off += 2; break; case CT_AMP: if (off == start) return scanRef(buf, off + 1, end, token); token.tokenEnd = off; return TOK_DATA_CHARS; case CT_LT: /* this is for inside entity references */ throw new InvalidTokenException(off); case CT_S: if (off == start) { token.tokenEnd = off + 1; return TOK_ATTRIBUTE_VALUE_S; } token.tokenEnd = off; return TOK_DATA_CHARS; case CT_LF: if (off == start) { token.tokenEnd = off + 1; return TOK_DATA_NEWLINE; } token.tokenEnd = off; return TOK_DATA_CHARS; case CT_CR: if (off == start) { off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_NEWLINE); if (charType(buf[off]) == CT_LF) off += 1; token.tokenEnd = off; return TOK_DATA_NEWLINE; } token.tokenEnd = off; return TOK_DATA_CHARS; default: off += 1; break; } } token.tokenEnd = off; return TOK_DATA_CHARS; } /** * Scans the first token of a char subarrary that contains part of * literal entity value. The opening and closing delimiters * are not included in the subarrary. * Returns one of the following integers according to the type of * token that the subarray starts with: *
      *
    • TOK_DATA_CHARS *
    • TOK_DATA_NEWLINE *
    • TOK_PARAM_ENTITY_REF *
    • TOK_MAGIC_ENTITY_REF *
    • TOK_ENTITY_REF *
    • TOK_CHAR_REF *
    • TOK_CHAR_PAIR_REF *
    * @exception EmptyTokenException if the subarray is empty * @exception PartialTokenException if the subarray contains only part of * a legal token * @exception InvalidTokenException if the subarrary does not start * with a legal token or part of one * @exception ExtensibleTokenException if the subarray encodes just a carriage * return ('\r') * @see #TOK_DATA_CHARS * @see #TOK_DATA_NEWLINE * @see #TOK_MAGIC_ENTITY_REF * @see #TOK_ENTITY_REF * @see #TOK_PARAM_ENTITY_REF * @see #TOK_CHAR_REF * @see #TOK_CHAR_PAIR_REF * @see Token * @see EmptyTokenException * @see PartialTokenException * @see InvalidTokenException * @see ExtensibleTokenException */ public static int tokenizeEntityValue(char[] buf, int off, int end, Token token) throws PartialTokenException, InvalidTokenException, EmptyTokenException, ExtensibleTokenException { if (off == end) throw new EmptyTokenException(); int start = off; while (off != end) { switch (charType(buf[off])) { case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); off += 2; break; case CT_AMP: if (off == start) return scanRef(buf, off + 1, end, token); token.tokenEnd = off; return TOK_DATA_CHARS; case CT_PERCNT: if (off == start) { int tok = scanPercent(buf, off + 1, end, token); if (tok == TOK_PERCENT) throw new InvalidTokenException(off + 1); return tok; } token.tokenEnd = off; return TOK_DATA_CHARS; case CT_LF: if (off == start) { token.tokenEnd = off + 1; return TOK_DATA_NEWLINE; } token.tokenEnd = off; return TOK_DATA_CHARS; case CT_CR: if (off == start) { off += 1; if (off == end) throw new ExtensibleTokenException(TOK_DATA_NEWLINE); if (charType(buf[off]) == CT_LF) off += 1; token.tokenEnd = off; return TOK_DATA_NEWLINE; } token.tokenEnd = off; return TOK_DATA_CHARS; default: off += 1; break; } } token.tokenEnd = off; return TOK_DATA_CHARS; } /** * Skips over an ignored conditional section. * The subarray starts following the <![ IGNORE [. * * @return the index of the character following the closing * ]]> * * @exception PartialTokenException if the subarray does not contain the * complete ignored conditional section * @exception InvalidTokenException if the ignored conditional section * contains illegal characters */ public static int skipIgnoreSect(char[] buf, int off, int end) throws PartialTokenException, InvalidTokenException { int level = 0; loop: while (off != end) { switch (charType(buf[off])) { case CT_LEAD2: if (end - off < 2) throw new PartialCharException(off); check2(buf, off); off += 2; break; case CT_NONXML: case CT_MALFORM: throw new InvalidTokenException(off); case CT_LT: off += 1; if (off == end) break loop; if (buf[off] != '!') break; off += 1; if (off == end) break loop; if (buf[off] != '[') break; level++; off += 1; break; case CT_RSQB: off += 1; if (off == end) break loop; if (buf[off] != ']') break; off += 1; if (off == end) break loop; if (buf[off] == '>') { if (level == 0) return off + 1; level--; } else if (buf[off] == ']') break; off += 1; break; default: off += 1; break; } } throw new PartialTokenException(); } /** * Checks that a literal contained in the specified char subarray * is a legal public identifier and returns a string with * the normalized content of the public id. * The subarray includes the opening and closing quotes. * @exception InvalidTokenException if it is not a legal public identifier */ public static String getPublicId(char[] buf, int off, int end) throws InvalidTokenException { StringBuffer sbuf = new StringBuffer(); off += 1; end -= 1; for (; off != end; off += 1) { char c = buf[off]; switch (charType(buf[off])) { case CT_MINUS: case CT_APOS: case CT_LPAR: case CT_RPAR: case CT_PLUS: case CT_COMMA: case CT_SOL: case CT_EQUALS: case CT_QUEST: case CT_SEMI: case CT_EXCL: case CT_AST: case CT_PERCNT: case CT_NUM: case CT_COLON: sbuf.append(c); break; case CT_S: if (buf[off] == '\t') throw new InvalidTokenException(off); /* fall through */ case CT_CR: case CT_LF: if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) != ' ') sbuf.append(' '); break; case CT_NAME: case CT_NMSTRT: if ((c & ~0x7f) == 0) { sbuf.append(c); break; } // fall through default: switch (c) { case '$': case '@': break; default: throw new InvalidTokenException(off); } break; } } if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) == ' ') sbuf.setLength(sbuf.length() - 1); return sbuf.toString(); } /** * Returns true if the specified char subarray is equal to the string. * The string must contain only XML significant characters. */ public static boolean matchesXMLString(char[] buf, int off, int end, String str) { int len = str.length(); if (len != end - off) return false; for (int i = 0; i < len; off += 1, i++) { if (buf[off] != str.charAt(i)) return false; } return true; } /** * Skips over XML whitespace characters at the start of the specified * subarray. * * @return the index of the first non-whitespace character, * end if there is the subarray is all whitespace */ public static int skipS(char[] buf, int off, int end) { loop: while (off < end) { switch (charType(buf[off])) { case CT_S: case CT_CR: case CT_LF: off += 1; break; default: break loop; } } return off; } private static boolean isNameChar2(char[] buf, int off) { int ct = charType2(buf, off); return ct == CT_NAME || ct == CT_NMSTRT; } private static final String nameStartSingles = "\u003a\u005f\u0386\u038c\u03da\u03dc\u03de\u03e0\u0559\u06d5\u093d\u09b2" + "\u0a5e\u0a8d\u0abd\u0ae0\u0b3d\u0b9c\u0cde\u0e30\u0e84\u0e8a\u0e8d\u0ea5" + "\u0ea7\u0eb0\u0ebd\u1100\u1109\u113c\u113e\u1140\u114c\u114e\u1150\u1159" + "\u1163\u1165\u1167\u1169\u1175\u119e\u11a8\u11ab\u11ba\u11eb\u11f0\u11f9" + "\u1f59\u1f5b\u1f5d\u1fbe\u2126\u212e\u3007"; private static final String nameStartRanges = "\u0041\u005a\u0061\u007a\u00c0\u00d6\u00d8\u00f6\u00f8\u00ff\u0100\u0131" + "\u0134\u013e\u0141\u0148\u014a\u017e\u0180\u01c3\u01cd\u01f0\u01f4\u01f5" + "\u01fa\u0217\u0250\u02a8\u02bb\u02c1\u0388\u038a\u038e\u03a1\u03a3\u03ce" + "\u03d0\u03d6\u03e2\u03f3\u0401\u040c\u040e\u044f\u0451\u045c\u045e\u0481" + "\u0490\u04c4\u04c7\u04c8\u04cb\u04cc\u04d0\u04eb\u04ee\u04f5\u04f8\u04f9" + "\u0531\u0556\u0561\u0586\u05d0\u05ea\u05f0\u05f2\u0621\u063a\u0641\u064a" + "\u0671\u06b7\u06ba\u06be\u06c0\u06ce\u06d0\u06d3\u06e5\u06e6\u0905\u0939" + "\u0958\u0961\u0985\u098c\u098f\u0990\u0993\u09a8\u09aa\u09b0\u09b6\u09b9" + "\u09dc\u09dd\u09df\u09e1\u09f0\u09f1\u0a05\u0a0a\u0a0f\u0a10\u0a13\u0a28" + "\u0a2a\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59\u0a5c\u0a72\u0a74" + "\u0a85\u0a8b\u0a8f\u0a91\u0a93\u0aa8\u0aaa\u0ab0\u0ab2\u0ab3\u0ab5\u0ab9" + "\u0b05\u0b0c\u0b0f\u0b10\u0b13\u0b28\u0b2a\u0b30\u0b32\u0b33\u0b36\u0b39" + "\u0b5c\u0b5d\u0b5f\u0b61\u0b85\u0b8a\u0b8e\u0b90\u0b92\u0b95\u0b99\u0b9a" + "\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0baa\u0bae\u0bb5\u0bb7\u0bb9\u0c05\u0c0c" + "\u0c0e\u0c10\u0c12\u0c28\u0c2a\u0c33\u0c35\u0c39\u0c60\u0c61\u0c85\u0c8c" + "\u0c8e\u0c90\u0c92\u0ca8\u0caa\u0cb3\u0cb5\u0cb9\u0ce0\u0ce1\u0d05\u0d0c" + "\u0d0e\u0d10\u0d12\u0d28\u0d2a\u0d39\u0d60\u0d61\u0e01\u0e2e\u0e32\u0e33" + "\u0e40\u0e45\u0e81\u0e82\u0e87\u0e88\u0e94\u0e97\u0e99\u0e9f\u0ea1\u0ea3" + "\u0eaa\u0eab\u0ead\u0eae\u0eb2\u0eb3\u0ec0\u0ec4\u0f40\u0f47\u0f49\u0f69" + "\u10a0\u10c5\u10d0\u10f6\u1102\u1103\u1105\u1107\u110b\u110c\u110e\u1112" + "\u1154\u1155\u115f\u1161\u116d\u116e\u1172\u1173\u11ae\u11af\u11b7\u11b8" + "\u11bc\u11c2\u1e00\u1e9b\u1ea0\u1ef9\u1f00\u1f15\u1f18\u1f1d\u1f20\u1f45" + "\u1f48\u1f4d\u1f50\u1f57\u1f5f\u1f7d\u1f80\u1fb4\u1fb6\u1fbc\u1fc2\u1fc4" + "\u1fc6\u1fcc\u1fd0\u1fd3\u1fd6\u1fdb\u1fe0\u1fec\u1ff2\u1ff4\u1ff6\u1ffc" + "\u212a\u212b\u2180\u2182\u3041\u3094\u30a1\u30fa\u3105\u312c\uac00\ud7a3" + "\u4e00\u9fa5\u3021\u3029"; private static final String nameSingles = "\u002d\u002e\u05bf\u05c4\u0670\u093c\u094d\u09bc\u09be\u09bf\u09d7\u0a02" + "\u0a3c\u0a3e\u0a3f\u0abc\u0b3c\u0bd7\u0d57\u0e31\u0eb1\u0f35\u0f37\u0f39" + "\u0f3e\u0f3f\u0f97\u0fb9\u20e1\u3099\u309a\u00b7\u02d0\u02d1\u0387\u0640" + "\u0e46\u0ec6\u3005"; private static final String nameRanges = "\u0300\u0345\u0360\u0361\u0483\u0486\u0591\u05a1\u05a3\u05b9\u05bb\u05bd" + "\u05c1\u05c2\u064b\u0652\u06d6\u06dc\u06dd\u06df\u06e0\u06e4\u06e7\u06e8" + "\u06ea\u06ed\u0901\u0903\u093e\u094c\u0951\u0954\u0962\u0963\u0981\u0983" + "\u09c0\u09c4\u09c7\u09c8\u09cb\u09cd\u09e2\u09e3\u0a40\u0a42\u0a47\u0a48" + "\u0a4b\u0a4d\u0a70\u0a71\u0a81\u0a83\u0abe\u0ac5\u0ac7\u0ac9\u0acb\u0acd" + "\u0b01\u0b03\u0b3e\u0b43\u0b47\u0b48\u0b4b\u0b4d\u0b56\u0b57\u0b82\u0b83" + "\u0bbe\u0bc2\u0bc6\u0bc8\u0bca\u0bcd\u0c01\u0c03\u0c3e\u0c44\u0c46\u0c48" + "\u0c4a\u0c4d\u0c55\u0c56\u0c82\u0c83\u0cbe\u0cc4\u0cc6\u0cc8\u0cca\u0ccd" + "\u0cd5\u0cd6\u0d02\u0d03\u0d3e\u0d43\u0d46\u0d48\u0d4a\u0d4d\u0e34\u0e3a" + "\u0e47\u0e4e\u0eb4\u0eb9\u0ebb\u0ebc\u0ec8\u0ecd\u0f18\u0f19\u0f71\u0f84" + "\u0f86\u0f8b\u0f90\u0f95\u0f99\u0fad\u0fb1\u0fb7\u20d0\u20dc\u302a\u302f" + "\u0030\u0039\u0660\u0669\u06f0\u06f9\u0966\u096f\u09e6\u09ef\u0a66\u0a6f" + "\u0ae6\u0aef\u0b66\u0b6f\u0be7\u0bef\u0c66\u0c6f\u0ce6\u0cef\u0d66\u0d6f" + "\u0e50\u0e59\u0ed0\u0ed9\u0f20\u0f29\u3031\u3035\u309d\u309e\u30fc\u30fe"; private final static byte[][] charTypeTable; private static void setCharType(char c, int type) { if (c < 0x80) return; int hi = c >> 8; if (charTypeTable[hi] == null) { charTypeTable[hi] = new byte[256]; for (int i = 0; i < 256; i++) charTypeTable[hi][i] = CT_OTHER; } charTypeTable[hi][c & 0xFF] = (byte)type; } private static void setCharType(char min, char max, int type) { byte[] shared = null; do { if ((min & 0xFF) == 0) { for (; min + 0xFF <= max; min += 0x100) { if (shared == null) { shared = new byte[256]; for (int i = 0; i < 256; i++) shared[i] = (byte)type; } charTypeTable[min >> 8] = shared; if (min + 0xFF == max) return; } } setCharType(min, type); } while (min++ != max); } static { charTypeTable = new byte[256][]; for (int i = 0; i < nameSingles.length(); i++) setCharType(nameSingles.charAt(i), CT_NAME); for (int i = 0; i < nameRanges.length(); i += 2) setCharType(nameRanges.charAt(i), nameRanges.charAt(i + 1), CT_NAME); for (int i = 0; i < nameStartSingles.length(); i++) setCharType(nameStartSingles.charAt(i), CT_NMSTRT); for (int i = 0; i < nameStartRanges.length(); i += 2) setCharType(nameStartRanges.charAt(i), nameStartRanges.charAt(i + 1), CT_NMSTRT); setCharType('\uD800', '\uDBFF', CT_LEAD2); setCharType('\uDC00', '\uDFFF', CT_MALFORM); setCharType('\uFFFE', '\uFFFF', CT_NONXML); byte[] other = new byte[256]; for (int i = 0; i < 256; i++) other[i] = CT_OTHER; for (int i = 0; i < 256; i++) if (charTypeTable[i] == null) charTypeTable[i] = other; System.arraycopy(asciiTypeTable, 0, charTypeTable[0], 0, 128); } static int charType(char c) { return charTypeTable[c >> 8][c & 0xFF]; } // Called only when charType(buf[off]) == CT_LEAD2 static private int charType2(char[] buf, int off) { return CT_OTHER; } static private void check2(char[] buf, int off) throws InvalidTokenException { } } jing-trang-20131210+dfsg+1/mod/dtd-parse/todo.txt000066400000000000000000000032551225366607500212510ustar00rootroot00000000000000Put location information in the object model. Support OASIS catalogs. Option for properties file to set properties. Option to set start elements. Make UriEntityManager respect charset parameter. Make UriEntityManager get the right base URI after HTTP redirection. Add DtdParseException to om package. Maybe better to avoid empty sequences and empty choices in the object model. Methods on DTD giving random access to various kinds of declaration. Command-line options to expand/not recognize various kinds of ref. Command-line option to define a parameter entity as INCLUDE. Maybe distinguish char entities in object model; or perhaps represent result of parsing entity. Try to parse ignored marked sections. Warning for unused parameter entities. String pasting. SAXEntityManager (support Norm's entity manager) Check that no default value for ID. Check that at most one ID per element type. Check at most one NOTATION attribute per element. Check that members of NOTATION enumeration are declared as NOTATION attributes. Check that EMPTY elements don't have a NOTATION attribute. Check that attribute defaults are legal. Check that notation name of unparsed external entity is declared. Check no duplicate element names in mixed content model. Use nameSpec for general entities. EncodingDetectInputStream should support entities that need an XmlDecl rather than a TextDecl. In EncodingDetectInputStream should check that encoding specified in XML declaration is consistent with auto-detected encoding. Add a MINIMIZATION_SEMANTIC to deal with TEI RR/RO. Cleanup handling of newline normalization. Line-wrapping for long attribute lists in XmlWriter. private and nested classes jing-trang-20131210+dfsg+1/mod/dtdinst/000077500000000000000000000000001225366607500173245ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/mod.xml000066400000000000000000000007231225366607500206270ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/dtdinst/src/000077500000000000000000000000001225366607500201135ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/000077500000000000000000000000001225366607500210375ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/000077500000000000000000000000001225366607500216155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/000077500000000000000000000000001225366607500246455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/000077500000000000000000000000001225366607500254455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/000077500000000000000000000000001225366607500262205ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/app/000077500000000000000000000000001225366607500270005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/app/Driver.java000066400000000000000000000032221225366607500310750ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.app; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.UriOrFile; import com.thaiopensource.util.Version; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.parse.DtdParserImpl; import com.thaiopensource.xml.out.XmlWriter; import com.thaiopensource.xml.em.UriEntityManager; import java.io.IOException; public class Driver { private static final int FAILURE_EXIT_CODE = 1; private static final Localizer localizer = new Localizer(Driver.class); public static void main(String[] args) { try { if (doMain(args)) return; } catch (IOException e) { error(e.getMessage()); } System.exit(FAILURE_EXIT_CODE); } public static boolean doMain(String args[]) throws IOException { if (args.length == 0) { error(localizer.message("MISSING_ARGUMENT")); usage(); return false; } if (args.length > 1) { error(localizer.message("TOO_MANY_ARGUMENTS")); usage(); return false; } String uri = UriOrFile.toUri(args[0]); Dtd dtd = new DtdParserImpl().parse(uri, new UriEntityManager()); XmlWriter w = new XmlOutputStreamWriter(System.out, dtd.getEncoding()); new SchemaWriter(w).writeDtd(dtd); w.close(); return true; } private static void usage() { print(localizer.message("USAGE", Version.getVersion(Driver.class))); } private static void error(String str) { print(localizer.message("ERROR", str)); } private static void warning(String str) { print(localizer.message("WARNING", str)); } private static void print(String str) { System.err.println(str); } } jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/app/SchemaWriter.java000066400000000000000000000234561225366607500322520ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.app; import java.io.IOException; import com.thaiopensource.xml.dtd.om.*; import com.thaiopensource.xml.out.XmlWriter; import com.thaiopensource.xml.em.ExternalId; public class SchemaWriter implements TopLevelVisitor, ModelGroupVisitor, AttributeGroupVisitor, DatatypeVisitor, EnumGroupVisitor, FlagVisitor, NameSpecVisitor, AttributeDefaultVisitor { private final XmlWriter w; public SchemaWriter(XmlWriter writer) { this.w = writer; } public void writeDtd(Dtd dtd) throws IOException { String enc = dtd.getEncoding(); if (enc != null) w.writeXmlDecl(enc); w.startElement("doctype"); try { dtd.accept(this); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw (IOException)e; } w.endElement(); } public void elementDecl(NameSpec nameSpec, ModelGroup modelGroup) throws Exception { w.startElement("element"); nameSpec.accept(this); modelGroup.accept(this); w.endElement(); } public void attlistDecl(NameSpec nameSpec, AttributeGroup attributeGroup) throws Exception { w.startElement("attlist"); nameSpec.accept(this); attributeGroup.accept(this); w.endElement(); } public void processingInstruction(String target, String value) throws Exception { w.startElement("processingInstruction"); w.attribute("target", target); w.characters(value); w.endElement(); } public void comment(String value) throws Exception { w.startElement("comment"); w.characters(value); w.endElement(); } public void modelGroupDef(String name, ModelGroup modelGroup) throws Exception { w.startElement("modelGroup"); w.attribute("name", name); modelGroup.accept(this); w.endElement(); } public void attributeGroupDef(String name, AttributeGroup attributeGroup) throws Exception { w.startElement("attributeGroup"); w.attribute("name", name); attributeGroup.accept(this); w.endElement(); } public void enumGroupDef(String name, EnumGroup enumGroup) throws Exception { w.startElement("enumGroup"); w.attribute("name", name); enumGroup.accept(this); w.endElement(); } public void datatypeDef(String name, Datatype datatype) throws Exception { w.startElement("datatype"); w.attribute("name", name); datatype.accept(this); w.endElement(); } public void flagDef(String name, Flag flag) throws Exception { w.startElement("flag"); w.attribute("name", name); flag.accept(this); w.endElement(); } public void attributeDefaultDef(String name, AttributeDefault attributeDefault) throws Exception { w.startElement("attributeDefault"); w.attribute("name", name); attributeDefault.accept(this); w.endElement(); } public void choice(ModelGroup[] members) throws Exception { w.startElement("choice"); for (int i = 0; i < members.length; i++) members[i].accept(this); w.endElement(); } public void sequence(ModelGroup[] members) throws Exception { w.startElement("sequence"); for (int i = 0; i < members.length; i++) members[i].accept(this); w.endElement(); } public void oneOrMore(ModelGroup member) throws Exception { w.startElement("oneOrMore"); member.accept(this); w.endElement(); } public void zeroOrMore(ModelGroup member) throws Exception { w.startElement("zeroOrMore"); member.accept(this); w.endElement(); } public void optional(ModelGroup member) throws Exception { w.startElement("optional"); member.accept(this); w.endElement(); } public void modelGroupRef(String name, ModelGroup modelGroup) throws Exception { w.startElement("modelGroupRef"); w.attribute("name", name); w.endElement(); } public void elementRef(NameSpec nameSpec) throws Exception { w.startElement("elementRef"); nameSpec.accept(this); w.endElement(); } public void pcdata() throws Exception { w.startElement("pcdata"); w.endElement(); } public void any() throws Exception { w.startElement("any"); w.endElement(); } public void attribute(NameSpec nameSpec, Datatype datatype, AttributeDefault attributeDefault) throws Exception { w.startElement("attribute"); nameSpec.accept(this); datatype.accept(this); attributeDefault.accept(this); w.endElement(); } public void attributeGroupRef(String name, AttributeGroup attributeGroup) throws Exception { w.startElement("attributeGroupRef"); w.attribute("name", name); w.endElement(); } public void enumValue(String value) throws Exception { w.startElement("enum"); w.characters(value); w.endElement(); } public void enumGroupRef(String name, EnumGroup enumGroup) throws Exception { w.startElement("enumGroupRef"); w.attribute("name", name); w.endElement(); } public void cdataDatatype() throws IOException { w.startElement("cdata"); w.endElement(); } public void tokenizedDatatype(String typeName) throws IOException { w.startElement("tokenized"); w.attribute("name", typeName); w.endElement(); } public void enumDatatype(EnumGroup enumGroup) throws Exception { w.startElement("tokenized"); enumGroup.accept(this); w.endElement(); } public void notationDatatype(EnumGroup enumGroup) throws Exception { w.startElement("tokenized"); w.attribute("name", "NOTATION"); enumGroup.accept(this); w.endElement(); } public void datatypeRef(String name, Datatype datatype) throws IOException { w.startElement("datatypeRef"); w.attribute("name", name); w.endElement(); } public void flagRef(String name, Flag flag) throws IOException { w.startElement("flagRef"); w.attribute("name", name); w.endElement(); } public void include() throws IOException { w.startElement("include"); w.endElement(); } public void ignore() throws IOException { w.startElement("ignore"); w.endElement(); } public void includedSection(Flag flag, TopLevel[] contents) throws Exception { w.startElement("includedSection"); if (flag instanceof FlagRef) w.attribute("flag", ((FlagRef)flag).getName()); for (int i = 0; i < contents.length; i++) contents[i].accept(this); w.endElement(); } public void ignoredSection(Flag flag, String contents) throws Exception { w.startElement("ignoredSection"); if (flag instanceof FlagRef) w.attribute("flag", ((FlagRef)flag).getName()); w.characters(contents); w.endElement(); } public void externalIdDef(String name, ExternalId xid) throws IOException { w.startElement("externalId"); w.attribute("name", name); externalId(xid); w.endElement(); } public void externalIdRef(String name, ExternalId xid, String uri, String encoding, TopLevel[] contents) throws Exception { w.startElement("externalIdRef"); w.attribute("name", name); for (int i = 0; i < contents.length; i++) contents[i].accept(this); w.endElement(); } public void internalEntityDecl(String name, String value) throws Exception { w.startElement("internalEntity"); w.attribute("name", name); boolean useCharRef = value.length() == 1 && value.charAt(0) >= 0x80; w.characters(value, useCharRef); w.endElement(); } public void externalEntityDecl(String name, ExternalId xid) throws IOException { w.startElement("externalEntity"); w.attribute("name", name); externalId(xid); w.endElement(); } public void notationDecl(String name, ExternalId xid) throws IOException { w.startElement("notation"); w.attribute("name", name); externalId(xid); w.endElement(); } private void externalId(ExternalId xid) throws IOException { attributeIfNotNull("system", xid.getSystemId()); attributeIfNotNull("public", xid.getPublicId()); // this messes up testing // attributeIfNotNull("xml:base", xid.getBaseUri()); } private void attributeIfNotNull(String name, String value) throws IOException { if (value != null) w.attribute(name, value); } public void nameSpecDef(String name, NameSpec nameSpec) throws Exception { w.startElement("nameSpec"); w.attribute("name", name); nameSpec.accept(this); w.endElement(); } public void name(String value) throws IOException { w.startElement("name"); w.characters(value); w.endElement(); } public void nameSpecRef(String name, NameSpec nameSpec) throws Exception { w.startElement("nameSpecRef"); w.attribute("name", name); w.endElement(); } public void overriddenDef(Def def, boolean duplicate) throws Exception { w.startElement("overridden"); if (duplicate) { w.startElement("duplicate"); w.attribute("name", def.getName()); w.endElement(); } else def.accept(this); w.endElement(); } public void paramDef(String name, String value) throws IOException { w.startElement("param"); w.attribute("name", name); w.characters(value); w.endElement(); } public void defaultValue(String value) throws Exception { w.startElement("default"); w.characters(value); w.endElement(); } public void fixedValue(String value) throws Exception { w.startElement("fixed"); w.characters(value); w.endElement(); } public void impliedValue() throws Exception { w.startElement("implied"); w.endElement(); } public void requiredValue() throws Exception { w.startElement("required"); w.endElement(); } public void attributeDefaultRef(String name, AttributeDefault attributeDefault) throws Exception { w.startElement("attributeDefaultRef"); w.attribute("name", name); w.endElement(); } } XmlOutputStreamWriter.java000066400000000000000000000013561225366607500341230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/apppackage com.thaiopensource.xml.dtd.app; import java.io.BufferedWriter; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import com.thaiopensource.xml.out.XmlWriter; import com.thaiopensource.xml.out.CharRepertoire; import com.thaiopensource.xml.util.EncodingMap; public class XmlOutputStreamWriter extends XmlWriter { public XmlOutputStreamWriter(OutputStream out, String enc) throws UnsupportedEncodingException { this(EncodingMap.getJavaName(enc), out); } private XmlOutputStreamWriter(String jEnc, OutputStream out) throws UnsupportedEncodingException { super(new BufferedWriter(new OutputStreamWriter(out, jEnc)), CharRepertoire.getInstance(jEnc)); } } jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/app/resources/000077500000000000000000000000001225366607500310125ustar00rootroot00000000000000Messages.properties000066400000000000000000000005561225366607500346260ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/main/com/thaiopensource/xml/dtd/app/resources# Properties file specifying messages # key=message MISSING_ARGUMENT=missing argument USAGE=DTDinst version {0}\n\ Usage: java com.thaiopensource.xml.dtd.app.Driver DTD\n\ DTDinst converts XML DTDs to XML instance format.\n\ See http://www.thaiopensource.com/dtdinst/ for more information. TOO_MANY_ARGUMENTS=too many arguments ERROR=Error: {0} WARNING=Warning: {0} jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/000077500000000000000000000000001225366607500210725ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/000077500000000000000000000000001225366607500216505ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/000077500000000000000000000000001225366607500247005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/000077500000000000000000000000001225366607500255005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/000077500000000000000000000000001225366607500262535ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/test/000077500000000000000000000000001225366607500272325ustar00rootroot00000000000000CompareFailException.java000066400000000000000000000004601225366607500340570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/testpackage com.thaiopensource.xml.dtd.test; import java.io.IOException; public class CompareFailException extends IOException { private final long byteIndex; public CompareFailException(long byteIndex) { this.byteIndex = byteIndex; } public long getByteIndex() { return byteIndex; } } CompareOutputStream.java000066400000000000000000000011401225366607500337750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/testpackage com.thaiopensource.xml.dtd.test; import java.io.OutputStream; import java.io.InputStream; import java.io.IOException; public class CompareOutputStream extends OutputStream { private final InputStream in; private long byteIndex = 0; public CompareOutputStream(InputStream in) { this.in = in; } public void write(int b) throws IOException { if (in.read() != (b & 0xFF)) throw new CompareFailException(byteIndex); byteIndex++; } public void close() throws IOException { if (in.read() != -1) throw new CompareFailException(byteIndex); in.close(); } } jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/test/Driver.java000066400000000000000000000044571225366607500313420ustar00rootroot00000000000000package com.thaiopensource.xml.dtd.test; import java.io.IOException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.BufferedInputStream; import java.util.Hashtable; import com.thaiopensource.xml.out.XmlWriter; import com.thaiopensource.xml.dtd.om.DtdParser; import com.thaiopensource.xml.dtd.om.Dtd; import com.thaiopensource.xml.dtd.parse.DtdParserImpl; import com.thaiopensource.xml.dtd.app.SchemaWriter; import com.thaiopensource.xml.dtd.app.XmlOutputStreamWriter; import com.thaiopensource.xml.em.FileEntityManager; public class Driver { public static void main (String args[]) throws IOException, TestFailException { String dir = args[0]; String failDir = args[1]; String[] files = new File(dir).list(); Hashtable fileTable = new Hashtable(); for (int i = 0; i < files.length; i++) fileTable.put(files[i], files[i]); String failures = null; for (int i = 0; i < files.length; i++) if (files[i].endsWith(".dtd")) { String inFile = files[i]; String outFile = inFile.substring(0, inFile.length() - 4) + ".xml"; if (fileTable.get(outFile) != null) { try { System.err.println("Running test " + inFile); runCompareTest(new File(dir, inFile), new File(dir, outFile)); } catch (CompareFailException e) { System.err.println(inFile + " failed at byte " + e.getByteIndex()); if (failures == null) failures = inFile; else failures += " " + inFile; runOutputTest(new File(dir, inFile), new File(failDir, outFile)); } } } if (failures != null) throw new TestFailException(failures); } public static void runCompareTest(File inFile, File outFile) throws IOException { runTest(inFile, new CompareOutputStream(new BufferedInputStream(new FileInputStream(outFile)))); } public static void runOutputTest(File inFile, File outFile) throws IOException { runTest(inFile, new FileOutputStream(outFile)); } private static void runTest(File inFile, OutputStream out) throws IOException { DtdParser dtdParser = new DtdParserImpl(); Dtd dtd = dtdParser.parse(inFile.toString(), new FileEntityManager()); XmlWriter w = new XmlOutputStreamWriter(out, dtd.getEncoding()); new SchemaWriter(w).writeDtd(dtd); w.close(); } } TestFailException.java000066400000000000000000000002441225366607500334100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/dtdinst/src/test/com/thaiopensource/xml/dtd/testpackage com.thaiopensource.xml.dtd.test; public class TestFailException extends Exception { public TestFailException(String message) { super(message); } } jing-trang-20131210+dfsg+1/mod/infer/000077500000000000000000000000001225366607500167565ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/mod.xml000066400000000000000000000003471225366607500202630ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/infer/src/000077500000000000000000000000001225366607500175455ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/000077500000000000000000000000001225366607500204715ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/000077500000000000000000000000001225366607500212475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/000077500000000000000000000000001225366607500242775ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/000077500000000000000000000000001225366607500250775ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/000077500000000000000000000000001225366607500262025ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/AttributeDecl.java000066400000000000000000000007111225366607500315770ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; public class AttributeDecl { private final Name datatype; private final boolean optional; public AttributeDecl(Name datatype, boolean optional) { this.datatype = datatype; this.optional = optional; } /** * @return null for anything */ public Name getDatatype() { return datatype; } public boolean isOptional() { return optional; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/BinaryParticle.java000066400000000000000000000005401225366607500317540ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public abstract class BinaryParticle extends Particle { private final Particle p1; private final Particle p2; public BinaryParticle(Particle p1, Particle p2) { this.p1 = p1; this.p2 = p2; } public Particle getChild1() { return p1; } public Particle getChild2() { return p2; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ChoiceParticle.java000066400000000000000000000004071225366607500317240ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public class ChoiceParticle extends BinaryParticle { public ChoiceParticle(Particle p1, Particle p2) { super(p1, p2); } public Object accept(ParticleVisitor visitor) { return visitor.visitChoice(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ContentModelInferrer.java000066400000000000000000000007101225366607500331330ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import java.util.Set; public abstract class ContentModelInferrer { public abstract void addElement(Name elementName); public abstract void endSequence(); public abstract Particle inferContentModel(); public abstract Set getElementNames(); public static ContentModelInferrer createContentModelInferrer() { return new ContentModelInferrerImpl(); } } ContentModelInferrerImpl.java000066400000000000000000000165651225366607500337150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/inferpackage com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Stack; class ContentModelInferrerImpl extends ContentModelInferrer { private static final Name START = new Name("", "#start"); private static final Name END = new Name("", "#end"); /** * Maps names to nodes. */ private final Map nameMap = new HashMap(); private SingleNode prevNode; private final SingleNode startNode; private final SingleNode endNode; private static class SingleNode { final Set followingNodes = new HashSet(); final Name name; final int index; boolean repeated = false; SingleNode(Name name, int index) { this.name = name; this.index = index; } } private static class ParticleNode { final int index; Particle particle; int refCount = 0; Set followingNodes = new HashSet(); ParticleNode(int index) { this.index = index; } void addFollowing(ParticleNode p) { if (p != this) { if (!followingNodes.contains(p)) { p.refCount++; followingNodes.add(p); } } } } private static class StronglyConnectedComponentsFinder { private final int[] visited; private final SingleNode[] root; private int visitIndex = 0; private final Stack stack = new Stack(); private final ParticleNode[] particleNodes; private final SingleNode[] singleNodes; private int nParticles = 0; StronglyConnectedComponentsFinder(int nNodes) { visited = new int[nNodes]; root = new SingleNode[nNodes]; particleNodes = new ParticleNode[nNodes]; singleNodes = new SingleNode[nNodes]; } ParticleNode makeDag(SingleNode start) { visit(start); for (int i = 0; i < singleNodes.length; i++) for (SingleNode node : singleNodes[i].followingNodes) particleNodes[i].addFollowing(particleNodes[node.index]); return particleNodes[start.index]; } /** * http://citeseer.nj.nec.com/nuutila94finding.html */ void visit(SingleNode v) { root[v.index] = v; visited[v.index] = ++visitIndex; singleNodes[v.index] = v; stack.push(v); for (SingleNode w : v.followingNodes) { if (visited[w.index] == 0) visit(w); if (particleNodes[w.index] == null) root[v.index] = firstVisited(root[v.index], root[w.index]); } if (root[v.index] == v) { SingleNode w = stack.pop(); ParticleNode pn = new ParticleNode(nParticles++); pn.particle = makeParticle(w.name); particleNodes[w.index] = pn; if (w != v) { do { w = stack.pop(); particleNodes[w.index] = pn; pn.particle = new ChoiceParticle(makeParticle(w.name), pn.particle); } while (w != v); pn.particle = new OneOrMoreParticle(pn.particle); } else { if (w.repeated) pn.particle = new OneOrMoreParticle(pn.particle); } } } SingleNode firstVisited(SingleNode n1, SingleNode n2) { return visited[n1.index] < visited[n2.index] ? n1 : n2; } } private static class ParticleBuilder { private final int[] rank; private int currentRank = 0; private Particle rankParticleChoice; private Particle followParticle; /** * Sum of the refCounts of the nodes in the ranks (not necessarily immediately) following the current rank. */ int followRanksTotalRefCount = 0; /** * Sum of the refCounts of the nodes in the current rank. */ int currentRankTotalRefCount = 0; /** * Number of references that are from nodes in the current or following ranks. */ int totalCoveredRefCount = 0; ParticleBuilder(int nNodes) { rank = new int[nNodes]; } Particle build(ParticleNode start) { visit(start); if (followParticle == null) followParticle = new EmptyParticle(); return followParticle; } void visit(ParticleNode node) { int maxRank = 0; for (ParticleNode follow : node.followingNodes) { if (rank[follow.index] == 0) visit(follow); maxRank = Math.max(maxRank, rank[follow.index]); } int nodeRank = maxRank + 1; rank[node.index] = nodeRank; if (nodeRank == currentRank) { rankParticleChoice = new ChoiceParticle(rankParticleChoice, node.particle); currentRankTotalRefCount += node.refCount; } else { if (totalCoveredRefCount != followRanksTotalRefCount) rankParticleChoice = new ChoiceParticle(rankParticleChoice, new EmptyParticle()); if (followParticle == null) followParticle = rankParticleChoice; else followParticle = new SequenceParticle(rankParticleChoice, followParticle); followRanksTotalRefCount += currentRankTotalRefCount; rankParticleChoice = node.particle; currentRankTotalRefCount = node.refCount; currentRank = nodeRank; } totalCoveredRefCount += node.followingNodes.size(); } } private static class ParticleMerger { private final boolean[] done; private ParticleMerger(int nNodes) { this.done = new boolean[nNodes]; } void merge(ParticleNode node) { if (done[node.index]) return; done[node.index] = true; if (node.particle != null) { while (node.followingNodes.size() == 1) { ParticleNode follower = node.followingNodes.iterator().next(); if (follower.refCount != 1 || follower.particle == null) break; node.particle = new SequenceParticle(node.particle, follower.particle); node.followingNodes = follower.followingNodes; } } for (ParticleNode follower : node.followingNodes) merge(follower); } } ContentModelInferrerImpl() { startNode = lookup(START); endNode = lookup(END); prevNode = startNode; } public void addElement(Name elementName) { SingleNode node = lookup(elementName); if (node == prevNode) prevNode.repeated = true; else { prevNode.followingNodes.add(node); prevNode = node; } } public void endSequence() { prevNode.followingNodes.add(endNode); prevNode = startNode; } private SingleNode lookup(Name name) { SingleNode node = nameMap.get(name); if (node == null) { node = new SingleNode(name, nameMap.size()); nameMap.put(name, node); } return node; } public Particle inferContentModel() { if (startNode.followingNodes.size() == 0 || prevNode != startNode) throw new IllegalStateException(); ParticleNode start = new StronglyConnectedComponentsFinder(nameMap.size()).makeDag(lookup(START)); int nNodes = start.index + 1; new ParticleMerger(nNodes).merge(start); return new ParticleBuilder(nNodes).build(start); } private static Particle makeParticle(Name name) { if (name == START || name == END) return null; return new ElementParticle(name); } public Set getElementNames() { Set elementNames = new HashSet(); elementNames.addAll(nameMap.keySet()); elementNames.remove(START); elementNames.remove(END); return elementNames; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/DatatypeInferrer.java000066400000000000000000000032411225366607500323150ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; class DatatypeInferrer { private final DatatypeRepertoire.Type[] possibleTypes; private int nTypes; private int typicalMask = 0; private final String uri; private boolean allWhiteSpace = true; DatatypeInferrer(DatatypeRepertoire datatypes, String value) { uri = DatatypeRepertoire.getUri(); possibleTypes = new DatatypeRepertoire.Type[datatypes.size()]; for (int i = 0; i < possibleTypes.length; i++) possibleTypes[i] = datatypes.get(i); nTypes = possibleTypes.length; addValue(value); } public void addValue(String value) { int nDeleted = 0; for (int i = 0; i < nTypes; i++) { if (!possibleTypes[i].matches(value)) nDeleted++; else { if (possibleTypes[i].isTypical(value)) typicalMask |= 1 << possibleTypes[i].getIndex(); if (nDeleted > 0) { possibleTypes[i - nDeleted] = possibleTypes[i]; possibleTypes[i] = null; } } } nTypes -= nDeleted; if (!isWhiteSpace(value)) allWhiteSpace = false; } static boolean isWhiteSpace(String value) { for (int i = 0; i < value.length(); i++) switch (value.charAt(i)) { case ' ': case '\t': case '\n': case '\r': break; default: return false; } return true; } public Name getTypeName() { for (int i = 0; i < nTypes; i++) if (((1 << possibleTypes[i].getIndex()) & typicalMask) != 0) return new Name(uri, possibleTypes[i].getName()); return null; } public boolean isAllWhiteSpace() { return allWhiteSpace; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/DatatypeRepertoire.java000066400000000000000000000101261225366607500326610ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeLibraryFactory; import com.thaiopensource.util.Uri; import com.thaiopensource.xml.util.WellKnownNamespaces; public class DatatypeRepertoire { static private final int TOKEN_TYPICAL_MAX_LENGTH = 32; static private final int BINARY_TYPICAL_MIN_LENGTH = 128; static private final String[] typeNames = { "boolean", // XXX add int? "integer", "decimal", "double", "NCName", "time", "date", "dateTime", "duration", "hexBinary", "NMTOKEN", "base64Binary", "anyURI" }; static public class Type { private final Datatype dt; private final String name; private final int index; private Type(Datatype dt, String name, int index) { this.dt = dt; this.name = name; this.index = index; } public boolean matches(String value) { return dt.isValid(value, null); } public boolean isTypical(String value) { return value.length() < TOKEN_TYPICAL_MAX_LENGTH; } public String getName() { return name; } public int getIndex() { return index; } } static private class BinaryType extends Type { private BinaryType(Datatype dt, String name, int index) { super(dt, name, index); } public boolean isTypical(String value) { return value.length() > BINARY_TYPICAL_MIN_LENGTH; } } static private class UriType extends Type { private UriType(Datatype dt, String name, int index) { super(dt, name, index); } public boolean isTypical(String value) { return Uri.isAbsolute(value) && !containsEmbeddedWhitespace(value) && !containsExcluded(value); } static private final String EXCLUDED = "<>\"{}|\\^`"; private static boolean containsExcluded(String value) { for (int i = 0; i < EXCLUDED.length(); i++) if (value.indexOf(EXCLUDED.charAt(i)) >= 0) return true; return false; } // anyURI is derived from token so there's nothing wrong with leading and trailing whitespace private static boolean containsEmbeddedWhitespace(String value) { int state = 0; for (int i = 0, len = value.length(); i < len; i++) switch (value.charAt(i)) { case ' ': case '\t': case '\r': case '\n': if (state == 1) state = 2; break; default: if (state == 2) return true; if (state == 0) state = 1; break; } return false; } } static private class BooleanType extends Type { private BooleanType(Datatype dt, String name, int index) { super(dt, name, index); } public boolean isTypical(String value) { value = value.trim(); return value.equals("true") || value.equals("false"); } } private final Type[] types = new Type[typeNames.length]; private int nTypes = 0; DatatypeRepertoire(DatatypeLibraryFactory factory) { DatatypeLibrary lib = factory.createDatatypeLibrary(WellKnownNamespaces.XML_SCHEMA_DATATYPES); if (lib == null) return; for (int i = 0; i < types.length; i++) { try { types[nTypes] = makeType(typeNames[i], lib.createDatatype(typeNames[i]), i); nTypes++; } catch (DatatypeException e) { } } } public int size() { return nTypes; } Type get(int i) { return types[i]; } static private Type makeType(String typeName, Datatype dt, int index) { if (typeName.equals("anyURI")) return new UriType(dt, typeName, index); if (typeName.equals("boolean")) return new BooleanType(dt, typeName, index); if (typeName.equals("base64Binary") || typeName.equals("hexBinary")) return new BinaryType(dt, typeName, index); return new Type(dt, typeName, index); } public static String getUri() { return WellKnownNamespaces.XML_SCHEMA_DATATYPES; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ElementDecl.java000066400000000000000000000013651225366607500312330ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import java.util.Map; import java.util.HashMap; public class ElementDecl { private Particle contentModel; private Name datatype; private final Map attributeDecls = new HashMap(); public Map getAttributeDecls() { return attributeDecls; } public Particle getContentModel() { return contentModel; } public void setContentModel(Particle contentModel) { this.datatype = null; this.contentModel = contentModel; } public Name getDatatype() { return datatype; } public void setDatatype(Name datatype) { this.contentModel = null; this.datatype = datatype; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ElementDeclInferrer.java000066400000000000000000000073361225366607500327340ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; class ElementDeclInferrer { private final DatatypeRepertoire datatypes; private ContentModelInferrer contentModelInferrer; private final Map attributeTypeMap = new HashMap(); private DatatypeInferrer valueInferrer; private final Set requiredAttributeNames = new HashSet(); private Set mixedContentNames = null; ElementDeclInferrer(DatatypeRepertoire datatypes, List attributeNames) { this.datatypes = datatypes; requiredAttributeNames.addAll(attributeNames); } ElementDecl infer() { ElementDecl decl = new ElementDecl(); for (Map.Entry entry : attributeTypeMap.entrySet()) { decl.getAttributeDecls().put(entry.getKey(), new AttributeDecl((entry.getValue()).getTypeName(), !requiredAttributeNames.contains(entry.getKey()))); } if (contentModelInferrer != null) decl.setContentModel(contentModelInferrer.inferContentModel()); else if (mixedContentNames != null) decl.setContentModel(makeMixedContentModel()); else { if (valueInferrer.isAllWhiteSpace()) decl.setContentModel(new EmptyParticle()); else { Name typeName = valueInferrer.getTypeName(); if (typeName == null) decl.setContentModel(new TextParticle()); else decl.setDatatype(typeName); } } return decl; } private Particle makeMixedContentModel() { Particle p = new TextParticle(); for (Name name : mixedContentNames) p = new ChoiceParticle(p, new ElementParticle(name)); return new OneOrMoreParticle(p); } boolean wantValue() { return contentModelInferrer == null && mixedContentNames == null; } void addElement(Name elementName) { if (valueInferrer != null) { if (valueInferrer.isAllWhiteSpace()) { if (contentModelInferrer == null) contentModelInferrer = ContentModelInferrer.createContentModelInferrer(); // Previously had all elements contained only white space. // Equivalent to an empty content model. contentModelInferrer.endSequence(); valueInferrer = null; } else useMixedContent(); } if (mixedContentNames != null) mixedContentNames.add(elementName); else { if (contentModelInferrer == null) contentModelInferrer = ContentModelInferrer.createContentModelInferrer(); contentModelInferrer.addElement(elementName); } } void endSequence() { if (contentModelInferrer != null) contentModelInferrer.endSequence(); } void addValue(String value) { if (valueInferrer == null) valueInferrer = new DatatypeInferrer(datatypes, value); else valueInferrer.addValue(value); } void addText() { useMixedContent(); } private void useMixedContent() { if (mixedContentNames == null) { mixedContentNames = new HashSet(); if (contentModelInferrer != null) { mixedContentNames.addAll(contentModelInferrer.getElementNames()); contentModelInferrer = null; } valueInferrer = null; } } void addAttributeNames(List attributeNames) { requiredAttributeNames.retainAll(attributeNames); } void addAttributeValue(Name name, String value) { DatatypeInferrer dt = attributeTypeMap.get(name); if (dt == null) { dt = new DatatypeInferrer(datatypes, value); attributeTypeMap.put(name, dt); } else dt.addValue(value); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ElementParticle.java000066400000000000000000000005561225366607500321300ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; public class ElementParticle extends Particle { private final Name name; public ElementParticle(Name name) { this.name = name; } public Name getName() { return name; } public Object accept(ParticleVisitor visitor) { return visitor.visitElement(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/EmptyParticle.java000066400000000000000000000002621225366607500316270ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public class EmptyParticle extends Particle { public Object accept(ParticleVisitor visitor) { return visitor.visitEmpty(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/InferHandler.java000066400000000000000000000105521225366607500314110ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; public class InferHandler extends DefaultHandler { private final Map inferrerMap = new HashMap(); private OpenElement openElement = null; private final Set startSet = new HashSet(); private final List attributeNames = new Vector(); private final DatatypeRepertoire datatypes; private final StringBuffer textBuffer = new StringBuffer(); private final Set usedNamespaceUris = new HashSet(); private final Schema schema = new Schema(); private final Set assignedPrefixes = new HashSet(); private static class OpenElement { final OpenElement parent; final ElementDeclInferrer inferrer; public OpenElement(OpenElement parent, ElementDeclInferrer inferrer) { this.parent = parent; this.inferrer = inferrer; } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { Name name = makeName(uri, localName); if (openElement == null) startSet.add(name); else { if (textBuffer.length() > 0) { if (!DatatypeInferrer.isWhiteSpace(textBuffer.toString())) openElement.inferrer.addText(); textBuffer.setLength(0); } openElement.inferrer.addElement(name); } for (int i = 0, len = attributes.getLength(); i < len; i++) attributeNames.add(makeName(attributes.getURI(i), attributes.getLocalName(i))); ElementDeclInferrer inferrer = inferrerMap.get(name); if (inferrer == null) { inferrer = new ElementDeclInferrer(datatypes, attributeNames); inferrerMap.put(name, inferrer); } else inferrer.addAttributeNames(attributeNames); for (int i = 0, len = attributes.getLength(); i < len; i++) inferrer.addAttributeValue(attributeNames.get(i), attributes.getValue(i)); attributeNames.clear(); openElement = new OpenElement(openElement, inferrer); } public void startPrefixMapping(String prefix, String uri) throws SAXException { if (prefix != null && !prefix.equals("") && schema.getPrefixMap().get(uri) == null && !assignedPrefixes.contains(prefix)) { assignedPrefixes.add(prefix); schema.getPrefixMap().put(uri, prefix); } } private Name makeName(String uri, String localName) { if (!uri.equals("")) usedNamespaceUris.add(uri); return new Name(uri, localName); } public void characters(char ch[], int start, int length) throws SAXException { if (openElement.inferrer.wantValue()) textBuffer.append(ch, start, length); else { for (int i = 0; i < length; i++) switch (ch[start + i]) { case ' ': case '\t': case '\n': case '\r': break; default: openElement.inferrer.addText(); return; } } } public void endElement(String uri, String localName, String qName) throws SAXException { if (openElement.inferrer.wantValue()) { openElement.inferrer.addValue(textBuffer.toString()); textBuffer.setLength(0); } else openElement.inferrer.endSequence(); openElement = openElement.parent; } public Schema getSchema() { for (Map.Entry entry : inferrerMap.entrySet()) { ElementDecl decl = (entry.getValue()).infer(); Name name = entry.getKey(); schema.getElementDecls().put(name, decl); } schema.setStart(makeStart()); schema.getPrefixMap().keySet().retainAll(usedNamespaceUris); return schema; } private Particle makeStart() { Particle start = null; for (Name name : startSet) { Particle tem = new ElementParticle(name); if (start == null) start = tem; else start = new ChoiceParticle(start, tem); } return start; } public InferHandler(DatatypeLibraryFactory factory) { this.datatypes = new DatatypeRepertoire(factory); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/OneOrMoreParticle.java000066400000000000000000000005331225366607500323770ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public class OneOrMoreParticle extends Particle { private final Particle child; public OneOrMoreParticle(Particle child) { this.child = child; } public Particle getChild() { return child; } public Object accept(ParticleVisitor visitor) { return visitor.visitOneOrMore(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/Particle.java000066400000000000000000000002041225366607500306040ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public abstract class Particle { public abstract Object accept(ParticleVisitor visitor); } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ParticleDumper.java000066400000000000000000000041711225366607500317700ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; public class ParticleDumper implements ParticleVisitor { final private String defaultNamespace; private ParticleDumper(String defaultNamespace) { this.defaultNamespace = defaultNamespace; } public static String toString(Particle p, String defaultNamespace) { return new ParticleDumper(defaultNamespace).convert(p); } private String convert(Particle p) { return (String)p.accept(this); } public Object visitElement(ElementParticle p) { Name name = p.getName(); String ns = name.getNamespaceUri(); if (ns.equals(defaultNamespace)) return name.getLocalName(); return "{" + name.getNamespaceUri() + "}" + name.getLocalName(); } public Object visitChoice(ChoiceParticle p) { StringBuffer buf = new StringBuffer(); buf.append("("); convertForChoice(p, buf); buf.append(")"); return buf.toString(); } private void convertForChoice(Particle p, StringBuffer buf) { if (p instanceof ChoiceParticle) convertForChoice((ChoiceParticle)p, buf); else buf.append(convert(p)); } private void convertForChoice(ChoiceParticle cp, StringBuffer buf) { convertForChoice(cp.getChild1(), buf); buf.append('|'); convertForChoice(cp.getChild2(), buf); } public Object visitSequence(SequenceParticle p) { StringBuffer buf = new StringBuffer(); buf.append("("); convertForSequence(p, buf); buf.append(")"); return buf.toString(); } private void convertForSequence(Particle p, StringBuffer buf) { if (p instanceof SequenceParticle) convertForSequence((SequenceParticle)p, buf); else buf.append(convert(p)); } private void convertForSequence(SequenceParticle sp, StringBuffer buf) { convertForSequence(sp.getChild1(), buf); buf.append(','); convertForSequence(sp.getChild2(), buf); } public Object visitEmpty(EmptyParticle p) { return "#empty"; } public Object visitText(TextParticle p) { return "#text"; } public Object visitOneOrMore(OneOrMoreParticle p) { return convert(p.getChild()) + "+"; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/ParticleVisitor.java000066400000000000000000000005021225366607500321650ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public interface ParticleVisitor { Object visitElement(ElementParticle p); Object visitChoice(ChoiceParticle p); Object visitSequence(SequenceParticle p); Object visitEmpty(EmptyParticle p); Object visitText(TextParticle p); Object visitOneOrMore(OneOrMoreParticle p); } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/Schema.java000066400000000000000000000013131225366607500302430ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.xml.util.Name; import java.util.Map; import java.util.HashMap; public class Schema { private final Map elementDecls = new HashMap(); private Particle start; private final Map prefixMap = new HashMap(); public Map getElementDecls() { return elementDecls; } public Map getPrefixMap() { return prefixMap; } public ElementDecl getElementDecl(Name name) { return elementDecls.get(name); } public Particle getStart() { return start; } public void setStart(Particle start) { this.start = start; } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/SequenceParticle.java000066400000000000000000000004141225366607500323000ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public class SequenceParticle extends BinaryParticle { public SequenceParticle(Particle p1, Particle p2) { super(p1, p2); } public Object accept(ParticleVisitor visitor) { return visitor.visitSequence(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/TestDriver.java000066400000000000000000000041451225366607500311440ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.UriOrFile; import com.thaiopensource.xml.util.Name; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import java.io.IOException; import java.util.Map; public class TestDriver { static public void main(String[] args) throws SAXException, IOException { InferHandler handler = new InferHandler(new DatatypeLibraryLoader()); SAXResolver resolver = new SAXResolver(); XMLReader xr = resolver.createXMLReader(); xr.setContentHandler(handler); for (int i = 0; i < args.length; i++) xr.parse(new InputSource(UriOrFile.toUri(args[i]))); Schema schema = handler.getSchema(); for (Map.Entry entry : schema.getElementDecls().entrySet()) { Name name = entry.getKey(); String ns = name.getNamespaceUri(); if (!ns.equals("")) System.out.print("{" + ns + "}"); System.out.print(name.getLocalName()); System.out.print(" = "); ElementDecl elementDecl = entry.getValue(); Particle particle = elementDecl.getContentModel(); if (particle != null) System.out.println(ParticleDumper.toString(particle, ns)); else System.out.println("xsd:" + elementDecl.getDatatype().getLocalName()); for (Map.Entry attEntry : elementDecl.getAttributeDecls().entrySet()) { System.out.print(" @"); AttributeDecl att = attEntry.getValue(); Name attName = attEntry.getKey(); ns = attName.getNamespaceUri(); if (!ns.equals("")) System.out.print("{" + ns + "}"); System.out.print(attName.getLocalName()); Name typeName = att.getDatatype(); if (typeName == null) System.out.print(" string"); else System.out.print(" xsd:" + typeName.getLocalName()); if (att.isOptional()) System.out.println(" optional"); else System.out.println(" required"); } } } } jing-trang-20131210+dfsg+1/mod/infer/src/main/com/thaiopensource/xml/infer/TextParticle.java000066400000000000000000000002601225366607500314530ustar00rootroot00000000000000package com.thaiopensource.xml.infer; public class TextParticle extends Particle { public Object accept(ParticleVisitor visitor) { return visitor.visitText(this); } } jing-trang-20131210+dfsg+1/mod/infer/src/test/000077500000000000000000000000001225366607500205245ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/test/com/000077500000000000000000000000001225366607500213025ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/test/com/thaiopensource/000077500000000000000000000000001225366607500243325ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/test/com/thaiopensource/xml/000077500000000000000000000000001225366607500251325ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/test/com/thaiopensource/xml/infer/000077500000000000000000000000001225366607500262355ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/infer/src/test/com/thaiopensource/xml/infer/TestInferHandler.java000066400000000000000000000122461225366607500323060ustar00rootroot00000000000000package com.thaiopensource.xml.infer; import java.io.IOException; import java.io.StringReader; import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import com.thaiopensource.datatype.xsd.DatatypeLibraryFactoryImpl; import com.thaiopensource.datatype.xsd.regex.java.RegexEngineImpl; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.util.Name; /** * Test the inference handler */ public class TestInferHandler { @DataProvider(name = "samples") public Object[][] createDateSamples() { return new Object[][] { { "\n" + " \n" + " \n" + " \n" + "", "boolean" }, { "\n" + " \n" + " \n" + " \n" + "", "integer" }, { "\n" + " \n" + " \n" + " \n" + "", "decimal" }, { "\n" + " \n" + " \n" + " \n" + "", "double" }, { "\n" + " \n" + " \n" + " \n" + "", "NCName" }, { "\n" + " \n" + " \n" + " \n" + "", "time" }, { "\n" + " \n" + " \n" + " \n" + "", "date" }, { "\n" + " \n" + " \n" + " \n" + "", "dateTime" }, { "\n" + " \n" + " \n" + " \n" + "", "duration" }, { "\n" + " \n" + " \n" + " \n" + "", "hexBinary" }, { "\n" + " \n" + " \n" + " \n" + "", "NMTOKEN" }, { "\n" + " \n" + " \n" + " \n" + "", "base64Binary" }, { "\n" + " \n" + " \n" + " \n" + "", "anyURI" } }; } @Test(dataProvider = "samples") public void testTypeInferenceForAttribute(String xmlSource, String type) throws SAXException, IOException { InferHandler handler = new InferHandler(new DatatypeLibraryFactoryImpl(new RegexEngineImpl())); SAXResolver resolver = new SAXResolver(); XMLReader xr = resolver.createXMLReader(); xr.setContentHandler(handler); xr.parse(new InputSource(new StringReader(xmlSource))); Schema schema = handler.getSchema(); for (Map.Entry entry : schema.getElementDecls() .entrySet()) { Name name = entry.getKey(); ElementDecl elementDecl = entry.getValue(); if ("element".equals(name.getLocalName())) { for (Map.Entry attEntry : elementDecl.getAttributeDecls().entrySet()) { AttributeDecl att = attEntry.getValue(); Name attName = attEntry.getKey(); if ("att".equals(attName.getLocalName())) { Name typeName = att.getDatatype(); Assert.assertEquals(typeName.getLocalName(), type); } } } } } }jing-trang-20131210+dfsg+1/mod/jaxp/000077500000000000000000000000001225366607500166155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/mod.xml000066400000000000000000000001331225366607500201130ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/jaxp/src/000077500000000000000000000000001225366607500174045ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/src/main/000077500000000000000000000000001225366607500203305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/000077500000000000000000000000001225366607500211065ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/000077500000000000000000000000001225366607500241365ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/000077500000000000000000000000001225366607500262705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/Constants.java000066400000000000000000000013561225366607500311140ustar00rootroot00000000000000package com.thaiopensource.validation; import javax.xml.XMLConstants; /** * Some useful constants for the names of schema languages. */ public class Constants { private Constants() { } /** * URI representating the Relax NG Compact Syntax schema language. * @see javax.xml.validation.SchemaFactory#newInstance(String) */ static public final String RELAXNG_COMPACT_URI = "http://www.iana.org/assignments/media-types/application/relax-ng-compact-syntax"; /** * URI representating the Relax NG XML Syntax schema language. * Identical to XMLConstants#RELAXNG_NS_URI * @see javax.xml.validation.SchemaFactory#newInstance(String) */ static public final String RELAXNG_XML_URI = XMLConstants.RELAXNG_NS_URI; } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/LSInputImpl.java000066400000000000000000000032371225366607500313200ustar00rootroot00000000000000package com.thaiopensource.validation; import org.w3c.dom.ls.LSInput; import java.io.InputStream; import java.io.Reader; /** * A straightforward default implementation of LSInput. * @see LSInput */ public class LSInputImpl implements LSInput { private Reader characterStream; private InputStream byteStream; private String systemId; private String publicId; private String baseURI; private String encoding; private boolean certifiedText; private String stringData; public Reader getCharacterStream() { return characterStream; } public void setCharacterStream(Reader characterStream) { this.characterStream = characterStream; } public InputStream getByteStream() { return byteStream; } public void setByteStream(InputStream byteStream) { this.byteStream = byteStream; } 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; } public String getStringData() { return stringData; } public void setStringData(String stringData) { this.stringData = stringData; } } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/Schema2.java000066400000000000000000000011621225366607500304150ustar00rootroot00000000000000package com.thaiopensource.validation; import javax.xml.validation.Schema; /** * An extension to the Schema abstract class. The main difference is that * there is a default implementation of newValidator in terms of newValidatorHandler. * Also both newValidator and newValidatorHandler return the extended versions * of Validator and ValidatorHandler (using covariant return types). */ public abstract class Schema2 extends Schema { protected Schema2() { } public Validator2 newValidator() { return new ValidatorImpl(newValidatorHandler()); } public abstract ValidatorHandler2 newValidatorHandler(); } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/SchemaFactory2.java000066400000000000000000000076311225366607500317540ustar00rootroot00000000000000package com.thaiopensource.validation; import org.xml.sax.SAXException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.InputSource; import org.w3c.dom.ls.LSResourceResolver; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.SchemaFactory; import javax.xml.XMLConstants; import java.io.File; import java.net.URL; /** * Extends the SchemaFactory abstract class. All methods of SchemaFactory * that return a Schema are overridden to return a Schema2. Default implementations * of several methods are provided. * @see SchemaFactory */ public abstract class SchemaFactory2 extends SchemaFactory { // Corresponds to XMLConstants.FEATURE_SECURE_PROCESSING. private boolean secureProcessing = false; private ErrorHandler errorHandler = null; private LSResourceResolver resourceResolver = null; /** * Create a new Schema from a SAXSource. Subclasses must implement this. * @see SchemaFactory#newSchema(Source) */ public abstract Schema2 newSchema(SAXSource schema) throws SAXException; public Schema2 newSchema(Source[] schemas) throws SAXException { if (schemas.length != 1) throw new UnsupportedOperationException(); return newSchema(schemas[0]); } /** * This implementation of SchemaFactory#newSchema simply throws UnsupportedOperationException. * @see SchemaFactory#newSchema */ public Schema2 newSchema() throws SAXException { throw new UnsupportedOperationException(); } public Schema2 newSchema(Source source) throws SAXException { if (source == null) throw new NullPointerException(); if (source instanceof SAXSource) return newSchema((SAXSource)source); InputSource inputSource = SAXSource.sourceToInputSource(source); // XXX support other types of Source for the schema if (inputSource == null) throw new IllegalArgumentException("unsupported type of Source for schema"); return newSchema(new SAXSource(inputSource)); } public Schema2 newSchema(File schema) throws SAXException { return newSchema(new StreamSource(schema)); } public Schema2 newSchema(URL schema) throws SAXException { return newSchema(new StreamSource(schema.toExternalForm())); } public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } public ErrorHandler getErrorHandler() { return errorHandler; } public void setResourceResolver(LSResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } public LSResourceResolver getResourceResolver() { return resourceResolver; } /** * Extends SchemaFactory.setFeature by implementing the secure processing feature. * The implementation simply sets an internal flag, which can be accessed using * getSecureProcessing. * @see SchemaFactory#setFeature * @see #getSecureProcessing */ public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) secureProcessing = value; else super.setFeature(name, value); } /** * Extends SchemaFactory.setFeature by implementing the secure processing feature. * The implementation simply sets an internal flag, which can be accessed using * getSecureProcessing. * @see SchemaFactory#getFeature * @see #getSecureProcessing */ public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) return secureProcessing; return super.getFeature(name); } public void setSecureProcessing(boolean secureProcessing) { this.secureProcessing = secureProcessing; } public boolean getSecureProcessing() { return secureProcessing; } } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/Validator2.java000066400000000000000000000014011225366607500311360ustar00rootroot00000000000000package com.thaiopensource.validation; import org.xml.sax.SAXException; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Validator; import java.io.File; import java.io.IOException; import java.net.URL; /** * Adds some convenience methods to Validator. */ abstract public class Validator2 extends Validator { protected Validator2() { } /** * Validate a file. * @param file the file to validate; must not be null. */ public void validate(File file) throws SAXException, IOException { validate(new StreamSource(file)); } /** * Validate a URL. * @param url the URL to validate */ public void validate(URL url) throws SAXException, IOException { validate(new StreamSource(url.toExternalForm())); } } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/ValidatorHandler2.java000066400000000000000000000014321225366607500324400ustar00rootroot00000000000000package com.thaiopensource.validation; import org.xml.sax.DTDHandler; import javax.xml.validation.ValidatorHandler; /** * Extension to ValidatorHandler. This implements DTDHandler because some schema language * datatypes need to know whether a name is the name of a notation or an unparsed entity. * It also provides a reset() method. */ public abstract class ValidatorHandler2 extends ValidatorHandler implements DTDHandler { abstract public void reset(); /** * Sets the DTD handler that receives the validation result. * @param dtdHandler the DTD hanlder */ abstract public void setDTDHandler(DTDHandler dtdHandler); /** * Gets the DTD handler that receives the validation result. * @return the DTDHandler */ abstract public DTDHandler getDTDHandler(); } jing-trang-20131210+dfsg+1/mod/jaxp/src/main/com/thaiopensource/validation/ValidatorImpl.java000066400000000000000000000157531225366607500317150ustar00rootroot00000000000000package com.thaiopensource.validation; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.xml.ls.LS; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.sax.DraconianErrorHandler; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.ErrorHandler; 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.LexicalHandler; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.IOException; /** * Implements Validator2 in terms of ValidatorHandler2. */ class ValidatorImpl extends Validator2 { private final ValidatorHandler2 handler; private XMLReader cachedXMLReader = null; private LSResourceResolver cachedResourceResolver = null; private boolean needReset = false; private static final String LEXICAL_HANDLER_PROPERTY = "http://xml.org/sax/properties/lexical-handler"; public ValidatorImpl(ValidatorHandler2 handler) { this.handler = handler; } public void reset() { handler.reset(); needReset = false; // XXX not sure if we should do this handler.setErrorHandler(null); handler.setResourceResolver(null); } public void validate(Source source, Result result) throws SAXException, IOException { if (source == null) throw new NullPointerException(); try { if (source instanceof SAXSource) { if (result != null && !(result instanceof SAXResult)) throw new IllegalArgumentException(); doValidate((SAXSource)source, result); } else if (source instanceof StreamSource) { if (result != null && !(result instanceof StreamResult)) throw new IllegalArgumentException(); doValidate(new SAXSource(SAXSource.sourceToInputSource(source)), result); } else if (source instanceof DOMSource) { if (result != null && !(result instanceof DOMResult)) throw new IllegalArgumentException(); doValidate((DOMSource)source, (DOMResult)result); } // else if (source instanceof StAXSource) { // if (result != null && !(result instanceof StAXResult)) // throw new IllegalArgumentException(); // doValidate((StAXSource)source, (StAXResult)result); // } else throw new IllegalArgumentException("unsupported type of Source: " + source.getClass().getName()); } catch (TransformerException e) { // XXX unwrap if possible throw new SAXException(e); } } // private void doValidate(StAXSource source, StAXResult result) // throws SAXException, IOException, TransformerException { // // XXX transform source and result // throw new IllegalArgumentException(); // } private void doValidate(DOMSource source, DOMResult result) throws SAXException, IOException, TransformerException { // XXX transform source and result throw new IllegalArgumentException(); } private TransformerHandler getIdentityTransformerHandler() throws SAXException, TransformerConfigurationException { TransformerFactory transformerFactory = TransformerFactory.newInstance(); if (!transformerFactory.getFeature(SAXTransformerFactory.FEATURE)) throw new SAXException("TransformerFactory must implement SAXTransformerFactory"); return ((SAXTransformerFactory)transformerFactory).newTransformerHandler(); } private void doValidate(SAXSource source, Result result) throws SAXException, IOException, TransformerConfigurationException { if (result == null) doValidate(source, null, null, null); else if (result instanceof SAXResult) { SAXResult saxResult = (SAXResult)result; doValidate(source, saxResult.getHandler(), saxResult.getLexicalHandler(), null); } else { TransformerHandler identityHandler = getIdentityTransformerHandler(); identityHandler.setResult(result); doValidate(source, identityHandler, identityHandler, identityHandler); } } private void doValidate(SAXSource source, ContentHandler contentHandler, LexicalHandler lexicalHandler, DTDHandler dtdHandler) throws SAXException, IOException { XMLReader xr = source.getXMLReader(); if (xr == null) { LSResourceResolver resourceResolver = handler.getResourceResolver(); if (cachedXMLReader != null && cachedResourceResolver == resourceResolver) xr = cachedXMLReader; else { Resolver resolver = null; if (resourceResolver != null) resolver = LS.createResolver(resourceResolver); xr = new SAXResolver(resolver).createXMLReader(); cachedXMLReader = xr; cachedResourceResolver = resourceResolver; } } handler.setContentHandler(contentHandler); handler.setDTDHandler(dtdHandler); // always set the lexical handler to avoid problems when reusing the XMLReader try { xr.setProperty(LEXICAL_HANDLER_PROPERTY, lexicalHandler); } catch (SAXNotRecognizedException e) { // ignore it } catch (SAXNotSupportedException e) { // ignore it } xr.setContentHandler(handler); xr.setDTDHandler(handler); ErrorHandler eh = handler.getErrorHandler(); if (eh == null) eh = new DraconianErrorHandler(); xr.setErrorHandler(eh); if (needReset) handler.reset(); else needReset = true; xr.parse(source.getInputSource()); } public void setErrorHandler(ErrorHandler errorHandler) { handler.setErrorHandler(errorHandler); } public ErrorHandler getErrorHandler() { return handler.getErrorHandler(); } public void setResourceResolver(LSResourceResolver resourceResolver) { handler.setResourceResolver(resourceResolver); } public LSResourceResolver getResourceResolver() { return handler.getResourceResolver(); } public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { return handler.getFeature(name); } public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { handler.setFeature(name, value); } public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException { handler.setProperty(name, object); } public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { return handler.getProperty(name); } } jing-trang-20131210+dfsg+1/mod/jing/000077500000000000000000000000001225366607500166025ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/jing/mod.xml000066400000000000000000000025031225366607500201030ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/nvdl/000077500000000000000000000000001225366607500166165ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/mns-todo.txt000066400000000000000000000002701225366607500211160ustar00rootroot00000000000000ID/IDREF testing. Support an element. Might have a checker specific to a particular namespace (eg RDF, XSLT, HTML). What to do about DTD information (unparsed entities)? jing-trang-20131210+dfsg+1/mod/nvdl/mod.xml000066400000000000000000000012741225366607500201230ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/nvdl/nrl-todo.txt000066400000000000000000000006151225366607500211170ustar00rootroot00000000000000Support inline schemas. Need to pass unparsed entities to sub schemas. Test option handling Handle possibility of multiple different validation processes using same schema. reject messages should specify mode Allow to specify name for schema; use that name in error messages. Allow namespace and anyNamespace nested in actions, with the effect that they create an anonymous mode. jing-trang-20131210+dfsg+1/mod/nvdl/src/000077500000000000000000000000001225366607500174055ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/000077500000000000000000000000001225366607500203315ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/000077500000000000000000000000001225366607500211075ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/000077500000000000000000000000001225366607500241375ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/000077500000000000000000000000001225366607500257305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/000077500000000000000000000000001225366607500265255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/ContextMap.java000066400000000000000000000027421225366607500314570ustar00rootroot00000000000000package com.thaiopensource.validate.mns; import com.thaiopensource.xml.util.Name; import java.util.Vector; import java.util.Hashtable; class ContextMap { private Object rootValue; private Object otherValue; private final Hashtable nameTable = new Hashtable(); Object get(Vector context) { return get(context, context.size()); } boolean put(boolean isRoot, Vector names, Object value) { return put(isRoot, names, names.size(), value); } private Object get(Vector context, int len) { if (len > 0) { ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1)); if (nestedMap != null) { Object value = nestedMap.get(context, len - 1); if (value != null) return value; } } if (rootValue != null && len == 0) return rootValue; return otherValue; } private boolean put(boolean isRoot, Vector names, int len, Object value) { if (len == 0) { if (isRoot) { if (rootValue != null) return false; rootValue = value; } else { if (otherValue != null) return false; otherValue = value; } return true; } else { Name name = (Name)names.elementAt(len - 1); ContextMap nestedMap = (ContextMap)nameTable.get(name); if (nestedMap == null) { nestedMap = new ContextMap(); nameTable.put(name, nestedMap); } return nestedMap.put(isRoot, names, len - 1, value); } } } ElementsOrAttributes.java000066400000000000000000000020621225366607500334350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mnspackage com.thaiopensource.validate.mns; class ElementsOrAttributes { private static final int ELEMENTS_FLAG = 01; private static final int ATTRIBUTES_FLAG = 02; static final ElementsOrAttributes NEITHER = new ElementsOrAttributes(0); static final ElementsOrAttributes ELEMENTS = new ElementsOrAttributes(ELEMENTS_FLAG); static final ElementsOrAttributes ATTRIBUTES = new ElementsOrAttributes(ATTRIBUTES_FLAG); static final ElementsOrAttributes BOTH = new ElementsOrAttributes(ELEMENTS_FLAG|ATTRIBUTES_FLAG); private static final ElementsOrAttributes values[] = { NEITHER, ELEMENTS, ATTRIBUTES, BOTH }; private int flags = 0; private ElementsOrAttributes(int flags) { this.flags = flags; } ElementsOrAttributes addElements() { return values[flags | ELEMENTS_FLAG]; } ElementsOrAttributes addAttributes() { return values[flags | ATTRIBUTES_FLAG]; } boolean containsAttributes() { return (flags & ATTRIBUTES_FLAG) != 0; } boolean containsElements() { return (flags & ELEMENTS_FLAG) != 0; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/Hashset.java000066400000000000000000000004651225366607500307740ustar00rootroot00000000000000package com.thaiopensource.validate.mns; import java.util.Hashtable; class Hashset { private final Hashtable table = new Hashtable(); boolean contains(Object key) { return table.get(key) != null; } void add(Object key) { table.put(key, key); } void clear() { table.clear(); } } MnsSchemaReceiverFactory.java000066400000000000000000000011261225366607500342040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mnspackage com.thaiopensource.validate.mns; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.Option; public class MnsSchemaReceiverFactory implements SchemaReceiverFactory { public SchemaReceiver createSchemaReceiver(String namespaceUri, PropertyMap properties) { if (!SchemaImpl.MNS_URI.equals(namespaceUri)) return null; return new SchemaReceiverImpl(properties); } public Option getOption(String uri) { return null; } } NamespaceFilteredAttributes.java000066400000000000000000000053651225366607500347440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mnspackage com.thaiopensource.validate.mns; import org.xml.sax.Attributes; class NamespaceFilteredAttributes implements Attributes { private final String ns; private final boolean keepLocal; private final Attributes attributes; private final int[] indexMap; private final int[] reverseIndexMap; public NamespaceFilteredAttributes(String ns, boolean keepLocal, Attributes attributes) { this.ns = ns; this.keepLocal = keepLocal; this.attributes = attributes; int n = 0; for (int i = 0, len = attributes.getLength(); i < len; i++) if (keepAttribute(attributes.getURI(i))) n++; indexMap = new int[n]; reverseIndexMap = new int[attributes.getLength()]; n = 0; for (int i = 0, len = attributes.getLength(); i < len; i++) { if (keepAttribute(attributes.getURI(i))) { reverseIndexMap[i] = n; indexMap[n++] = i; } else reverseIndexMap[i] = -1; } } private boolean keepAttribute(String uri) { return uri.equals(ns) || (keepLocal && uri.equals("")); } public int getLength() { return indexMap.length; } public String getURI(int index) { if (index < 0 || index >= indexMap.length) return null; return attributes.getURI(indexMap[index]); } public String getLocalName(int index) { if (index < 0 || index >= indexMap.length) return null; return attributes.getLocalName(indexMap[index]); } public String getQName(int index) { if (index < 0 || index >= indexMap.length) return null; return attributes.getQName(indexMap[index]); } public String getType(int index) { if (index < 0 || index >= indexMap.length) return null; return attributes.getType(indexMap[index]); } public String getValue(int index) { if (index < 0 || index >= indexMap.length) return null; return attributes.getValue(indexMap[index]); } public int getIndex(String uri, String localName) { int n = attributes.getIndex(uri, localName); if (n < 0) return n; return reverseIndexMap[n]; } public int getIndex(String qName) { int n = attributes.getIndex(qName); if (n < 0) return n; return reverseIndexMap[n]; } public String getType(String uri, String localName) { if (keepAttribute(uri)) return attributes.getType(uri, localName); return null; } public String getValue(String uri, String localName) { if (keepAttribute(uri)) return attributes.getValue(uri, localName); return null; } public String getType(String qName) { int i = getIndex(qName); if (i < 0) return null; return getType(i); } public String getValue(String qName) { int i = getIndex(qName); if (i < 0) return null; return getValue(i); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/SchemaImpl.java000066400000000000000000000361371225366607500314240ustar00rootroot00000000000000package com.thaiopensource.validate.mns; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.Uri; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.xml.sax.XmlBaseHandler; import com.thaiopensource.xml.sax.DelegatingContentHandler; import com.thaiopensource.xml.sax.CountingErrorHandler; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.StringSplitter; import com.thaiopensource.xml.util.WellKnownNamespaces; 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.LocatorImpl; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Stack; class SchemaImpl extends AbstractSchema { static final String MNS_URI = "http://www.thaiopensource.com/ns/mns"; private final Hashtable modeMap = new Hashtable(); private Mode startMode; private static final String DEFAULT_MODE_NAME = "#default"; private final boolean attributesSchema; static private final class WrappedIOException extends RuntimeException { private final IOException exception; private WrappedIOException(IOException exception) { this.exception = exception; } private IOException getException() { return exception; } } static class ElementAction { private final Schema schema; private final Mode mode; private final ContextMap contextMap; private final ElementsOrAttributes prune; private final Hashset covered = new Hashset(); ElementAction(String ns, Schema schema, Mode mode, ContextMap contextMap, ElementsOrAttributes prune) { this.schema = schema; this.mode = mode; this.contextMap = contextMap; this.prune = prune; covered.add(ns); } Mode getMode() { return mode; } ContextMap getContextMap() { return contextMap; } Schema getSchema() { return schema; } ElementsOrAttributes getPrune() { return prune; } Hashset getCoveredNamespaces() { return covered; } } static class Mode { private Locator whereDefined; private boolean defined = false; private ElementsOrAttributes lax; private boolean strictDefined = false; private final Hashtable elementMap = new Hashtable(); private final Hashtable attributesMap = new Hashtable(); Mode(ElementsOrAttributes lax) { this.lax = lax; } ElementsOrAttributes getLax() { return lax; } Schema getAttributesSchema(String ns) { return (Schema)attributesMap.get(ns); } ElementAction getElementAction(String ns) { return (ElementAction)elementMap.get(ns); } } private class Handler extends DelegatingContentHandler implements SchemaFuture { private final SchemaReceiverImpl sr; private ElementAction currentElementAction; private boolean hadError = false; private final ErrorHandler eh; private final CountingErrorHandler ceh; private final Localizer localizer = new Localizer(SchemaImpl.class); private Locator locator; private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler(); private int foreignDepth = 0; private String contextNs; private Mode contextMode; private String elementNs; private String defaultSchemaType; private final Stack nameStack = new Stack(); private boolean isRoot; private int pathDepth = 0; private Validator validator; Handler(SchemaReceiverImpl sr) { this.sr = sr; this.eh = sr.getProperties().get(ValidateProperty.ERROR_HANDLER); this.ceh = new CountingErrorHandler(eh); } public void setDocumentLocator(Locator locator) { xmlBaseHandler.setLocator(locator); this.locator = locator; } public void startDocument() throws SAXException { try { PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties()); builder.put(ValidateProperty.ERROR_HANDLER, ceh); validator = sr.getMnsSchema().createValidator(builder.toPropertyMap()); } catch (IOException e) { throw new WrappedIOException(e); } catch (IncorrectSchemaException e) { throw new RuntimeException("internal error in RNG schema for MNS"); } setDelegate(validator.getContentHandler()); if (locator != null) super.setDocumentLocator(locator); super.startDocument(); } public Schema getSchema() throws IncorrectSchemaException, SAXException { if (validator == null || ceh.getHadErrorOrFatalError()) throw new IncorrectSchemaException(); for (Enumeration e = modeMap.keys(); e.hasMoreElements();) { String modeName = (String)e.nextElement(); Mode mode = (Mode)modeMap.get(modeName); if (!mode.defined && !modeName.equals(DEFAULT_MODE_NAME)) error("undefined_mode", modeName, mode.whereDefined); } if (hadError) throw new IncorrectSchemaException(); return SchemaImpl.this; } public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException { if (e instanceof WrappedIOException) throw ((WrappedIOException)e).getException(); return e; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); xmlBaseHandler.startElement(); String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base"); if (xmlBase != null) xmlBaseHandler.xmlBaseAttribute(xmlBase); if (!MNS_URI.equals(uri) || foreignDepth > 0) { foreignDepth++; return; } if (ceh.getHadErrorOrFatalError()) return; if (localName.equals("rules")) parseRules(attributes); else if (localName.equals("cover")) parseCover(attributes); else if (localName.equals("context")) parseContext(attributes); else if (localName.equals("root")) parseRoot(attributes); else if (localName.equals("element")) parseElement(attributes); else if (localName.equals("lax")) parseLax(attributes); else parseValidate(localName.equals("validateAttributes"), attributes); } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { super.endElement(namespaceURI, localName, qName); xmlBaseHandler.endElement(); if (foreignDepth > 0) { foreignDepth--; return; } if (pathDepth > 0) { pathDepth--; if (pathDepth == 0) endPath(); } } private void parseRules(Attributes attributes) { String modeName = attributes.getValue("", "startMode"); if (modeName == null) modeName = DEFAULT_MODE_NAME; defaultSchemaType = getSchemaType(attributes); startMode = lookupCreateMode(modeName); } private void parseCover(Attributes attributes) throws SAXException { String ns = getNs(attributes, false); currentElementAction.covered.add(ns); } private void parseLax(Attributes attributes) throws SAXException { String[] modeNames = getInModes(attributes); Mode[] modes = getModes(modeNames); ElementsOrAttributes lax = toElementsOrAttributes(attributes.getValue("", "allow"), ElementsOrAttributes.BOTH); for (int i = 0; i < modes.length; i++) { if (modes[i].strictDefined) error("lax_multiply_defined", modeNames[i]); else { modes[i].lax = lax; modes[i].strictDefined = true; } } } private void parseValidate(boolean isAttribute, Attributes attributes) throws SAXException { String[] modeNames = getInModes(attributes); Mode[] modes = getModes(modeNames); String ns = getNs(attributes, isAttribute); String schemaUri = getSchema(attributes); String schemaType = getSchemaType(attributes); if (schemaType == null) schemaType = defaultSchemaType; try { if (isAttribute) { Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, true); for (int i = 0; i < modes.length; i++) { if (modes[i].attributesMap.get(ns) != null) error("validate_attributes_multiply_defined", modeNames[i], ns); else modes[i].attributesMap.put(ns, schema); } } else { Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, false); currentElementAction = new ElementAction(ns, schema, getUseMode(attributes), new ContextMap(), getPrune(attributes)); contextNs = ns; for (int i = 0; i < modes.length; i++) { if (modes[i].elementMap.get(ns) != null) error("validate_element_multiply_defined", modeNames[i], ns); else modes[i].elementMap.put(ns, currentElementAction); } } } catch (IncorrectSchemaException e) { hadError = true; } catch (IOException e) { throw new WrappedIOException(e); } } private void parseContext(Attributes attributes) throws SAXException { String ns = getNs(attributes, false); if (ns != null) contextNs = ns; elementNs = contextNs; contextMode = getUseMode(attributes); } private void parseRoot(Attributes attributes) throws SAXException { String ns = getNs(attributes, false); if (ns != null) elementNs = ns; isRoot = true; pathDepth++; } private void parseElement(Attributes attributes) throws SAXException { String ns = getNs(attributes, false); if (ns != null) elementNs = ns; if (!currentElementAction.covered.contains(elementNs)) error("context_ns_not_covered", elementNs); nameStack.push(new Name(elementNs, attributes.getValue("", "name").trim())); pathDepth++; } private void endPath() throws SAXException { if (!currentElementAction.contextMap.put(isRoot, nameStack, contextMode)) error("path_multiply_defined", displayPath(isRoot, nameStack)); elementNs = contextNs; isRoot = false; nameStack.setSize(0); } private String displayPath(boolean isRoot, Stack nameStack) { StringBuffer buf = new StringBuffer(); for (int i = 0, len = nameStack.size(); i < len; i++) { if (i > 0 || isRoot) buf.append('/'); Name name = (Name)nameStack.elementAt(i); if (name.getNamespaceUri().length() > 0) { buf.append('{'); buf.append(name.getNamespaceUri()); buf.append('}'); } buf.append(name.getLocalName()); } return buf.toString(); } private String getSchema(Attributes attributes) throws SAXException { String schemaUri = attributes.getValue("", "schema"); if (Uri.hasFragmentId(schemaUri)) error("schema_fragment_id"); return Uri.resolve(xmlBaseHandler.getBaseUri(), Uri.escapeDisallowedChars(schemaUri)); } private String getSchemaType(Attributes attributes) { return attributes.getValue("", "schemaType"); } private ElementsOrAttributes getPrune(Attributes attributes) { return toElementsOrAttributes(attributes.getValue("", "prune"), ElementsOrAttributes.NEITHER); } private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) { if (value == null) return defaultValue; ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER; if (value.indexOf("elements") >= 0) eoa = eoa.addElements(); if (value.indexOf("attributes") >= 0) eoa = eoa.addAttributes(); return eoa; } private Mode getUseMode(Attributes attributes) { String modeName = attributes.getValue("", "useMode"); if (modeName == null) modeName = DEFAULT_MODE_NAME; Mode mode = lookupCreateMode(modeName); if (mode.whereDefined == null && locator != null) mode.whereDefined = new LocatorImpl(locator); return mode; } private String getNs(Attributes attributes, boolean forbidEmpty) throws SAXException { String ns = attributes.getValue("", "ns"); if (ns != null && !Uri.isAbsolute(ns) && (forbidEmpty || !ns.equals(""))) error("ns_absolute"); return ns; } private Mode[] getModes(String[] modeNames) { Mode[] modes = new Mode[modeNames.length]; for (int i = 0; i < modes.length; i++) { modes[i] = lookupCreateMode(modeNames[i]); modes[i].defined = true; } return modes; } private String[] getInModes(Attributes attributes) { String inModes = attributes.getValue("", "inModes"); if (inModes == null) return new String[] { DEFAULT_MODE_NAME }; return StringSplitter.split(inModes); } void error(String key) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key), locator)); } void error(String key, String arg) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } void error(String key, String arg, Locator locator) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } void error(String key, String arg1, String arg2) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator)); } } SchemaImpl(boolean attributesSchema) { this.attributesSchema = attributesSchema; } SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) { Handler h = new Handler(sr); in.setContentHandler(h); return h; } public Validator createValidator(PropertyMap properties) { return new ValidatorImpl(startMode, properties); } private Mode lookupCreateMode(String name) { Mode mode = (Mode)modeMap.get(name); if (mode == null) { mode = new Mode(attributesSchema ? ElementsOrAttributes.ELEMENTS : ElementsOrAttributes.NEITHER); modeMap.put(name, mode); } return mode; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/SchemaReceiverImpl.java000066400000000000000000000073471225366607500331120ustar00rootroot00000000000000package com.thaiopensource.validate.mns; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.validate.rng.SAXSchemaReader; import com.thaiopensource.xml.util.Name; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import java.io.IOException; import java.net.URL; class SchemaReceiverImpl implements SchemaReceiver { private static final String MNS_SCHEMA = "mns.rng"; private static final String RNC_MEDIA_TYPE = "application/x-rnc"; private final PropertyMap properties; private final PropertyMap attributeSchemaProperties; private final boolean attributesSchema; private final SchemaReader autoSchemaLanguage; private Schema mnsSchema = null; public SchemaReceiverImpl(PropertyMap properties) { Name attributeOwner = properties.get(WrapProperty.ATTRIBUTE_OWNER); attributesSchema = (attributeOwner != null); PropertyMapBuilder builder = new PropertyMapBuilder(properties); if (ValidatorImpl.OWNER_NAME.equals(attributeOwner)) { attributeSchemaProperties = properties; builder.put(WrapProperty.ATTRIBUTE_OWNER, null); this.properties = builder.toPropertyMap(); } else { if (attributeOwner == null) this.properties = properties; else { builder.put(WrapProperty.ATTRIBUTE_OWNER, null); this.properties = builder.toPropertyMap(); } builder.put(WrapProperty.ATTRIBUTE_OWNER, ValidatorImpl.OWNER_NAME); attributeSchemaProperties = builder.toPropertyMap(); } this.autoSchemaLanguage = new AutoSchemaReader(properties.get(SchemaReceiverFactory.PROPERTY)); } public SchemaFuture installHandlers(XMLReader xr) { return new SchemaImpl(attributesSchema).installHandlers(xr, this); } Schema getMnsSchema() throws IOException, IncorrectSchemaException, SAXException { if (mnsSchema == null) { String className = SchemaReceiverImpl.class.getName(); String resourceName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + MNS_SCHEMA; URL mnsSchemaUrl = getResource(resourceName); mnsSchema = SAXSchemaReader.getInstance().createSchema( new InputSource(mnsSchemaUrl.toString()), properties); } return mnsSchema; } private static URL getResource(String resourceName) { ClassLoader cl = SchemaReceiverImpl.class.getClassLoader(); // XXX see if we should borrow 1.2 code from Service if (cl == null) return ClassLoader.getSystemResource(resourceName); else return cl.getResource(resourceName); } PropertyMap getProperties() { return properties; } Schema createChildSchema(InputSource inputSource, String schemaType, boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException { SchemaReader lang = isRnc(schemaType) ? CompactSchemaReader.getInstance() : autoSchemaLanguage; return lang.createSchema(inputSource, isAttributesSchema ? attributeSchemaProperties : properties); } private static boolean isRnc(String schemaType) { if (schemaType == null) return false; schemaType = schemaType.trim(); return schemaType.equals(RNC_MEDIA_TYPE); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/ValidatorImpl.java000066400000000000000000000212211225366607500321350ustar00rootroot00000000000000package com.thaiopensource.validate.mns; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.xml.util.Name; 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.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import java.util.Hashtable; import java.util.Stack; class ValidatorImpl extends DefaultHandler implements Validator { static final Name OWNER_NAME = new Name("http://www.thaiopensource.com/ns/mns/instance", "owner"); private SchemaImpl.Mode currentMode; private int laxDepth = 0; private final ErrorHandler eh; private final PropertyMap properties; private Locator locator; private Subtree subtrees = null; private final Hashset attributeNamespaces = new Hashset(); private PrefixMapping prefixMapping = null; private final Localizer localizer = new Localizer(ValidatorImpl.class); private final Hashtable validatorCache = new Hashtable(); static private class Subtree { final Subtree parent; final Validator validator; final Schema schema; final Hashset coveredNamespaces; final ElementsOrAttributes prune; final SchemaImpl.Mode parentMode; final int parentLaxDepth; final Stack context = new Stack(); final ContextMap contextMap; Subtree(Hashset coveredNamespaces, ContextMap contextMap, ElementsOrAttributes prune, Validator validator, Schema schema, SchemaImpl.Mode parentMode, int parentLaxDepth, Subtree parent) { this.coveredNamespaces = coveredNamespaces; this.contextMap = contextMap; this.prune = prune; this.validator = validator; this.schema = schema; this.parentMode = parentMode; this.parentLaxDepth = parentLaxDepth; this.parent = parent; } } static private class PrefixMapping { final String prefix; final String uri; final PrefixMapping parent; PrefixMapping(String prefix, String uri, PrefixMapping parent) { this.prefix = prefix; this.uri = uri; this.parent = parent; } } ValidatorImpl(SchemaImpl.Mode mode, PropertyMap properties) { this.currentMode = mode; this.properties = properties; this.eh = properties.get(ValidateProperty.ERROR_HANDLER); } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void characters(char ch[], int start, int length) throws SAXException { for (Subtree st = subtrees; wantsEvent(st); st = st.parent) st.validator.getContentHandler().characters(ch, start, length); } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { for (Subtree st = subtrees; wantsEvent(st); st = st.parent) st.validator.getContentHandler().ignorableWhitespace(ch, start, length); } private SchemaImpl.Mode getMode() { if (subtrees != null) { SchemaImpl.Mode mode = (SchemaImpl.Mode)subtrees.contextMap.get(subtrees.context); if (mode != null) return mode; } return currentMode; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (namespaceCovered(uri)) subtrees.context.push(new Name(uri, localName)); else { SchemaImpl.Mode mode = getMode(); SchemaImpl.ElementAction elementAction = mode.getElementAction(uri); if (elementAction == null) { if (laxDepth == 0 && !mode.getLax().containsElements()) error("element_undeclared_namespace", uri); laxDepth++; } else { subtrees = new Subtree(elementAction.getCoveredNamespaces(), elementAction.getContextMap(), elementAction.getPrune(), createValidator(elementAction.getSchema()), elementAction.getSchema(), currentMode, laxDepth, subtrees); subtrees.context.push(new Name(uri, localName)); currentMode = elementAction.getMode(); laxDepth = 0; startSubtree(subtrees.validator.getContentHandler()); } } for (Subtree st = subtrees; wantsEvent(st); st = st.parent) { Attributes prunedAtts; if (st.prune.containsAttributes()) prunedAtts = new NamespaceFilteredAttributes(uri, true, attributes); else prunedAtts = attributes; st.validator.getContentHandler().startElement(uri, localName, qName, prunedAtts); } for (int i = 0, len = attributes.getLength(); i < len; i++) { String ns = attributes.getURI(i); if (!ns.equals("") && !ns.equals(uri) && !namespaceCovered(ns) && !attributeNamespaces.contains(ns)) { attributeNamespaces.add(ns); validateAttributes(ns, attributes); } } attributeNamespaces.clear(); } private boolean namespaceCovered(String ns) { return (laxDepth == 0 && subtrees != null && subtrees.coveredNamespaces.contains(ns)); } private boolean wantsEvent(Subtree st) { return st != null && (!st.prune.containsElements() || (laxDepth == 0 && st == subtrees)); } private void validateAttributes(String ns, Attributes attributes) throws SAXException { SchemaImpl.Mode mode = getMode(); Schema attributesSchema = mode.getAttributesSchema(ns); if (attributesSchema == null) { if (!mode.getLax().containsAttributes()) error("attributes_undeclared_namespace", ns); return; } Validator validator = createValidator(attributesSchema); ContentHandler ch = validator.getContentHandler(); startSubtree(ch); ch.startElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName(), new NamespaceFilteredAttributes(ns, false, attributes)); ch.endElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName()); endSubtree(ch); releaseValidator(attributesSchema, validator); } private void startSubtree(ContentHandler ch) throws SAXException { if (locator != null) ch.setDocumentLocator(locator); ch.startDocument(); for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) ch.startPrefixMapping(pm.prefix, pm.uri); } private void endSubtree(ContentHandler ch) throws SAXException { for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) ch.endPrefixMapping(pm.prefix); ch.endDocument(); } public void endElement(String uri, String localName, String qName) throws SAXException { for (Subtree st = subtrees; wantsEvent(st); st = st.parent) st.validator.getContentHandler().endElement(uri, localName, qName); if (laxDepth > 0) laxDepth--; else if (!subtrees.context.empty()) { subtrees.context.pop(); if (subtrees.context.empty()) { endSubtree(subtrees.validator.getContentHandler()); releaseValidator(subtrees.schema, subtrees.validator); currentMode = subtrees.parentMode; laxDepth = subtrees.parentLaxDepth; subtrees = subtrees.parent; } } } private Validator createValidator(Schema schema) { Stack stack = (Stack)validatorCache.get(schema); if (stack == null) { stack = new Stack(); validatorCache.put(schema, stack); } if (stack.empty()) return schema.createValidator(properties); return (Validator)stack.pop(); } private void releaseValidator(Schema schema, Validator validator) { validator.reset(); ((Stack)validatorCache.get(schema)).push(validator); } public void endDocument() throws SAXException { } public void startPrefixMapping(String prefix, String uri) throws SAXException { super.startPrefixMapping(prefix, uri); prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); } public void endPrefixMapping(String prefix) throws SAXException { super.endPrefixMapping(prefix); prefixMapping = prefixMapping.parent; } public void reset() { subtrees = null; locator = null; } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return null; } private void error(String key, String arg) throws SAXException { eh.error(new SAXParseException(localizer.message(key, arg), locator)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/resources/000077500000000000000000000000001225366607500305375ustar00rootroot00000000000000Messages.properties000066400000000000000000000014551225366607500343520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/resourceselement_undeclared_namespace=no applicable schema for element with namespace \"{0}\" in this context attributes_undeclared_namespace=no applicable schema for one or more attributes with namespace \"{0}\" in this context lax_multiply_defined=laxness for mode \"{0}\" already defined undefined_mode=mode \"{0}\" not defined schema_fragment_id=schema URI must not have a fragment identifier ns_absolute=namespace URI must be absolute URI validate_attributes_multiply_defined=multiple applicable \"validateAttributes\" elements in mode \"{0}\" for namespace \"{1}\" validate_element_multiply_defined=multiple applicable \"validateElement\" elements in mode \"{0}\" for namespace \"{1}\" path_multiply_defined=mode for context \"{0}\" already defined context_ns_not_covered=namespace of contextual element not covered jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/mns/resources/mns.rng000066400000000000000000000117201225366607500320450ustar00rootroot00000000000000 #default elements attributes attributes elements elements attributes jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/000077500000000000000000000000001225366607500265235ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/Action.java000066400000000000000000000007271225366607500306110ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; abstract class Action { private final ModeUsage modeUsage; Action(ModeUsage modeUsage) { this.modeUsage = modeUsage; } ModeUsage getModeUsage() { return modeUsage; } public boolean equals(Object obj) { return obj != null && obj.getClass() == getClass() && ((Action)obj).modeUsage.equals(modeUsage); } public int hashCode() { return getClass().hashCode() ^ modeUsage.hashCode(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ActionSet.java000066400000000000000000000021531225366607500312600ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; class ActionSet { private ResultAction resultAction; private NoResultAction[] noResultActions = new NoResultAction[0]; ResultAction getResultAction() { return resultAction; } void setResultAction(ResultAction resultAction) { this.resultAction = resultAction; } void addNoResultAction(NoResultAction action) { NoResultAction[] actions = new NoResultAction[noResultActions.length + 1]; System.arraycopy(noResultActions, 0, actions, 0, noResultActions.length); actions[noResultActions.length] = action; noResultActions = actions; } NoResultAction[] getNoResultActions() { return noResultActions; } ActionSet changeCurrentMode(Mode mode) { ActionSet actions = new ActionSet(); if (this.resultAction != null) actions.resultAction = this.resultAction.changeCurrentMode(mode); actions.noResultActions = new NoResultAction[this.noResultActions.length]; for (int i = 0; i < actions.noResultActions.length; i++) actions.noResultActions[i] = this.noResultActions[i].changeCurrentMode(mode); return actions; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/AllowAction.java000066400000000000000000000006421225366607500316040ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; class AllowAction extends NoResultAction { AllowAction(ModeUsage modeUsage) { super(modeUsage); } void perform(SectionState state) { state.addChildMode(getModeUsage(), null); state.addAttributeValidationModeUsage(getModeUsage()); } NoResultAction changeCurrentMode(Mode mode) { return new AllowAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/AttachAction.java000066400000000000000000000013511225366607500317300ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.nrl.Mode; import com.thaiopensource.validate.nrl.ModeUsage; import org.xml.sax.ContentHandler; class AttachAction extends ResultAction { AttachAction(ModeUsage modeUsage) { super(modeUsage); } void perform(ContentHandler handler, SectionState state) { final ModeUsage modeUsage = getModeUsage(); if (handler != null) state.addActiveHandler(handler, modeUsage); else state.addAttributeValidationModeUsage(modeUsage); state.addChildMode(modeUsage, handler); } ResultAction changeCurrentMode(Mode mode) { return new AttachAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/AttributeActionSet.java000066400000000000000000000012531225366607500331440ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Schema; class AttributeActionSet { private boolean attach; private boolean reject; private Schema[] schemas = new Schema[0]; boolean getAttach() { return attach; } void setAttach(boolean attach) { this.attach = attach; } boolean getReject() { return reject; } void setReject(boolean reject) { this.reject = reject; } Schema[] getSchemas() { return schemas; } void addSchema(Schema schema) { Schema[] s = new Schema[schemas.length + 1]; System.arraycopy(schemas, 0, s, 0, schemas.length); s[schemas.length] = schema; schemas = s; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ContextMap.java000066400000000000000000000073101225366607500314510ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.util.Equal; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; import java.util.NoSuchElementException; class ContextMap { private Object rootValue; private Object otherValue; private final Hashtable nameTable = new Hashtable(); Object get(Vector context) { return get(context, context.size()); } boolean put(boolean isRoot, Vector names, Object value) { return put(isRoot, names, names.size(), value); } private Object get(Vector context, int len) { if (len > 0) { ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1)); if (nestedMap != null) { Object value = nestedMap.get(context, len - 1); if (value != null) return value; } } if (rootValue != null && len == 0) return rootValue; return otherValue; } private boolean put(boolean isRoot, Vector names, int len, Object value) { if (len == 0) { if (isRoot) { if (rootValue != null) return false; rootValue = value; } else { if (otherValue != null) return false; otherValue = value; } return true; } else { Object name = names.elementAt(len - 1); ContextMap nestedMap = (ContextMap)nameTable.get(name); if (nestedMap == null) { nestedMap = new ContextMap(); nameTable.put(name, nestedMap); } return nestedMap.put(isRoot, names, len - 1, value); } } public boolean equals(Object obj) { if (!(obj instanceof ContextMap)) return false; ContextMap other = (ContextMap)obj; if (!Equal.equal(this.rootValue, other.rootValue) || !Equal.equal(this.otherValue, other.otherValue)) return false; // We want jing to work with JDK 1.1 so we cannot use Hashtable.equals if (this.nameTable.size() != other.nameTable.size()) return false; for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { Object key = e.nextElement(); if (!nameTable.get(key).equals(other.nameTable.get(key))) return false; } return true; } public int hashCode() { int hc = 0; if (rootValue != null) hc ^= rootValue.hashCode(); if (otherValue != null) hc ^= otherValue.hashCode(); for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { Object key = e.nextElement(); hc ^= key.hashCode(); hc ^= nameTable.get(key).hashCode(); } return hc; } static private class Enumerator implements Enumeration { private Object rootValue; private Object otherValue; private Enumeration subMapValues; private final Enumeration subMaps; private Enumerator(ContextMap map) { rootValue = map.rootValue; otherValue = map.otherValue; subMaps = map.nameTable.elements(); } private void prep() { while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements()) subMapValues = ((ContextMap)subMaps.nextElement()).values(); } public boolean hasMoreElements() { prep(); return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements()); } public Object nextElement() { if (rootValue != null) { Object tem = rootValue; rootValue = null; return tem; } if (otherValue != null) { Object tem = otherValue; otherValue = null; return tem; } prep(); if (subMapValues == null) throw new NoSuchElementException(); return subMapValues.nextElement(); } } Enumeration values() { return new Enumerator(this); } } ElementsOrAttributes.java000066400000000000000000000020621225366607500334330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrlpackage com.thaiopensource.validate.nrl; class ElementsOrAttributes { private static final int ELEMENTS_FLAG = 01; private static final int ATTRIBUTES_FLAG = 02; static final ElementsOrAttributes NEITHER = new ElementsOrAttributes(0); static final ElementsOrAttributes ELEMENTS = new ElementsOrAttributes(ELEMENTS_FLAG); static final ElementsOrAttributes ATTRIBUTES = new ElementsOrAttributes(ATTRIBUTES_FLAG); static final ElementsOrAttributes BOTH = new ElementsOrAttributes(ELEMENTS_FLAG|ATTRIBUTES_FLAG); private static final ElementsOrAttributes values[] = { NEITHER, ELEMENTS, ATTRIBUTES, BOTH }; private int flags = 0; private ElementsOrAttributes(int flags) { this.flags = flags; } ElementsOrAttributes addElements() { return values[flags | ELEMENTS_FLAG]; } ElementsOrAttributes addAttributes() { return values[flags | ATTRIBUTES_FLAG]; } boolean containsAttributes() { return (flags & ATTRIBUTES_FLAG) != 0; } boolean containsElements() { return (flags & ELEMENTS_FLAG) != 0; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/FilteredAttributes.java000066400000000000000000000051271225366607500332000ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import org.xml.sax.Attributes; class FilteredAttributes implements Attributes { private final Attributes attributes; private final IntSet indexSet; private int[] reverseIndexMap; public FilteredAttributes(IntSet indexSet, Attributes attributes) { this.indexSet = indexSet; this.attributes = attributes; } private int reverseIndex(int k) { if (reverseIndexMap == null) { reverseIndexMap = new int[attributes.getLength()]; for (int i = 0, len = indexSet.size(); i < len; i++) reverseIndexMap[indexSet.get(i)] = i + 1; } return reverseIndexMap[k] - 1; } public int getLength() { return indexSet.size(); } public String getURI(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getURI(indexSet.get(index)); } public String getLocalName(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getLocalName(indexSet.get(index)); } public String getQName(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getQName(indexSet.get(index)); } public String getType(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getType(indexSet.get(index)); } public String getValue(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getValue(indexSet.get(index)); } public int getIndex(String uri, String localName) { int n = attributes.getIndex(uri, localName); if (n < 0) return n; return reverseIndex(n); } public int getIndex(String qName) { int n = attributes.getIndex(qName); if (n < 0) return n; return reverseIndex(n); } private int getRealIndex(String uri, String localName) { int index = attributes.getIndex(uri, localName); if (index < 0 || reverseIndex(index) < 0) return -1; return index; } private int getRealIndex(String qName) { int index = attributes.getIndex(qName); if (index < 0 || reverseIndex(index) < 0) return -1; return index; } public String getType(String uri, String localName) { return attributes.getType(getRealIndex(uri, localName)); } public String getValue(String uri, String localName) { return attributes.getValue(getRealIndex(uri, localName)); } public String getType(String qName) { return attributes.getType(getRealIndex(qName)); } public String getValue(String qName) { return attributes.getValue(getRealIndex(qName)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/Hashset.java000066400000000000000000000010121225366607500307570ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import java.util.Hashtable; import java.util.Enumeration; class Hashset { private final Hashtable table = new Hashtable(); boolean contains(Object key) { return table.get(key) != null; } void add(Object key) { table.put(key, key); } void addAll(Hashset set) { for (Enumeration e = set.table.keys(); e.hasMoreElements();) add(e.nextElement()); } void clear() { table.clear(); } Enumeration members() { return table.keys(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/IntSet.java000066400000000000000000000026061225366607500306000ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; class IntSet { static private final int INIT_SIZE = 4; private int[] v = null; private int len = 0; void add(int n) { if (v == null) { v = new int[INIT_SIZE]; v[0] = n; len = 1; return; } if (len == v.length) { int[] newv = new int[len*2]; System.arraycopy(v, 0, newv, 0, len); v = newv; } if (n > v[len - 1]) { v[len++] = n; return; } int i = 0; for (; i < len; i++) { if (n <= v[i]) { if (n == v[i]) return; break; } } for (int j = len; j >= i; j--) v[j + 1] = v[j]; v[i] = n; ++len; } void addAll(IntSet is) { if (is.len == 0) return; int[] newv = new int[len + is.len]; int i = 0, j = 0, k = 0; while (i < len && j < is.len) { if (v[i] < is.v[j]) newv[k++] = v[i++]; else if (is.v[j] < v[i]) newv[k++] = is.v[j++]; else { newv[k++] = v[i++]; j++; } } while (i < len) newv[k++] = v[i++]; while (j < is.len) newv[k++] = is.v[j++]; v = newv; len = k; } int size() { return len; } int get(int i) { if (i >= len) throw new IndexOutOfBoundsException(); try { return v[i]; } catch (NullPointerException e) { throw new IndexOutOfBoundsException(); } } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/Mode.java000066400000000000000000000101011225366607500302430ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import org.xml.sax.Locator; import org.xml.sax.helpers.LocatorImpl; import java.util.Hashtable; import java.util.Enumeration; import com.thaiopensource.validate.nrl.ActionSet; import com.thaiopensource.validate.nrl.AttributeActionSet; class Mode { static final String ANY_NAMESPACE = "##any"; static final int ATTRIBUTE_PROCESSING_NONE = 0; static final int ATTRIBUTE_PROCESSING_QUALIFIED = 1; static final int ATTRIBUTE_PROCESSING_FULL = 2; static final Mode CURRENT = new Mode("#current", null); private final String name; private Mode baseMode; private boolean defined; private Locator whereDefined; private Locator whereUsed; private final Hashtable elementMap = new Hashtable(); private final Hashtable attributeMap = new Hashtable(); private int attributeProcessing = -1; Mode(String name, Mode baseMode) { this.name = name; this.baseMode = baseMode; } String getName() { return name; } Mode getBaseMode() { return baseMode; } void setBaseMode(Mode baseMode) { this.baseMode = baseMode; } ActionSet getElementActions(String ns) { ActionSet actions = getElementActionsExplicit(ns); if (actions == null) { actions = getElementActionsExplicit(ANY_NAMESPACE); // this is not correct: it breaks a derived mode that use anyNamespace // elementMap.put(ns, actions); } return actions; } private ActionSet getElementActionsExplicit(String ns) { ActionSet actions = (ActionSet)elementMap.get(ns); if (actions == null && baseMode != null) { actions = baseMode.getElementActionsExplicit(ns); if (actions != null) { actions = actions.changeCurrentMode(this); elementMap.put(ns, actions); } } return actions; } AttributeActionSet getAttributeActions(String ns) { AttributeActionSet actions = getAttributeActionsExplicit(ns); if (actions == null) { actions = getAttributeActionsExplicit(ANY_NAMESPACE); // this is not correct: it breaks a derived mode that use anyNamespace // attributeMap.put(ns, actions); } return actions; } private AttributeActionSet getAttributeActionsExplicit(String ns) { AttributeActionSet actions = (AttributeActionSet)attributeMap.get(ns); if (actions == null && baseMode != null) { actions = baseMode.getAttributeActionsExplicit(ns); if (actions != null) attributeMap.put(ns, actions); } return actions; } int getAttributeProcessing() { if (attributeProcessing == -1) { if (baseMode != null) attributeProcessing = baseMode.getAttributeProcessing(); else attributeProcessing = ATTRIBUTE_PROCESSING_NONE; for (Enumeration e = attributeMap.keys(); e.hasMoreElements() && attributeProcessing != ATTRIBUTE_PROCESSING_FULL;) { String ns = (String)e.nextElement(); AttributeActionSet actions = (AttributeActionSet)attributeMap.get(ns); if (!actions.getAttach() || actions.getReject() || actions.getSchemas().length > 0) attributeProcessing = ((ns.equals("") || ns.equals(ANY_NAMESPACE)) ? ATTRIBUTE_PROCESSING_FULL : ATTRIBUTE_PROCESSING_QUALIFIED); } } return attributeProcessing; } Locator getWhereDefined() { return whereDefined; } boolean isDefined() { return defined; } Locator getWhereUsed() { return whereUsed; } void noteUsed(Locator locator) { if (whereUsed == null && locator != null) whereUsed = new LocatorImpl(locator); } void noteDefined(Locator locator) { defined = true; if (whereDefined == null && locator != null) whereDefined = new LocatorImpl(locator); } boolean bindElement(String ns, ActionSet actions) { if (elementMap.get(ns) != null) return false; elementMap.put(ns, actions); return true; } boolean bindAttribute(String ns, AttributeActionSet actions) { if (attributeMap.get(ns) != null) return false; attributeMap.put(ns, actions); return true; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ModeUsage.java000066400000000000000000000042401225366607500312370ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.util.Equal; import com.thaiopensource.validate.nrl.ContextMap; import com.thaiopensource.validate.nrl.Mode; import java.util.Vector; import java.util.Enumeration; class ModeUsage { private final Mode mode; private final Mode currentMode; private ContextMap modeMap; private int attributeProcessing = -1; ModeUsage(Mode mode, Mode currentMode) { this(mode, currentMode, null); } private ModeUsage(Mode mode, Mode currentMode, ContextMap modeMap) { this.mode = mode; this.currentMode = currentMode; this.modeMap = modeMap; } ModeUsage changeCurrentMode(Mode currentMode) { return new ModeUsage(mode, currentMode, modeMap); } public boolean equals(Object obj) { if (!(obj instanceof ModeUsage)) return false; ModeUsage other = (ModeUsage)obj; return this.mode == other.mode && this.currentMode == other.currentMode && Equal.equal(this.modeMap, other.modeMap); } public int hashCode() { int hc = mode.hashCode() ^ currentMode.hashCode(); if (modeMap != null) hc ^= modeMap.hashCode(); return hc; } private Mode resolve(Mode mode) { return mode == Mode.CURRENT ? currentMode : mode; } int getAttributeProcessing() { if (attributeProcessing == -1) { attributeProcessing = resolve(mode).getAttributeProcessing(); if (modeMap != null) { for (Enumeration e = modeMap.values(); e.hasMoreElements() && attributeProcessing != Mode.ATTRIBUTE_PROCESSING_FULL;) attributeProcessing = Math.max(resolve((Mode)e.nextElement()).getAttributeProcessing(), attributeProcessing); } } return attributeProcessing; } boolean isContextDependent() { return modeMap != null; } Mode getMode(Vector context) { if (modeMap != null) { Mode m = (Mode)modeMap.get(context); if (m != null) return resolve(m); } return resolve(mode); } boolean addContext(boolean isRoot, Vector names, Mode mode) { if (modeMap == null) modeMap = new ContextMap(); return modeMap.put(isRoot, names, mode); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/NoResultAction.java000066400000000000000000000007651225366607500323070ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.nrl.Action; import com.thaiopensource.validate.nrl.Mode; import com.thaiopensource.validate.nrl.ModeUsage; import org.xml.sax.SAXException; abstract class NoResultAction extends Action { NoResultAction(ModeUsage modeUsage) { super(modeUsage); } abstract void perform(SectionState state) throws SAXException; abstract NoResultAction changeCurrentMode(Mode mode); } NrlSchemaReceiverFactory.java000066400000000000000000000011261225366607500342000ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrlpackage com.thaiopensource.validate.nrl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.Option; public class NrlSchemaReceiverFactory implements SchemaReceiverFactory { public SchemaReceiver createSchemaReceiver(String namespaceUri, PropertyMap properties) { if (!SchemaImpl.NRL_URI.equals(namespaceUri)) return null; return new SchemaReceiverImpl(properties); } public Option getOption(String uri) { return null; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/Path.java000066400000000000000000000072731225366607500302730ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.xml.util.Naming; import java.util.Vector; class Path { private final boolean root; private final Vector names; Path(boolean root, Vector names) { this.root = root; this.names = names; } boolean isRoot() { return root; } Vector getNames() { return names; } public String toString() { StringBuffer buf = new StringBuffer(); if (root) buf.append('/'); for (int i = 0, len = names.size(); i < len; i++) { if (i != 0) buf.append('/'); buf.append((String)names.elementAt(i)); } return buf.toString(); } static class ParseException extends Exception { private final String messageKey; ParseException(String messageKey) { super(messageKey); this.messageKey = messageKey; } public String getMessageKey() { return messageKey; } } private static final int START = 0; private static final int IN_NAME = 1; private static final int AFTER_NAME = 2; private static final int AFTER_SLASH = 3; static Vector parse(String str) throws ParseException { int state = START; int nameStartIndex = -1; Vector paths = new Vector(); Vector names = new Vector(); boolean root = false; for (int i = 0, len = str.length(); i < len; i++) { char c = str.charAt(i); switch (c) { case ' ': case '\r': case '\n': case '\t': if (state == IN_NAME) { names.addElement(makeName(str, nameStartIndex, i)); state = AFTER_NAME; } break; case '/': switch (state) { case IN_NAME: names.addElement(makeName(str, nameStartIndex, i)); break; case START: root = true; break; case AFTER_SLASH: throw new ParseException("unexpected_slash"); } state = AFTER_SLASH; break; case '|': switch (state) { case START: throw new ParseException("empty_path"); case AFTER_NAME: break; case AFTER_SLASH: throw new ParseException("expected_name"); case IN_NAME: names.addElement(makeName(str, nameStartIndex, i)); break; } paths.addElement(new Path(root, names)); root = false; names = new Vector(); state = START; break; default: switch (state) { case AFTER_NAME: throw new ParseException("expected_slash"); case AFTER_SLASH: case START: nameStartIndex = i; state = IN_NAME; break; case IN_NAME: break; } break; } } switch (state) { case START: throw new ParseException("empty_path"); case AFTER_NAME: break; case AFTER_SLASH: throw new ParseException("expected_name"); case IN_NAME: names.addElement(makeName(str, nameStartIndex, str.length())); break; } paths.addElement(new Path(root, names)); return paths; } private static String makeName(String str, int start, int end) throws ParseException { String name = str.substring(start, end); if (!Naming.isNcname(name)) throw new ParseException("invalid_name"); return name; } static public void main(String[] args) throws ParseException { Vector paths = parse(args[0]); for (int i = 0; i < paths.size(); i++) { if (i != 0) System.out.println("---"); Path path = (Path)paths.elementAt(i); if (path.isRoot()) System.out.println("/"); for (int j = 0; j < path.getNames().size(); j++) System.out.println(path.getNames().elementAt(j)); } } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/RejectAction.java000066400000000000000000000012531225366607500317410ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import org.xml.sax.SAXException; import com.thaiopensource.validate.nrl.Mode; import com.thaiopensource.validate.nrl.ModeUsage; import com.thaiopensource.validate.nrl.NoResultAction; class RejectAction extends NoResultAction { RejectAction(ModeUsage modeUsage) { super(modeUsage); } void perform(SectionState state) throws SAXException { final ModeUsage modeUsage = getModeUsage(); state.reject(); state.addChildMode(modeUsage, null); state.addAttributeValidationModeUsage(modeUsage); } NoResultAction changeCurrentMode(Mode mode) { return new RejectAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ResultAction.java000066400000000000000000000010521225366607500320000ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.nrl.Action; import com.thaiopensource.validate.nrl.Mode; import com.thaiopensource.validate.nrl.ModeUsage; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; abstract class ResultAction extends Action { ResultAction(ModeUsage modeUsage) { super(modeUsage); } abstract void perform(ContentHandler handler, SectionState state) throws SAXException; abstract ResultAction changeCurrentMode(Mode mode); } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/SchemaImpl.java000066400000000000000000000473221225366607500314200ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyId; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.util.Uri; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.OptionArgumentException; import com.thaiopensource.validate.OptionArgumentPresenceException; import com.thaiopensource.validate.ResolverFactory; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.xml.sax.CountingErrorHandler; import com.thaiopensource.xml.sax.DelegatingContentHandler; import com.thaiopensource.xml.sax.XmlBaseHandler; import com.thaiopensource.xml.util.WellKnownNamespaces; 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.XMLReader; import org.xml.sax.helpers.LocatorImpl; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; class SchemaImpl extends AbstractSchema { static private final String IMPLICIT_MODE_NAME = "#implicit"; static private final String WRAPPER_MODE_NAME = "#wrapper"; static final String NRL_URI = SchemaReader.BASE_URI + "nrl"; private final Hashtable modeMap = new Hashtable(); private Mode startMode; private final Mode defaultBaseMode; private final boolean attributesSchema; static private final class WrappedIOException extends RuntimeException { private final IOException exception; private WrappedIOException(IOException exception) { this.exception = exception; } private IOException getException() { return exception; } } static private class MustSupportOption { private final String name; private final PropertyId pid; private final Locator locator; MustSupportOption(String name, PropertyId pid, Locator locator) { this.name = name; this.pid = pid; this.locator = locator; } } private class Handler extends DelegatingContentHandler implements SchemaFuture { private final SchemaReceiverImpl sr; private boolean hadError = false; private final ErrorHandler eh; private final SAXResolver resolver; private final CountingErrorHandler ceh; private final Localizer localizer = new Localizer(SchemaImpl.class); private Locator locator; private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler(); private int foreignDepth = 0; private Mode currentMode = null; private String defaultSchemaType; private Validator validator; private ElementsOrAttributes match; private ActionSet actions; private AttributeActionSet attributeActions; private String schemaUri; private String schemaUriBase; private String schemaType; private PropertyMapBuilder options; private final Vector mustSupportOptions = new Vector(); private ModeUsage modeUsage; private boolean anyNamespace; Handler(SchemaReceiverImpl sr) { this.sr = sr; this.eh = sr.getProperties().get(ValidateProperty.ERROR_HANDLER); this.ceh = new CountingErrorHandler(this.eh); this.resolver = ResolverFactory.createResolver(sr.getProperties()); } public void setDocumentLocator(Locator locator) { xmlBaseHandler.setLocator(locator); this.locator = locator; } public void startDocument() throws SAXException { try { PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties()); builder.put(ValidateProperty.ERROR_HANDLER, ceh); validator = sr.getNrlSchema().createValidator(builder.toPropertyMap()); } catch (IOException e) { throw new WrappedIOException(e); } catch (IncorrectSchemaException e) { throw new RuntimeException("internal error in RNG schema for NRL"); } setDelegate(validator.getContentHandler()); if (locator != null) super.setDocumentLocator(locator); super.startDocument(); } public Schema getSchema() throws IncorrectSchemaException, SAXException { if (validator == null || ceh.getHadErrorOrFatalError()) throw new IncorrectSchemaException(); Hashset openModes = new Hashset(); Hashset checkedModes = new Hashset(); for (Enumeration e = modeMap.keys(); e.hasMoreElements();) { String modeName = (String)e.nextElement(); Mode mode = (Mode)modeMap.get(modeName); if (!mode.isDefined()) error("undefined_mode", modeName, mode.getWhereUsed()); for (Mode tem = mode; tem != null; tem = tem.getBaseMode()) { if (checkedModes.contains(tem)) break; if (openModes.contains(tem)) { error("mode_cycle", tem.getName(), tem.getWhereDefined()); break; } openModes.add(tem); } checkedModes.addAll(openModes); openModes.clear(); } if (hadError) throw new IncorrectSchemaException(); return SchemaImpl.this; } public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException { if (e instanceof WrappedIOException) throw ((WrappedIOException)e).getException(); return e; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); xmlBaseHandler.startElement(); String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base"); if (xmlBase != null) xmlBaseHandler.xmlBaseAttribute(xmlBase); if (!NRL_URI.equals(uri) || foreignDepth > 0) { foreignDepth++; return; } if (ceh.getHadErrorOrFatalError()) return; if (localName.equals("rules")) parseRules(attributes); else if (localName.equals("mode")) parseMode(attributes); else if (localName.equals("namespace")) parseNamespace(attributes); else if (localName.equals("anyNamespace")) parseAnyNamespace(attributes); else if (localName.equals("validate")) parseValidate(attributes); else if (localName.equals("reject")) parseReject(attributes); else if (localName.equals("attach")) parseAttach(attributes); else if (localName.equals("unwrap")) parseUnwrap(attributes); else if (localName.equals("allow")) parseAllow(attributes); else if (localName.equals("context")) parseContext(attributes); else if (localName.equals("option")) parseOption(attributes); else throw new RuntimeException("unexpected element \"" + localName + "\""); } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { super.endElement(namespaceURI, localName, qName); xmlBaseHandler.endElement(); if (foreignDepth > 0) { foreignDepth--; return; } if (ceh.getHadErrorOrFatalError()) return; if (localName.equals("validate")) finishValidate(); } private void parseRules(Attributes attributes) { startMode = getModeAttribute(attributes, "startMode"); if (startMode == null) { startMode = lookupCreateMode(IMPLICIT_MODE_NAME); currentMode = startMode; startMode.noteDefined(null); } startMode.noteUsed(locator); if (attributesSchema) { Mode wrapper = lookupCreateMode(WRAPPER_MODE_NAME); ActionSet actions = new ActionSet(); actions.addNoResultAction(new AllowAction(new ModeUsage(startMode, startMode))); wrapper.bindElement(Mode.ANY_NAMESPACE, actions); wrapper.noteDefined(null); startMode = wrapper; } defaultSchemaType = getSchemaType(attributes); } private void parseMode(Attributes attributes) throws SAXException { currentMode = getModeAttribute(attributes, "name"); if (currentMode.isDefined()) { error("duplicate_mode", currentMode.getName()); error("first_mode", currentMode.getName(), currentMode.getWhereDefined()); } else { Mode base = getModeAttribute(attributes, "extends"); if (base != null) currentMode.setBaseMode(base); currentMode.noteDefined(locator); } } private void parseNamespace(Attributes attributes) throws SAXException { anyNamespace = false; parseRule(getNs(attributes), attributes); } private void parseAnyNamespace(Attributes attributes) throws SAXException { anyNamespace = true; parseRule(Mode.ANY_NAMESPACE, attributes); } private void parseRule(String ns, Attributes attributes) throws SAXException { match = toElementsOrAttributes(attributes.getValue("", "match"), ElementsOrAttributes.ELEMENTS); if (match.containsAttributes()) { attributeActions = new AttributeActionSet(); if (!currentMode.bindAttribute(ns, attributeActions)) { if (ns.equals(Mode.ANY_NAMESPACE)) error("duplicate_attribute_action_any_namespace"); else error("duplicate_attribute_action", ns); } } if (match.containsElements()) { actions = new ActionSet(); if (!currentMode.bindElement(ns, actions)) { if (ns.equals(Mode.ANY_NAMESPACE)) error("duplicate_element_action_any_namespace"); else error("duplicate_element_action", ns); } } else actions = null; } private void parseValidate(Attributes attributes) throws SAXException { schemaUri = getSchema(attributes); schemaUriBase = xmlBaseHandler.getBaseUri(); schemaType = getSchemaType(attributes); if (schemaType == null) schemaType = defaultSchemaType; if (actions != null) modeUsage = getModeUsage(attributes); else modeUsage = null; options = new PropertyMapBuilder(); mustSupportOptions.clear(); } private void finishValidate() throws SAXException { try { if (attributeActions != null) { Schema schema = createSubSchema(true); attributeActions.addSchema(schema); } if (actions != null) { Schema schema = createSubSchema(false); actions.addNoResultAction(new ValidateAction(modeUsage, schema)); } } catch (IncorrectSchemaException e) { hadError = true; } catch (IOException e) { throw new WrappedIOException(e); } } private Schema createSubSchema(boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException { PropertyMap requestedProperties = options.toPropertyMap(); Schema schema = sr.createChildSchema(resolver.resolve(schemaUri, schemaUriBase), schemaType, requestedProperties, isAttributesSchema); PropertyMap actualProperties = schema.getProperties(); for (Enumeration e = mustSupportOptions.elements(); e.hasMoreElements();) { MustSupportOption mso = (MustSupportOption)e.nextElement(); Object actualValue = actualProperties.get(mso.pid); if (actualValue == null) error("unsupported_option", mso.name, mso.locator); else if (!actualValue.equals(requestedProperties.get(mso.pid))) error("unsupported_option_arg", mso.name, mso.locator); } return schema; } private void parseOption(Attributes attributes) throws SAXException { boolean mustSupport; String mustSupportValue = attributes.getValue("", "mustSupport"); if (mustSupportValue != null) { mustSupportValue = mustSupportValue.trim(); mustSupport = mustSupportValue.equals("1") || mustSupportValue.equals("true"); } else mustSupport = false; String name = Uri.resolve(NRL_URI, attributes.getValue("", "name")); Option option = sr.getOption(name); if (option == null) { if (mustSupport) error("unknown_option", name); } else { String arg = attributes.getValue("", "arg"); try { PropertyId pid = option.getPropertyId(); Object value = option.valueOf(arg); Object oldValue = options.get(pid); if (oldValue != null) { value = option.combine(new Object[]{oldValue, value}); if (value == null) error("duplicate_option", name); else options.put(pid, value); } else { options.put(pid, value); mustSupportOptions.addElement(new MustSupportOption(name, pid, locator == null ? null : new LocatorImpl(locator))); } } catch (OptionArgumentPresenceException e) { error(arg == null ? "option_requires_argument" : "option_unexpected_argument", name); } catch (OptionArgumentException e) { if (arg == null) error("option_requires_argument", name); else error("option_bad_argument", name, arg); } } } private void parseAttach(Attributes attributes) { if (attributeActions != null) attributeActions.setAttach(true); if (actions != null) { modeUsage = getModeUsage(attributes); actions.setResultAction(new AttachAction(modeUsage)); } else modeUsage = null; } private void parseUnwrap(Attributes attributes) { if (actions != null) { modeUsage = getModeUsage(attributes); actions.setResultAction(new UnwrapAction(modeUsage)); } else modeUsage = null; } private void parseAllow(Attributes attributes) { if (actions != null) { modeUsage = getModeUsage(attributes); actions.addNoResultAction(new AllowAction(modeUsage)); } else modeUsage = null; } private void parseReject(Attributes attributes) { if (actions != null) { modeUsage = getModeUsage(attributes); actions.addNoResultAction(new RejectAction(modeUsage)); } else modeUsage = null; if (attributeActions != null) attributeActions.setReject(true); } private void parseContext(Attributes attributes) throws SAXException { if (anyNamespace) { error("context_any_namespace"); return; } Mode mode = getUseMode(attributes); try { Vector paths = Path.parse(attributes.getValue("", "path")); // XXX warning if modeUsage is null if (modeUsage != null) { for (int i = 0, len = paths.size(); i < len; i++) { Path path = (Path)paths.elementAt(i); if (!modeUsage.addContext(path.isRoot(), path.getNames(), mode)) error("duplicate_path", path.toString()); } } } catch (Path.ParseException e) { error(e.getMessageKey()); } } private String getSchema(Attributes attributes) throws SAXException { String schemaUri = attributes.getValue("", "schema"); if (Uri.hasFragmentId(schemaUri)) error("schema_fragment_id"); return schemaUri; } private String getSchemaType(Attributes attributes) { return attributes.getValue("", "schemaType"); } private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) { if (value == null) return defaultValue; ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER; if (value.indexOf("elements") >= 0) eoa = eoa.addElements(); if (value.indexOf("attributes") >= 0) eoa = eoa.addAttributes(); return eoa; } private ModeUsage getModeUsage(Attributes attributes) { return new ModeUsage(getUseMode(attributes), currentMode); } private Mode getUseMode(Attributes attributes) { Mode mode = getModeAttribute(attributes, "useMode"); if (mode == null) return Mode.CURRENT; mode.noteUsed(locator); return mode; } private String getNs(Attributes attributes) throws SAXException { String ns = attributes.getValue("", "ns"); if (ns != null && !Uri.isAbsolute(ns) && !ns.equals("")) error("ns_absolute"); return ns; } void error(String key) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key), locator)); } void error(String key, String arg) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } void error(String key, String arg, Locator locator) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } void error(String key, String arg1, String arg2) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator)); } } SchemaImpl(PropertyMap properties) { super(properties); this.attributesSchema = properties.contains(WrapProperty.ATTRIBUTE_OWNER); makeBuiltinMode("#allow", AllowAction.class); makeBuiltinMode("#attach", AttachAction.class); makeBuiltinMode("#unwrap", UnwrapAction.class); defaultBaseMode = makeBuiltinMode("#reject", RejectAction.class); } private Mode makeBuiltinMode(String name, Class cls) { Mode mode = lookupCreateMode(name); ActionSet actions = new ActionSet(); ModeUsage modeUsage = new ModeUsage(Mode.CURRENT, mode); if (cls == AttachAction.class) actions.setResultAction(new AttachAction(modeUsage)); else if (cls == AllowAction.class) actions.addNoResultAction(new AllowAction(modeUsage)); else if (cls == UnwrapAction.class) actions.setResultAction(new UnwrapAction(modeUsage)); else actions.addNoResultAction(new RejectAction(modeUsage)); mode.bindElement(Mode.ANY_NAMESPACE, actions); mode.noteDefined(null); AttributeActionSet attributeActions = new AttributeActionSet(); if (attributesSchema) attributeActions.setReject(true); else attributeActions.setAttach(true); mode.bindAttribute(Mode.ANY_NAMESPACE, attributeActions); return mode; } SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) { Handler h = new Handler(sr); in.setContentHandler(h); return h; } public Validator createValidator(PropertyMap properties) { return new ValidatorImpl(startMode, properties); } private Mode getModeAttribute(Attributes attributes, String localName) { return lookupCreateMode(attributes.getValue("", localName)); } private Mode lookupCreateMode(String name) { if (name == null) return null; name = name.trim(); Mode mode = (Mode)modeMap.get(name); if (mode == null) { mode = new Mode(name, defaultBaseMode); modeMap.put(name, mode); } return mode; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/SchemaReceiverImpl.java000066400000000000000000000103401225366607500330730ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.util.PropertyId; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.validate.rng.SAXSchemaReader; import com.thaiopensource.xml.util.Name; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.transform.sax.SAXSource; import java.io.IOException; import java.net.URL; class SchemaReceiverImpl implements SchemaReceiver { private static final String NRL_SCHEMA = "nrl.rng"; private static final String RNC_MEDIA_TYPE = "application/x-rnc"; private final PropertyMap properties; private final Name attributeOwner; private final SchemaReader autoSchemaReader; private Schema nrlSchema = null; private static final PropertyId subSchemaProperties[] = { ValidateProperty.ERROR_HANDLER, ValidateProperty.XML_READER_CREATOR, ValidateProperty.ENTITY_RESOLVER, SchemaReceiverFactory.PROPERTY, }; public SchemaReceiverImpl(PropertyMap properties) { this.attributeOwner = properties.get(WrapProperty.ATTRIBUTE_OWNER); PropertyMapBuilder builder = new PropertyMapBuilder(); for (int i = 0; i < subSchemaProperties.length; i++) { Object value = properties.get(subSchemaProperties[i]); if (value != null) builder.put(subSchemaProperties[i], value); } this.properties = builder.toPropertyMap(); this.autoSchemaReader = new AutoSchemaReader(properties.get(SchemaReceiverFactory.PROPERTY)); } public SchemaFuture installHandlers(XMLReader xr) { PropertyMapBuilder builder = new PropertyMapBuilder(properties); if (attributeOwner != null) builder.put(WrapProperty.ATTRIBUTE_OWNER, attributeOwner); return new SchemaImpl(builder.toPropertyMap()).installHandlers(xr, this); } Schema getNrlSchema() throws IOException, IncorrectSchemaException, SAXException { if (nrlSchema == null) { String className = SchemaReceiverImpl.class.getName(); String resourceName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + NRL_SCHEMA; URL nrlSchemaUrl = getResource(resourceName); nrlSchema = SAXSchemaReader.getInstance().createSchema(new InputSource(nrlSchemaUrl.openStream()), properties); } return nrlSchema; } private static URL getResource(String resourceName) { ClassLoader cl = SchemaReceiverImpl.class.getClassLoader(); // XXX see if we should borrow 1.2 code from Service if (cl == null) return ClassLoader.getSystemResource(resourceName); else return cl.getResource(resourceName); } PropertyMap getProperties() { return properties; } Schema createChildSchema(SAXSource source, String schemaType, PropertyMap options, boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException { SchemaReader reader = isRnc(schemaType) ? CompactSchemaReader.getInstance() : autoSchemaReader; PropertyMapBuilder builder = new PropertyMapBuilder(properties); if (isAttributesSchema) builder.put(WrapProperty.ATTRIBUTE_OWNER, ValidatorImpl.OWNER_NAME); builder.add(options); return reader.createSchema(source, builder.toPropertyMap()); } Option getOption(String uri) { Option option = autoSchemaReader.getOption(uri); if (option != null) return option; return CompactSchemaReader.getInstance().getOption(uri); } private static boolean isRnc(String schemaType) { if (schemaType == null) return false; schemaType = schemaType.trim(); return schemaType.equals(RNC_MEDIA_TYPE); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/SectionState.java000066400000000000000000000012201225366607500317660ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.nrl.ModeUsage; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; interface SectionState { /** * * @param modeUsage * @param handler may be null */ void addChildMode(ModeUsage modeUsage, ContentHandler handler); void addValidator(Schema schema, ModeUsage modeUsage); /** * * @param handler must not be null */ void addActiveHandler(ContentHandler handler, ModeUsage attributeModeUsage); void addAttributeValidationModeUsage(ModeUsage modeUsage); void reject() throws SAXException; } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/UnwrapAction.java000066400000000000000000000006451225366607500320050ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import org.xml.sax.ContentHandler; class UnwrapAction extends ResultAction { UnwrapAction(ModeUsage modeUsage) { super(modeUsage); } void perform(ContentHandler handler, SectionState state) { state.addChildMode(getModeUsage(), handler); } ResultAction changeCurrentMode(Mode mode) { return new UnwrapAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ValidateAction.java000066400000000000000000000016671225366607500322670ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.nrl.Mode; import com.thaiopensource.validate.nrl.ModeUsage; import com.thaiopensource.validate.nrl.NoResultAction; import com.thaiopensource.validate.nrl.SectionState; import org.xml.sax.SAXException; class ValidateAction extends NoResultAction { private final Schema schema; ValidateAction(ModeUsage modeUsage, Schema schema) { super(modeUsage); this.schema = schema; } void perform(SectionState state) throws SAXException { state.addValidator(schema, getModeUsage()); } NoResultAction changeCurrentMode(Mode mode) { return new ValidateAction(getModeUsage().changeCurrentMode(mode), schema); } public boolean equals(Object obj) { return super.equals(obj) && schema.equals(((ValidateAction)obj).schema); } public int hashCode() { return super.hashCode() ^ schema.hashCode(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/ValidatorImpl.java000066400000000000000000000350661225366607500321470ustar00rootroot00000000000000package com.thaiopensource.validate.nrl; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.xml.util.Name; 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.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import java.util.Enumeration; import java.util.Hashtable; import java.util.Stack; import java.util.Vector; class ValidatorImpl extends DefaultHandler implements Validator { static final Name OWNER_NAME = new Name("http://www.thaiopensource.com/validate/nrl/instance", "owner"); private static final String NO_NS = "\0"; private final ErrorHandler eh; private final PropertyMap properties; private Locator locator; private Section currentSection; private PrefixMapping prefixMapping = null; private final Hashtable validatorHandlerCache = new Hashtable(); private final Localizer localizer = new Localizer(ValidatorImpl.class); private final Hashset noResultActions = new Hashset(); private final Hashtable attributeNamespaceIndexSets = new Hashtable(); private final Vector activeHandlersAttributeIndexSets = new Vector(); private final Hashset attributeSchemas = new Hashset(); private boolean attributeNamespaceRejected; private Attributes filteredAttributes; private final Mode startMode; static private class PrefixMapping { final String prefix; final String uri; final PrefixMapping parent; PrefixMapping(String prefix, String uri, PrefixMapping parent) { this.prefix = prefix; this.uri = uri; this.parent = parent; } } private class Section implements SectionState { final Section parent; /** * Namespace of this section. Empty string for absent. */ final String ns; /** * Number of open elements in this section. */ int depth = 0; /** * List of the Validators rooted in this section */ final Vector validators = new Vector(); final Vector schemas = new Vector(); /** * List of the ContentHandlers that want to see the elements in this section */ final Vector activeHandlers = new Vector(); final Vector activeHandlersAttributeModeUsage = new Vector(); final Vector attributeValidationModeUsages = new Vector(); /** * List of Programs saying what to do with child sections */ final Vector childPrograms = new Vector(); final Stack context = new Stack(); boolean contextDependent = false; int attributeProcessing = Mode.ATTRIBUTE_PROCESSING_NONE; Section(String ns, Section parent) { this.ns = ns; this.parent = parent; } public void addChildMode(ModeUsage modeUsage, ContentHandler handler) { childPrograms.addElement(new Program(modeUsage, handler)); if (modeUsage.isContextDependent()) contextDependent = true; } public void addValidator(Schema schema, ModeUsage modeUsage) { schemas.addElement(schema); Validator validator = createValidator(schema); validators.addElement(validator); activeHandlers.addElement(validator.getContentHandler()); activeHandlersAttributeModeUsage.addElement(modeUsage); attributeProcessing = Math.max(attributeProcessing, modeUsage.getAttributeProcessing()); childPrograms.addElement(new Program(modeUsage, validator.getContentHandler())); if (modeUsage.isContextDependent()) contextDependent = true; } public void addActiveHandler(ContentHandler handler, ModeUsage attributeModeUsage) { activeHandlers.addElement(handler); activeHandlersAttributeModeUsage.addElement(attributeModeUsage); attributeProcessing = Math.max(attributeProcessing, attributeModeUsage.getAttributeProcessing()); if (attributeModeUsage.isContextDependent()) contextDependent = true; } public void addAttributeValidationModeUsage(ModeUsage modeUsage) { int ap = modeUsage.getAttributeProcessing(); if (ap != Mode.ATTRIBUTE_PROCESSING_NONE) { attributeValidationModeUsages.addElement(modeUsage); attributeProcessing = Math.max(ap, attributeProcessing); if (modeUsage.isContextDependent()) contextDependent = true; } } public void reject() throws SAXException { if (eh != null) eh.error(new SAXParseException(localizer.message("reject_element", ns), locator)); } } static private class Program { final ModeUsage modeUsage; final ContentHandler handler; Program(ModeUsage modeUsage, ContentHandler handler) { this.modeUsage = modeUsage; this.handler = handler; } } ValidatorImpl(Mode mode, PropertyMap properties) { this.properties = properties; this.eh = properties.get(ValidateProperty.ERROR_HANDLER); this.startMode = mode; initCurrentSection(); } private void initCurrentSection() { currentSection = new Section(NO_NS, null); currentSection.addChildMode(new ModeUsage(startMode, startMode), null); } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void characters(char ch[], int start, int length) throws SAXException { for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).characters(ch, start, length); } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).ignorableWhitespace(ch, start, length); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (!uri.equals(currentSection.ns)) startSection(uri); currentSection.depth++; if (currentSection.contextDependent) currentSection.context.push(localName); boolean transformAttributes = processAttributes(attributes); for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) { ContentHandler handler = (ContentHandler)(currentSection.activeHandlers.elementAt(i)); handler.startElement(uri, localName, qName, transformAttributes ? filterAttributes((IntSet)activeHandlersAttributeIndexSets.elementAt(i), attributes) : attributes); } } private static Attributes filterAttributes(IntSet indexSet, Attributes attributes) { if (indexSet.size() == attributes.getLength()) return attributes; return new FilteredAttributes(indexSet, attributes); } private boolean processAttributes(Attributes attributes) throws SAXException { if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_NONE || attributes.getLength() == 0) return false; attributeNamespaceIndexSets.clear(); for (int i = 0, len = attributes.getLength(); i < len; i++) { String ns = attributes.getURI(i); IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); if (indexSet == null) { indexSet = new IntSet(); attributeNamespaceIndexSets.put(ns, indexSet); } indexSet.add(i); } if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_QUALIFIED && attributeNamespaceIndexSets.size() == 1 && attributeNamespaceIndexSets.get("") != null) return false; Vector handlerModes = currentSection.activeHandlersAttributeModeUsage; activeHandlersAttributeIndexSets.setSize(handlerModes.size()); for (int i = 0, len = handlerModes.size(); i < len; i++) activeHandlersAttributeIndexSets.setElementAt(new IntSet(), i); boolean transform = false; Vector validationModes = currentSection.attributeValidationModeUsages; for (Enumeration e = attributeNamespaceIndexSets.keys(); e.hasMoreElements();) { String ns = (String)e.nextElement(); IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); attributeSchemas.clear(); filteredAttributes = null; attributeNamespaceRejected = false; for (int i = 0, len = handlerModes.size(); i < len; i++) { ModeUsage modeUsage = (ModeUsage)handlerModes.elementAt(i); AttributeActionSet actions = processAttributeSection(modeUsage, ns, indexSet, attributes); if (actions.getAttach()) ((IntSet)activeHandlersAttributeIndexSets.get(i)).addAll(indexSet); else transform = true; } for (int i = 0, len = validationModes.size(); i < len; i++) { ModeUsage modeUsage = (ModeUsage)validationModes.elementAt(i); processAttributeSection(modeUsage, ns, indexSet, attributes); } } return transform; } private AttributeActionSet processAttributeSection(ModeUsage modeUsage, String ns, IntSet indexSet, Attributes attributes) throws SAXException { Mode mode = modeUsage.getMode(currentSection.context); AttributeActionSet actions = mode.getAttributeActions(ns); if (actions.getReject() && !attributeNamespaceRejected) { attributeNamespaceRejected = true; if (eh != null) eh.error(new SAXParseException(localizer.message("reject_attribute", ns), locator)); } Schema[] schemas = actions.getSchemas(); for (int j = 0; j < schemas.length; j++) { if (attributeSchemas.contains(schemas[j])) continue; attributeSchemas.add(schemas[j]); if (filteredAttributes == null) filteredAttributes = filterAttributes(indexSet, attributes); validateAttributes(schemas[j], filteredAttributes); } return actions; } private void validateAttributes(Schema schema, Attributes attributes) throws SAXException { Validator validator = createValidator(schema); ContentHandler ch = validator.getContentHandler(); initHandler(ch); ch.startElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName(), attributes); ch.endElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName()); cleanupHandler(ch); releaseValidator(schema, validator); } private void startSection(String uri) throws SAXException { Section section = new Section(uri, currentSection); Vector childPrograms = currentSection.childPrograms; noResultActions.clear(); for (int i = 0, len = childPrograms.size(); i < len; i++) { Program program = (Program)childPrograms.elementAt(i); ActionSet actions = program.modeUsage.getMode(currentSection.context).getElementActions(uri); ResultAction resultAction = actions.getResultAction(); if (resultAction != null) resultAction.perform(program.handler, section); NoResultAction[] nra = actions.getNoResultActions(); for (int j = 0; j < nra.length; j++) { NoResultAction tem = nra[j]; if (!noResultActions.contains(tem)) { nra[j].perform(section); noResultActions.add(tem); } } } for (int i = 0, len = section.validators.size(); i < len; i++) initHandler(((Validator)section.validators.elementAt(i)).getContentHandler()); currentSection = section; } private void initHandler(ContentHandler ch) throws SAXException { if (locator != null) ch.setDocumentLocator(locator); ch.startDocument(); for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) ch.startPrefixMapping(pm.prefix, pm.uri); } public void endElement(String uri, String localName, String qName) throws SAXException { for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).endElement(uri, localName, qName); currentSection.depth--; if (currentSection.contextDependent) currentSection.context.pop(); if (currentSection.depth == 0) endSection(); } private void endSection() throws SAXException { for (int i = 0, len = currentSection.validators.size(); i < len; i++) { Validator validator = (Validator)currentSection.validators.elementAt(i); cleanupHandler(validator.getContentHandler()); releaseValidator((Schema)currentSection.schemas.elementAt(i), validator); // endDocument() on one of the validators may throw an exception // in this case we don't want to release the validator twice currentSection.validators.setElementAt(null, i); } currentSection = currentSection.parent; } private void cleanupHandler(ContentHandler vh) throws SAXException { for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) vh.endPrefixMapping(pm.prefix); vh.endDocument(); } public void endDocument() throws SAXException { } public void startPrefixMapping(String prefix, String uri) throws SAXException { super.startPrefixMapping(prefix, uri); prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); } public void endPrefixMapping(String prefix) throws SAXException { super.endPrefixMapping(prefix); prefixMapping = prefixMapping.parent; } private Validator createValidator(Schema schema) { Stack stack = (Stack)validatorHandlerCache.get(schema); if (stack == null) { stack = new Stack(); validatorHandlerCache.put(schema, stack); } if (stack.empty()) return schema.createValidator(properties); return (Validator)stack.pop(); } private void releaseValidator(Schema schema, Validator vh) { if (vh == null) return; vh.reset(); ((Stack)validatorHandlerCache.get(schema)).push(vh); } public void reset() { for (; currentSection != null; currentSection = currentSection.parent) { for (int i = 0, len = currentSection.validators.size(); i < len; i++) releaseValidator((Schema)currentSection.schemas.elementAt(i), (Validator)currentSection.validators.elementAt(i)); } initCurrentSection(); } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return this; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/resources/000077500000000000000000000000001225366607500305355ustar00rootroot00000000000000Messages.properties000066400000000000000000000030431225366607500343430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/resourcesreject_element=elements from namespace \"{0}\" are not allowed reject_attribute=attributes from namespace \"{0}\" are not allowed undefined_mode=mode \"{0}\" not defined schema_fragment_id=schema URI must not have a fragment identifier ns_absolute=namespace URI must be absolute URI unexpected_slash=unexpected \"/\" expected_slash=expected \"/\" expected_name=expected a name empty_path=empty path invalid_name=invalid name duplicate_path=context with path \"{0}\" already defined context_any_namespace=\"context\" not allowed within \"anyNamespace\" duplicate_mode=mode \"{0}\" already defined first_mode=mode \"{0}\" was first defined here duplicate_attribute_action_any_namespace=rule for attributes from any namespace already specified in this mode duplicate_attribute_action=rule for attributes from namespace \"{0}\" already specified in this mode duplicate_element_action_any_namespace=rule for elements from any namespace already specified in this mode duplicate_element_action=rule for elements from namespace \"{0}\" already specified in this mode mode_cycle=mode \"{0}\" directly or indirectly extends itself unknown_option=option \"{0}\" not recognized unsupported_option=option \"{0}\" is not supported for this kind of schema unsupported_option_arg=specified argument for option \"{0}\" is not supported duplicate_option=option \"{0}\" cannot be specified more than once option_requires_argument=option \"{0}\" requires an argument option_unexpected_argument=option \"{0}\" does not take an argument option_bad_argument=invalid argument for option \"{0}\" jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nrl/resources/nrl.rng000066400000000000000000000132471225366607500320470ustar00rootroot00000000000000 elements attributes attributes elements elements attributes allow reject attach unwrap #attach #allow #reject #unwrap \s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*(|\s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*)* jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/000077500000000000000000000000001225366607500266735ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/Action.java000066400000000000000000000016161225366607500307570ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; /** * Base action class. */ abstract class Action { /** * Use mode when performing this action. */ private final ModeUsage modeUsage; /** * Creates an action with a given mode usage. * @param modeUsage The mode usage. */ Action(ModeUsage modeUsage) { this.modeUsage = modeUsage; } /** * Getter for the mode usage. * @return The mode usage for this action. */ ModeUsage getModeUsage() { return modeUsage; } /** * Checks for equality, we need to have the same action class with the same modeUsage. */ public boolean equals(Object obj) { return obj != null && obj.getClass() == getClass() && ((Action)obj).modeUsage.equals(modeUsage); } /** * Computes a hashCode for this action. */ public int hashCode() { return getClass().hashCode() ^ modeUsage.hashCode(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ActionSet.java000066400000000000000000000045721225366607500314370ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; /** * Stores a set of element actions. * The actions are result actions and no result actions. * An action set contains only one result action and more no result actions. * */ class ActionSet { /** * The result action. */ private ResultAction resultAction; /** * The no result actions. */ private NoResultAction[] noResultActions = new NoResultAction[0]; /** * Cancel nested actions flag. */ private boolean cancelNestedActions; /** * Getter for the result action. * @return The result action. */ ResultAction getResultAction() { return resultAction; } /** * Setter for the result action. * @param resultAction The result action. */ void setResultAction(ResultAction resultAction) { this.resultAction = resultAction; } /** * Adds a no result action to the no result actions. * @param action The no result action. */ void addNoResultAction(NoResultAction action) { NoResultAction[] actions = new NoResultAction[noResultActions.length + 1]; System.arraycopy(noResultActions, 0, actions, 0, noResultActions.length); actions[noResultActions.length] = action; noResultActions = actions; } /** * Getter for the no result actions array. * @return The no result actions. */ NoResultAction[] getNoResultActions() { return noResultActions; } /** * Getter for the cancel nested actions flag. */ boolean getCancelNestedActions() { return cancelNestedActions; } /** * Set the cancel nested actions flag. * @param cancelNestedActions The new value. */ void setCancelNestedActions(boolean cancelNestedActions) { this.cancelNestedActions = cancelNestedActions; } /** * Gets a new ActionSet containing all the actions with the * current mode changed. * * @param mode The new current mode. * @return A new ActionSet with actions with the current mode changed. */ ActionSet changeCurrentMode(Mode mode) { ActionSet actions = new ActionSet(); if (this.resultAction != null) actions.resultAction = this.resultAction.changeCurrentMode(mode); actions.noResultActions = new NoResultAction[this.noResultActions.length]; for (int i = 0; i < actions.noResultActions.length; i++) actions.noResultActions[i] = this.noResultActions[i].changeCurrentMode(mode); return actions; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/AllowAction.java000066400000000000000000000016071225366607500317560ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; /** * An action that allows any element. */ class AllowAction extends NoResultAction { /** * Creates this no result action with a given mode usage. * @param modeUsage The mode usage. */ AllowAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action on the section state. * @param state The section state. */ void perform(SectionState state) { state.addChildMode(getModeUsage(), null); state.addAttributeValidationModeUsage(getModeUsage()); } /** * Get a new allow action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ NoResultAction changeCurrentMode(Mode mode) { return new AllowAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/AttachAction.java000066400000000000000000000021641225366607500321030ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.ContentHandler; /** * Result attach action. * Attaches elements to the section. */ class AttachAction extends ResultAction { /** * Creates an attach action with a given mode usage. * @param modeUsage The mode usage. */ AttachAction(ModeUsage modeUsage) { super(modeUsage); } /** * Performs this action on the section state. * * @param handler ??? * @param state The section state. */ void perform(ContentHandler handler, SectionState state) { final ModeUsage modeUsage = getModeUsage(); if (handler != null) state.addActiveHandler(handler, modeUsage); else state.addAttributeValidationModeUsage(modeUsage); state.addChildMode(modeUsage, handler); } /** * Get a new attach action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ ResultAction changeCurrentMode(Mode mode) { return new AttachAction(getModeUsage().changeCurrentMode(mode)); } } AttachPlaceholderAction.java000066400000000000000000000021471225366607500341700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import org.xml.sax.ContentHandler; /** * Attach place holder result action. * This action replaces a section with a placeholder element. */ class AttachPlaceholderAction extends ResultAction { /** * Creates an attachPlaceHolder action with a given mode usage. * * @param modeUsage * The action mode usage. */ AttachPlaceholderAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action. * * @param handler * the handler this action is performed on * @param state * the section state. */ void perform(ContentHandler handler, SectionState state) { state.attachPlaceholder(getModeUsage(), handler); } /** * Get a new attach place holder action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ ResultAction changeCurrentMode(Mode mode) { return new AttachPlaceholderAction(getModeUsage().changeCurrentMode(mode)); } } AttributeActionSet.java000066400000000000000000000034231225366607500332360ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import com.thaiopensource.validate.Schema; /** * Action set for attributes. * Consistes of two flags (attach, reject) and a list of schemas. */ class AttributeActionSet { /** * Attach flag. */ private boolean attach; /** * Reject flag. */ private boolean reject; /** * Cancel nested actions flag. */ private boolean cancelNestedActions; /** * An array of schemas. */ private Schema[] schemas = new Schema[0]; /** * Getter for the attach flag. * @return attach. */ boolean getAttach() { return attach; } /** * Setter for the attach flag. * * @param attach The new attach value. */ void setAttach(boolean attach) { this.attach = attach; } /** * Getter for the reject flag. * @return reject. */ boolean getReject() { return reject; } /** * Setter for the reject flag. * @param reject The new reject flag value. */ void setReject(boolean reject) { this.reject = reject; } /** * Getter for the cancel nested actions flag. */ boolean getCancelNestedActions() { return cancelNestedActions; } /** * Set the cancel nested actions flag. * @param cancelNestedActions The new value. */ void setCancelNestedActions(boolean cancelNestedActions) { this.cancelNestedActions = cancelNestedActions; } /** * Get the schemas array. * @return The array of Schema objects. */ Schema[] getSchemas() { return schemas; } /** * Add a new Schema. * @param schema The schema to be added. */ void addSchema(Schema schema) { Schema[] s = new Schema[schemas.length + 1]; System.arraycopy(schemas, 0, s, 0, schemas.length); s[schemas.length] = schema; schemas = s; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ContextMap.java000066400000000000000000000171451225366607500316300ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.util.Equal; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; import java.util.NoSuchElementException; /** * Keeps modes depending on context. * The structure of the context map is * * stores the mode for * / in rootValue * "" in otherValue (this is for relative paths) * stores a hash with the last path elements as key and * ContextMap objects as values. * * A path like a/b and mode x * will be represented by 3 ContextMap objects * ContextMap b ---> ContextMap a ---> ContextMap otherValue=x * * Addind also /a/b and mode y will give * * ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y) * * Adding a2/b and mode w will give * * ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y) * a2 ---> ContextMap otherValue=w */ class ContextMap { /** * Stores the mode associated with an absolute path. */ private Object rootValue; /** * Stores a mode associated with a relative path. */ private Object otherValue; /** * Stores a hash map with with the key the last local name and * as values other ContextMap objects. */ private final Hashtable nameTable = new Hashtable(); /** * Get the mode matching a list of local names. * A root more returned means an exact matching of the given local names * with the local names from the context map. Otherwise we can get either * a mode stored as otherValue or null if the given context does not match * any of the stored paths. * @param context The list of local names that represent a section context * (path from root local element names from the same namespace). * @return A mode or null. */ Object get(Vector context) { return get(context, context.size()); } /** * Adds a single path (isRoot, names) and a mode to be used for this path = context. * @param isRoot True if the path starts with / * @param names The local names that form the path. * @param value The mode. * @return true if there is no duplicate path, false otherwise. */ boolean put(boolean isRoot, Vector names, Object value) { return put(isRoot, names, names.size(), value); } /** * Get the mode matching a list of local names. * A root more returned means an exact matching of the given local names * with the local names from the context map. Otherwise we can get either * a mode stored as otherValue or null if the given context does not match * any of the stored paths. * @param context The list of local names that represent a section context * (path from root local element names from the same namespace). * @param len The lenght we should take from the list. * @return A mode or null. */ private Object get(Vector context, int len) { if (len > 0) { ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1)); if (nestedMap != null) { Object value = nestedMap.get(context, len - 1); if (value != null) return value; } } if (rootValue != null && len == 0) return rootValue; return otherValue; } /** * Adds a single path (isRoot, names) and a mode to be used for this path = context. * @param isRoot True if the path starts with / * @param names The local names that form the path. * @param len The length if the names vector. * @param value The mode. * @return true if there is no duplicate path, false otherwise. */ private boolean put(boolean isRoot, Vector names, int len, Object value) { if (len == 0) { // if we have only / if (isRoot) { if (rootValue != null) return false; rootValue = value; } // We followed all the paths, it is not root, // then we store the mode as the other value. else { if (otherValue != null) return false; otherValue = value; } return true; } else { // get the last local name from the path Object name = names.elementAt(len - 1); // Get the context map mapped in nameTable to that name. ContextMap nestedMap = (ContextMap)nameTable.get(name); // Not preset then create it. if (nestedMap == null) { nestedMap = new ContextMap(); nameTable.put(name, nestedMap); } // Add the rest of the path names in the nested context map. return nestedMap.put(isRoot, names, len - 1, value); } } /** * Chek that this context map is equals with * a specified context map. */ public boolean equals(Object obj) { if (!(obj instanceof ContextMap)) return false; ContextMap other = (ContextMap)obj; if (!Equal.equal(this.rootValue, other.rootValue) || !Equal.equal(this.otherValue, other.otherValue)) return false; // We want jing to work with JDK 1.1 so we cannot use Hashtable.equals if (this.nameTable.size() != other.nameTable.size()) return false; for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { Object key = e.nextElement(); if (!nameTable.get(key).equals(other.nameTable.get(key))) return false; } return true; } /** * Get a hashcode for this context map. */ public int hashCode() { int hc = 0; if (rootValue != null) hc ^= rootValue.hashCode(); if (otherValue != null) hc ^= otherValue.hashCode(); for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { Object key = e.nextElement(); hc ^= key.hashCode(); hc ^= nameTable.get(key).hashCode(); } return hc; } /** * Creates an Enumeration implementation that enumerates all the * modes stored in this context map and in the nested context maps. */ static private class Enumerator implements Enumeration { /** * Store this context map root value. */ private Object rootValue; /** * Store this context map other value. */ private Object otherValue; /** * Stores the enumeration of modes of the current subMap. */ private Enumeration subMapValues; /** * Stores the ContextMap objects from the nameTable. */ private final Enumeration subMaps; private Enumerator(ContextMap map) { rootValue = map.rootValue; otherValue = map.otherValue; subMaps = map.nameTable.elements(); } /** * Advance to the next context map values * in subMapValues and to the next element * in subMap enumeration, if needed. */ private void prep() { while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements()) subMapValues = ((ContextMap)subMaps.nextElement()).values(); } /** * True if we have more elements. */ public boolean hasMoreElements() { prep(); return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements()); } /** * Get the next element (mode in this case). */ public Object nextElement() { if (rootValue != null) { Object tem = rootValue; rootValue = null; return tem; } if (otherValue != null) { Object tem = otherValue; otherValue = null; return tem; } prep(); if (subMapValues == null) throw new NoSuchElementException(); return subMapValues.nextElement(); } } /** * Get an enumeration with all the modes in this context map. * @return An enumeration containing Mode objects. */ Enumeration values() { return new Enumerator(this); } } ElementsOrAttributes.java000066400000000000000000000041571225366607500336120ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; /** * Possible values for match, that is represented as a list of elements and attributes. */ class ElementsOrAttributes { /** * Flag for elements. */ private static final int ELEMENTS_FLAG = 01; /** * Flag for attributes. */ private static final int ATTRIBUTES_FLAG = 02; // Define constants for all possible values. /** * Neither elements nor attributes specified. */ static final ElementsOrAttributes NEITHER = new ElementsOrAttributes(0); /** * Only elements is specified. */ static final ElementsOrAttributes ELEMENTS = new ElementsOrAttributes(ELEMENTS_FLAG); /** * Only attributes is specified. */ static final ElementsOrAttributes ATTRIBUTES = new ElementsOrAttributes(ATTRIBUTES_FLAG); /** * Bothe elements and attributes are specified. */ static final ElementsOrAttributes BOTH = new ElementsOrAttributes(ELEMENTS_FLAG|ATTRIBUTES_FLAG); /** * All possible values. */ private static final ElementsOrAttributes values[] = { NEITHER, ELEMENTS, ATTRIBUTES, BOTH }; /** * Stores this instance flags. */ private int flags = 0; /** * Creates an instance with the given flags. * @param flags */ private ElementsOrAttributes(int flags) { this.flags = flags; } /** * Get the value after adding elements to the current instance. * @return The value that matches also elements. */ ElementsOrAttributes addElements() { return values[flags | ELEMENTS_FLAG]; } /** * Get the value after adding attributes to the current instance. * @return The value that matches also attributes. */ ElementsOrAttributes addAttributes() { return values[flags | ATTRIBUTES_FLAG]; } /** * Checks whether the attributes are matched or not. * @return true is attributes are matched. */ boolean containsAttributes() { return (flags & ATTRIBUTES_FLAG) != 0; } /** * Checks whether the elements are matched or not. * @return true is elements are matched. */ boolean containsElements() { return (flags & ELEMENTS_FLAG) != 0; } } FilteredAttributes.java000066400000000000000000000121741225366607500332710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import org.xml.sax.Attributes; /** * Implementation of the Attributes interface that filters out some of the * attributes of an actual Attributes implementation. We will keep only the * attributes whose indexes are specified in a given set of indexes. */ class FilteredAttributes implements Attributes { /** * The actual attributes, we will filter out some of them. */ private final Attributes attributes; /** * The set of indexes of the attributes to used. */ private final IntSet indexSet; /** * Maps indexes in the real attributes list to 1 based indexes in the * filtered attributes list. For instance if we keep only the * 1st and the 3rd attributes from 4 attributes then the * reverse index map will have as values * [0] --> 1 * [1] --> 0 * [2] --> 2 * [3] --> 0 * */ private int[] reverseIndexMap; /** * Creates a filtered attributes instance. * @param indexSet The set with indexes that we will keep. * @param attributes The actual attributes. */ public FilteredAttributes(IntSet indexSet, Attributes attributes) { this.indexSet = indexSet; this.attributes = attributes; } /** * Gets the index in the filtered set for a given real index. * If the reverseIndexMap is not computed it computes it, * otherwise it just uses the previously computed map. * @param k The index in the real attributes. * @return The index in the filtered attributes. */ private int reverseIndex(int k) { if (reverseIndexMap == null) { reverseIndexMap = new int[attributes.getLength()]; for (int i = 0, len = indexSet.size(); i < len; i++) reverseIndexMap[indexSet.get(i)] = i + 1; } return reverseIndexMap[k] - 1; } /** * The number of attributes, the same as the length of the list of indexes. */ public int getLength() { return indexSet.size(); } /** * Get the URI for the index-th attribute. */ public String getURI(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getURI(indexSet.get(index)); } /** * Get the local name for the index-th attribute. */ public String getLocalName(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getLocalName(indexSet.get(index)); } /** * Get the QName for the index-th attribute. */ public String getQName(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getQName(indexSet.get(index)); } /** * Get the type for the index-th attribute. */ public String getType(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getType(indexSet.get(index)); } /** * Get the value for the index-th attribute. */ public String getValue(int index) { if (index < 0 || index >= indexSet.size()) return null; return attributes.getValue(indexSet.get(index)); } public int getIndex(String uri, String localName) { int n = attributes.getIndex(uri, localName); if (n < 0) return n; return reverseIndex(n); } public int getIndex(String qName) { int n = attributes.getIndex(qName); if (n < 0) return n; return reverseIndex(n); } /** * Get the real index, in the initial attributes list of a given attribute. * If the attribute is filtered out then return -1. * @param uri The attribute uri. * @param localName The attribute local name. * @return The real index if the attribute is present and not filtered out, otherwise -1. */ private int getRealIndex(String uri, String localName) { int index = attributes.getIndex(uri, localName); if (index < 0 || reverseIndex(index) < 0) return -1; return index; } /** * Get the real index, in the initial attributes list of a given attribute. * If the attribute is filtered out then return -1. * @param qName The attribute qualified name. * @return The real index if the attribute is present and not filtered out, otherwise -1. */ private int getRealIndex(String qName) { int index = attributes.getIndex(qName); if (index < 0 || reverseIndex(index) < 0) return -1; return index; } /** * Get the type of the attribute. * @param uri The attribute uri. * @param localName The attribute local name. */ public String getType(String uri, String localName) { return attributes.getType(getRealIndex(uri, localName)); } /** * Get the value of the attribute. * @param uri The attribute uri. * @param localName The attribute local name. */ public String getValue(String uri, String localName) { return attributes.getValue(getRealIndex(uri, localName)); } /** * Get the type of the attribute. * @param qName The attribute qualified name. */ public String getType(String qName) { return attributes.getType(getRealIndex(qName)); } /** * Get the value of the attribute. * @param qName The attribute qualified name. */ public String getValue(String qName) { return attributes.getValue(getRealIndex(qName)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/Hashset.java000066400000000000000000000022651225366607500311420ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import java.util.Hashtable; import java.util.Enumeration; /** * Utility class, stores a set of objects. * It uses a Hashtable for internal storage. */ class Hashset { /** * The internal storage, a hashtable. */ private final Hashtable table = new Hashtable(); /** * Test if an object belongs to this set or not. * @param key The object. * @return true if the object is contained in this set. */ boolean contains(Object key) { return table.get(key) != null; } /** * Adds an object to this set. * @param key The object to be added. */ void add(Object key) { table.put(key, key); } /** * Adds all the objects from another set to this set - union. * @param set The other set. */ void addAll(Hashset set) { for (Enumeration e = set.table.keys(); e.hasMoreElements();) add(e.nextElement()); } /** * Removes all the objects from this set. */ void clear() { table.clear(); } /** * Get an enumeration will all the objects from this set. * @return an enumeration with all the objects from this set. */ Enumeration members() { return table.keys(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/IntSet.java000066400000000000000000000037361225366607500307550ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; /** * Utility class. Stores a set of integers. * The set is stored in an array and sorted. */ class IntSet { /** * Initial size. */ static private final int INIT_SIZE = 4; /** * An int array with the values. */ private int[] v = null; /** * The number of stored values. */ private int len = 0; /** * Add a new value. * @param n The value to be added. */ void add(int n) { if (v == null) { v = new int[INIT_SIZE]; v[0] = n; len = 1; return; } if (len == v.length) { int[] newv = new int[len*2]; System.arraycopy(v, 0, newv, 0, len); v = newv; } if (n > v[len - 1]) { v[len++] = n; return; } int i = 0; for (; i < len; i++) { if (n <= v[i]) { if (n == v[i]) return; break; } } for (int j = len; j >= i; j--) v[j + 1] = v[j]; v[i] = n; ++len; } /** * Adds all the values from another set - union. * @param is The other integer set. */ void addAll(IntSet is) { if (is.len == 0) return; int[] newv = new int[len + is.len]; int i = 0, j = 0, k = 0; while (i < len && j < is.len) { if (v[i] < is.v[j]) newv[k++] = v[i++]; else if (is.v[j] < v[i]) newv[k++] = is.v[j++]; else { newv[k++] = v[i++]; j++; } } while (i < len) newv[k++] = v[i++]; while (j < is.len) newv[k++] = is.v[j++]; v = newv; len = k; } /** * Get the number of values in this set. * @return */ int size() { return len; } /** * Get the ith value from the set. * @param i The index in the set, zero based. * @return The value at position i. */ int get(int i) { if (i >= len) throw new IndexOutOfBoundsException(); try { return v[i]; } catch (NullPointerException e) { throw new IndexOutOfBoundsException(); } } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/Mode.java000066400000000000000000000300741225366607500304260ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.Locator; import org.xml.sax.helpers.LocatorImpl; import java.util.Hashtable; import java.util.Enumeration; import java.util.ArrayList; import java.util.Iterator; import java.util.List; class Mode { static final int ATTRIBUTE_PROCESSING_NONE = 0; static final int ATTRIBUTE_PROCESSING_QUALIFIED = 1; static final int ATTRIBUTE_PROCESSING_FULL = 2; /** * A special mode. In a mode usage this will be * resolved by the mode usage to the actual current mode * from that mode usage. */ static final Mode CURRENT = new Mode("#current", null); /** * Mode name prefix used for inline anonymous modes. */ private static final String ANONYMOUS_MODE_NAME_PREFIX = "#anonymous#"; /** * Inline anonymous modes counter. */ private static int anonymousModeCounter = 0; /** * Flag for anonymous modes. */ private boolean anonymous; /** * The mode name. */ private final String name; /** * The base mode. */ private Mode baseMode; /** * Flag indicating if this mode is defined by the user * or is an automatically generated mode. */ private boolean defined; /** * Locate the place where this mode is defined. */ private Locator whereDefined; /** * Locate the place this mode is first used. * Useful to report with location errors like * 'Mode "xxx" not defined'. */ private Locator whereUsed; private final Hashtable elementMap = new Hashtable(); private final Hashtable attributeMap = new Hashtable(); private int attributeProcessing = -1; /** * Namespace specification elements map. */ private final Hashtable nssElementMap = new Hashtable(); /** * Namespace specification attributes map. */ private final Hashtable nssAttributeMap = new Hashtable(); /** * List with included modes. */ private List includedModes = new ArrayList(); void addIncludedMode(Mode mode) { includedModes.add(mode); } /** * Creates a mode extending a base mode. * @param name The new mode name. * @param baseMode The base mode. */ Mode(String name, Mode baseMode) { this.name = name; this.baseMode = baseMode; } /** * Creates an anonymous mode. * @param baseMode */ public Mode(Mode baseMode) { this(ANONYMOUS_MODE_NAME_PREFIX+anonymousModeCounter++, baseMode); anonymous = true; } /** * Get this mode name. * @return The name. */ String getName() { return name; } /** * Get the base mode. * @return The base mode. */ Mode getBaseMode() { return baseMode; } /** * Set a base mode. * @param baseMode The new base mode. */ void setBaseMode(Mode baseMode) { this.baseMode = baseMode; } /** * Get the set of element actions for a given namespace. * If this mode has an explicit handling of that namespace then we get those * actions, otherwise we get the actions for any namespace. * @param ns The namespace we look for element actions for. * @return A set of element actions. */ ActionSet getElementActions(String ns) { ActionSet actions = getElementActionsExplicit(ns); if (actions == null) { actions = getElementActionsExplicit(NamespaceSpecification.ANY_NAMESPACE); // this is not correct: it breaks a derived mode that use anyNamespace // elementMap.put(ns, actions); } return actions; } /** * Look for element actions specifically specified * for this namespace. If the current mode does not have * actions for that namespace look at base modes. If the actions * are defined in a base mode we need to get a copy of those actions * associated with this mode, so we call changeCurrentMode on them. * * @param ns The namespace * @return A set of element actions. */ private ActionSet getElementActionsExplicit(String ns) { ActionSet actions = (ActionSet)elementMap.get(ns); if (actions==null) { // iterate namespace specifications. for (Enumeration e = nssElementMap.keys(); e.hasMoreElements() && actions==null;) { NamespaceSpecification nssI = (NamespaceSpecification)e.nextElement(); // If a namespace specification convers the current namespace URI then we get those actions. if (nssI.covers(ns)) { actions = (ActionSet)nssElementMap.get(nssI); } } // Store them in the element Map for faster access next time. if (actions!=null) { elementMap.put(ns, actions); } } // Look into the included modes if (actions == null && includedModes != null) { Iterator i = includedModes.iterator(); while (actions == null && i.hasNext()) { Mode includedMode = (Mode)i.next(); actions = includedMode.getElementActionsExplicit(ns); } if (actions != null) { actions = actions.changeCurrentMode(this); elementMap.put(ns, actions); } } // No actions specified, look into the base mode. if (actions == null && baseMode != null) { actions = baseMode.getElementActionsExplicit(ns); if (actions != null) { actions = actions.changeCurrentMode(this); elementMap.put(ns, actions); } } if (actions!=null && actions.getCancelNestedActions()) { actions = null; } return actions; } /** * Get the set of attribute actions for a given namespace. * If this mode has an explicit handling of that namespace then we get those * actions, otherwise we get the actions for any namespace. * @param ns The namespace we look for attribute actions for. * @return A set of attribute actions. */ AttributeActionSet getAttributeActions(String ns) { AttributeActionSet actions = getAttributeActionsExplicit(ns); if (actions == null) { actions = getAttributeActionsExplicit(NamespaceSpecification.ANY_NAMESPACE); // this is not correct: it breaks a derived mode that use anyNamespace // attributeMap.put(ns, actions); } return actions; } /** * Look for attribute actions specifically specified * for this namespace. If the current mode does not have * actions for that namespace look at base modes. If the actions * are defined in a base mode we need to get a copy of those actions * associated with this mode, so we call changeCurrentMode on them. * * @param ns The namespace * @return A set of attribute actions. */ private AttributeActionSet getAttributeActionsExplicit(String ns) { AttributeActionSet actions = (AttributeActionSet)attributeMap.get(ns); if (actions==null) { // iterate namespace specifications. for (Enumeration e = nssAttributeMap.keys(); e.hasMoreElements() && actions==null;) { NamespaceSpecification nssI = (NamespaceSpecification)e.nextElement(); // If a namespace specification convers the current namespace URI then we get those actions. if (nssI.covers(ns)) { actions = (AttributeActionSet)nssAttributeMap.get(nssI); } } // Store them in the element Map for faster access next time. if (actions!=null) { attributeMap.put(ns, actions); } } // Look into the included modes if (actions == null && includedModes != null) { Iterator i = includedModes.iterator(); while (actions == null && i.hasNext()) { Mode includedMode = (Mode)i.next(); actions = includedMode.getAttributeActionsExplicit(ns); } if (actions != null) { attributeMap.put(ns, actions); } } if (actions == null && baseMode != null) { actions = baseMode.getAttributeActionsExplicit(ns); if (actions != null) attributeMap.put(ns, actions); } if (actions!=null && actions.getCancelNestedActions()) { actions = null; } return actions; } /** * Computes (if not already computed) the attributeProcessing * for this mode and returns it. * If it find anything different than attach then we need to perform * attribute processing. * If only attributes for a specific namespace have actions then we only need to * process qualified attributes, otherwise we need to process all attributes. * * @return The attribute processing for this mode. */ int getAttributeProcessing() { if (attributeProcessing == -1) { if (baseMode != null) attributeProcessing = baseMode.getAttributeProcessing(); else attributeProcessing = ATTRIBUTE_PROCESSING_NONE; for (Enumeration e = nssAttributeMap.keys(); e.hasMoreElements() && attributeProcessing != ATTRIBUTE_PROCESSING_FULL;) { NamespaceSpecification nss = (NamespaceSpecification)e.nextElement(); AttributeActionSet actions = (AttributeActionSet)nssAttributeMap.get(nss); if (!actions.getAttach() || actions.getReject() || actions.getSchemas().length > 0) attributeProcessing = ((nss.ns.equals("") || nss.ns.equals(NamespaceSpecification.ANY_NAMESPACE)) ? ATTRIBUTE_PROCESSING_FULL : ATTRIBUTE_PROCESSING_QUALIFIED); } } return attributeProcessing; } /** * Get the locator that points to the place the * mode is defined. * @return a locator. */ Locator getWhereDefined() { return whereDefined; } /** * Getter for the defined flag. * @return defined. */ boolean isDefined() { return defined; } /** * Checks if a mode is anonymous. * @return true if anonymous. */ boolean isAnonymous() { return anonymous; } /** * Get a locator pointing to the first place this mode is used. * @return a locator. */ Locator getWhereUsed() { return whereUsed; } /** * Record the locator if this is the first location this mode is used. * @param locator Points to the location this mode is used from. */ void noteUsed(Locator locator) { if (whereUsed == null && locator != null) whereUsed = new LocatorImpl(locator); } /** * Record the locator this mode is defined at. * @param locator Points to the mode definition. */ void noteDefined(Locator locator) { defined = true; if (whereDefined == null && locator != null) whereDefined = new LocatorImpl(locator); } /** * Adds a set of element actions to be performed in this mode * for elements in a specified namespace. * * @param ns The namespace pattern. * @param wildcard The wildcard character. * @param actions The set of element actions. * @return true if successfully added, that is the namespace was * not already present in the elementMap, otherwise false, the * caller should signal a script error in this case. */ boolean bindElement(String ns, String wildcard, ActionSet actions) { NamespaceSpecification nss = new NamespaceSpecification(ns, wildcard); if (nssElementMap.get(nss) != null) return false; for (Enumeration e = nssElementMap.keys(); e.hasMoreElements();) { NamespaceSpecification nssI = (NamespaceSpecification)e.nextElement(); if (nss.compete(nssI)) { return false; } } nssElementMap.put(nss, actions); return true; } /** * Adds a set of attribute actions to be performed in this mode * for attributes in a specified namespace. * * @param ns The namespace pattern. * @param wildcard The wildcard character. * @param actions The set of attribute actions. * @return true if successfully added, that is the namespace was * not already present in the attributeMap, otherwise false, the * caller should signal a script error in this case. */ boolean bindAttribute(String ns, String wildcard, AttributeActionSet actions) { NamespaceSpecification nss = new NamespaceSpecification(ns, wildcard); if (nssAttributeMap.get(nss) != null) return false; for (Enumeration e = nssAttributeMap.keys(); e.hasMoreElements();) { NamespaceSpecification nssI = (NamespaceSpecification)e.nextElement(); if (nss.compete(nssI)) { return false; } } nssAttributeMap.put(nss, actions); return true; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ModeUsage.java000066400000000000000000000111061225366607500314060ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.util.Equal; import java.util.Vector; import java.util.Enumeration; /** * Stores mode usage information. */ class ModeUsage { /** * The use mode. */ private final Mode mode; /** * The current mode used until now. */ private final Mode currentMode; /** * Modes depending on context. */ private ContextMap modeMap; private int attributeProcessing = -1; /** * Creates a use mode. * @param mode The mode to be used. * @param currentMode The mode used until the new mode. */ ModeUsage(Mode mode, Mode currentMode) { this(mode, currentMode, null); } /** * Creates a use mode. * @param mode The mode to be used. * @param currentMode The mode used until now. * @param modeMap Modes to be used depending on context. */ private ModeUsage(Mode mode, Mode currentMode, ContextMap modeMap) { this.mode = mode; this.currentMode = currentMode; this.modeMap = modeMap; } /** * Gets a new mode usage with a different current mode * but with the same mode and modeMap as this one. * @param currentMode The new current mode. * @return A new mode usage with the changed current mode. */ ModeUsage changeCurrentMode(Mode currentMode) { return new ModeUsage(mode, currentMode, modeMap); } /** * Check to see if this mode usage is equals with another mode usage. */ public boolean equals(Object obj) { if (!(obj instanceof ModeUsage)) return false; ModeUsage other = (ModeUsage)obj; return this.mode == other.mode && this.currentMode == other.currentMode && Equal.equal(this.modeMap, other.modeMap); } /** * Gets a hash code for this mode usage. */ public int hashCode() { int hc = mode.hashCode() ^ currentMode.hashCode(); if (modeMap != null) hc ^= modeMap.hashCode(); return hc; } /** * Resolves the Mode.CURRENT to the currentMode for this mode usage. * If Mode.CURRENT is not passed as argument then the same mode is returned * with the exception of an anonymous mode that is not defined, when we * get also the current mode. * @param mode The mode to be resolved. * @return Either the current mode mode usage or the same mode passed as argument. */ private Mode resolve(Mode mode) { if (mode == Mode.CURRENT) { return currentMode; } // For an action that does not specify the useMode attribute // we create an anonymous next mode that becomes defined if we // have a nested mode element inside the action. // If we do not have a nested mode then the anonymous mode // is not defined and basically that means we should use the // current mode to perform that action. if (mode.isAnonymous() && !mode.isDefined()) { return currentMode; } return mode; } /** * Get the maximum attribute processing value from the default mode and * from all the modes specified in the contexts. * @return The attribute processing value. */ int getAttributeProcessing() { if (attributeProcessing == -1) { attributeProcessing = resolve(mode).getAttributeProcessing(); if (modeMap != null) { for (Enumeration e = modeMap.values(); e.hasMoreElements() && attributeProcessing != Mode.ATTRIBUTE_PROCESSING_FULL;) attributeProcessing = Math.max(resolve((Mode)e.nextElement()).getAttributeProcessing(), attributeProcessing); } } return attributeProcessing; } /** * Check if we have context dependent modes. * @return true if the modeMap exists. */ boolean isContextDependent() { return modeMap != null; } /** * Get the mode to be used for a specific context. * @param context The current context. * @return A mode. */ Mode getMode(Vector context) { // first look in the modeMap if exists. if (modeMap != null) { Mode m = (Mode)modeMap.get(context); if (m != null) return resolve(m); } // if no modeMap or no context specific mode found then // return the default mode for this mode usage. return resolve(mode); } /** * Adds a new context (isRoot, path --> mode). * @param isRoot Flag indicating that the path starts or not with / * @param names The local names that form the path. * @param mode The mode for this path. * @return true if we do not have a duplicate path. */ boolean addContext(boolean isRoot, Vector names, Mode mode) { if (modeMap == null) modeMap = new ContextMap(); return modeMap.put(isRoot, names, mode); } } NamespaceSpecification.java000066400000000000000000000127571225366607500340700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import java.util.StringTokenizer; /** * Stores information about a namespace specification. * A namespace is specified with a namespace pattern and a wildcard. * The wildcard can be present in multiple places in the namespace * specification and each occurence of the wildcard can be replaced with * an arbitrary sequence of characters. * * @author george */ class NamespaceSpecification { /** * Default value for wildcard. */ public static String DEFAULT_WILDCARD = "*"; /** * Constant for any namespace. */ static final String ANY_NAMESPACE = "##any"; /** * The namespace pattern, may contain one or more occurances of the wildcard. */ String ns="\0"; /** * The wildcard character, by default it is *. */ String wildcard = DEFAULT_WILDCARD; /** * Creates a namespace specification from a namespace pattern * using the default wildcard, that is *. * @param ns The namespace pattern */ public NamespaceSpecification(String ns) { this(ns, DEFAULT_WILDCARD); } /** * Creates a namespace specification from a namespace pattern * and a given wildcard. * @param ns The namespace pattern * @param wildcard The given wildcard character. */ public NamespaceSpecification(String ns, String wildcard) { this.ns = ns; this.wildcard = wildcard; } /** * Check if this namespace specification competes with * another namespace specification. * @param other The namespace specification we need to check if * it competes with this namespace specification. * @return true if the namespace specifications compete. */ public boolean compete(NamespaceSpecification other) { // if no wildcard for other then we check coverage if ("".equals(other.wildcard)) { return covers(other.ns); } // split the namespaces at wildcards String[] otherParts = split(other.ns, other.wildcard); // if the given namepsace specification does not use its wildcard // then we just look if the current namespace specification covers it if (otherParts.length == 1) { return covers(other.ns); } // if no wildcard for the current namespace specification if ("".equals(wildcard)) { return other.covers(ns); } // also for the current namespace specification String[] parts = split(ns, wildcard); // now check if the current namespace specification is just an URI if (parts.length == 1) { return other.covers(ns); } // now each namespace specification contains wildcards // suppose we have // ns = a1*a2*...*an // and // other.ns = b1*b2*...*bm // then we only need to check matchPrefix(a1, b1) and matchPrefix(an, bn) where // matchPrefix(a, b) means a starts with b or b starts with a. return matchPrefix(parts[0], otherParts[0]) && matchPrefix(parts[parts.length - 1], otherParts[otherParts.length - 1]); } /** * Checks with either of the strings starts with the other. * @param s1 a String * @param s2 a String * @return true if s1 starts with s2 or s2 starts with s1, false otherwise */ static private boolean matchPrefix(String s1, String s2) { return s1.startsWith(s2) || s2.startsWith(s1); } private String[] split(String value, String wildcard) { StringTokenizer st = new StringTokenizer(value, wildcard, true); int index = st.countTokens(); if (index == 0) return new String[]{value}; String[] parts = new String[index]; index = 0; while (st.hasMoreTokens()) { String token = st.nextToken(); parts[index++] = token.equals(wildcard) ? "" : token; } return parts; } /** * Checks if a namespace specification covers a specified URI. * any namespace pattern covers only the any namespace uri. * @param uri The uri to be checked. * @return true if the namespace pattern covers the specified uri. */ public boolean covers(String uri) { // any namspace covers only the any namespace uri // no wildcard ("") requires equality between namespaces. if (ANY_NAMESPACE.equals(ns) || "".equals(wildcard)) { return ns.equals(uri); } String[] parts = split(ns, wildcard); // no wildcard if (parts.length == 1) { return ns.equals(uri); } // at least one wildcard, we need to check that the start and end are the same // then we get to match a string against a pattern like *p1*...*pn* if (!uri.startsWith(parts[0])) { return false; } if (!uri.endsWith(parts[parts.length - 1])) { return false; } // Check that all remaining parts match the remaining URI. int start = parts[0].length(); int end = uri.length() - parts[parts.length - 1].length(); for (int i = 1; i < parts.length - 1; i++) { if (start > end) { return false; } int match = uri.indexOf(parts[i], start); if (match == -1 || match + parts[i].length() > end) { return false; } start = match + parts[i].length(); } return true; } /** * Checks for equality with another Namespace specification. */ public boolean equals(Object obj) { if (obj instanceof NamespaceSpecification) { NamespaceSpecification other = (NamespaceSpecification)obj; return ns.equals(other.ns) && wildcard.equals(other.wildcard); } return false; } /** * Get a hashcode for this namespace specification. */ public int hashCode() { return (wildcard + "|" + ns).hashCode(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/NoResultAction.java000066400000000000000000000014351225366607500324520ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.SAXException; /** * No result action. These actions are the validations, either validate, allow or reject. */ abstract class NoResultAction extends Action { /** * Creates the action with the specified mode usage. * @param modeUsage The mode usage. */ NoResultAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action on the SectionState. * @param state The section state. * @throws SAXException In case of errors. */ abstract void perform(SectionState state) throws SAXException; /** * Get a no result action with the current mode changed. * @param mode the new mode. * @return A new no result action. */ abstract NoResultAction changeCurrentMode(Mode mode); } NvdlSchemaReceiverFactory.java000066400000000000000000000015631225366607500345250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.Option; /** * A Schema receiver factory that knows how to create NVDL schema receivers. */ public class NvdlSchemaReceiverFactory implements SchemaReceiverFactory { /** * Checks if the namespace is the NVDL namespace and if yes then it creates * a schema receiver, otherwise returns null. */ public SchemaReceiver createSchemaReceiver(String namespaceUri, PropertyMap properties) { if (!SchemaImpl.NVDL_URI.equals(namespaceUri)) return null; return new SchemaReceiverImpl(properties); } /** * No options handling, always returns null. */ public Option getOption(String uri) { return null; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/Path.java000066400000000000000000000135741225366607500304440ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.xml.util.Naming; import java.util.Vector; /** * Stores a NVDL/NRL path information. * Parses a path string and returns a list of Path objects. * This stores a single path that can optionally start with a / and * contains a list of local names separated by /, like * /path1/path2 or * path1/path2. * */ class Path { /** * Flag indicating wether the path starts with / or not. */ private final boolean root; /** * The list of local names that form the path. */ private final Vector names; /** * Constructor, creates a Path. * @param root Flag specifying wether the path starts with / or not. * @param names The list of local names. */ Path(boolean root, Vector names) { this.root = root; this.names = names; } /** * Determines if the path starts with / or not. * @return true if the path starts with /. */ boolean isRoot() { return root; } /** * Get the local names list. * @return A vector with the local names. */ Vector getNames() { return names; } /** * Get a string representation of this path. * It can be either /name1/name2 or name1/name2. */ public String toString() { StringBuffer buf = new StringBuffer(); if (root) buf.append('/'); for (int i = 0, len = names.size(); i < len; i++) { if (i != 0) buf.append('/'); buf.append((String)names.elementAt(i)); } return buf.toString(); } /** * Exception thrown in case we get errors parsing a path. */ static class ParseException extends Exception { /** * The message key. */ private final String messageKey; /** * Creates an exception with a given message key. * @param messageKey The message key. */ ParseException(String messageKey) { super(messageKey); this.messageKey = messageKey; } /** * Get the message key. * @return The message key. */ public String getMessageKey() { return messageKey; } } // states for parsing the path. /** * Initial state. */ private static final int START = 0; /** * In a local name. */ private static final int IN_NAME = 1; /** * After a local name. */ private static final int AFTER_NAME = 2; /** * After a slash. */ private static final int AFTER_SLASH = 3; /** * Gets the list of Path from the path string. * The path string can represent more paths separated by |. * * @param str The path string. * @return A Vector with the determined Path objects. * @throws ParseException In case of invalid path expression. */ static Vector parse(String str) throws ParseException { int state = START; int nameStartIndex = -1; Vector paths = new Vector(); Vector names = new Vector(); boolean root = false; for (int i = 0, len = str.length(); i < len; i++) { char c = str.charAt(i); switch (c) { case ' ': case '\r': case '\n': case '\t': if (state == IN_NAME) { names.addElement(makeName(str, nameStartIndex, i)); state = AFTER_NAME; } break; case '/': switch (state) { case IN_NAME: names.addElement(makeName(str, nameStartIndex, i)); break; case START: root = true; break; case AFTER_SLASH: throw new ParseException("unexpected_slash"); } state = AFTER_SLASH; break; case '|': switch (state) { case START: throw new ParseException("empty_path"); case AFTER_NAME: break; case AFTER_SLASH: throw new ParseException("expected_name"); case IN_NAME: names.addElement(makeName(str, nameStartIndex, i)); break; } paths.addElement(new Path(root, names)); root = false; names = new Vector(); state = START; break; default: switch (state) { case AFTER_NAME: throw new ParseException("expected_slash"); case AFTER_SLASH: case START: nameStartIndex = i; state = IN_NAME; break; case IN_NAME: break; } break; } } switch (state) { case START: throw new ParseException("empty_path"); case AFTER_NAME: break; case AFTER_SLASH: throw new ParseException("expected_name"); case IN_NAME: names.addElement(makeName(str, nameStartIndex, str.length())); break; } paths.addElement(new Path(root, names)); return paths; } /** * Extracts a name from a given string (path) from the specified * start position to the specified end position. * It also checks that the extracted name is a valid non qualified name (local name). * * @param str The path string. * @param start The start position. * @param end The end position. * @return A string representing the extracted local name. * @throws ParseException In case of invalid local name. */ private static String makeName(String str, int start, int end) throws ParseException { String name = str.substring(start, end); if (!Naming.isNcname(name)) throw new ParseException("invalid_name"); return name; } /** * Main method, for test. * @param args Command line arguments, the first argument is a path. * @throws ParseException In case the parsing fails. */ static public void main(String[] args) throws ParseException { Vector paths = parse(args[0]); for (int i = 0; i < paths.size(); i++) { if (i != 0) System.out.println("---"); Path path = (Path)paths.elementAt(i); if (path.isRoot()) System.out.println("/"); for (int j = 0; j < path.getNames().size(); j++) System.out.println(path.getNames().elementAt(j)); } } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/RejectAction.java000066400000000000000000000017471225366607500321210ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.SAXException; /** * A no result action that rejects any element. */ class RejectAction extends NoResultAction { /** * Creates a reject action. * @param modeUsage The mode usage. */ RejectAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action on the session state. * @param state The section state. */ void perform(SectionState state) throws SAXException { final ModeUsage modeUsage = getModeUsage(); state.reject(); state.addChildMode(modeUsage, null); state.addAttributeValidationModeUsage(modeUsage); } /** * Get a new reject action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ NoResultAction changeCurrentMode(Mode mode) { return new RejectAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ResultAction.java000066400000000000000000000017361225366607500321610ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; /** * Reult action. * These actions change the sections, attach and unwrap. * */ abstract class ResultAction extends Action { /** * Creates a result action with a given mode usage. * @param modeUsage The mode usage. */ ResultAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action on a session state. * * @param handler The content handler??? * @param state The session state. * @throws SAXException */ abstract void perform(ContentHandler handler, SectionState state) throws SAXException; /** * Get a similar action but with the current mode in the mode usage changed. * This is useful to get the actions from a mode that extends the mode that has this action. * @param mode The new current mode. * @return The new result action. */ abstract ResultAction changeCurrentMode(Mode mode); } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/SchemaImpl.java000066400000000000000000001234101225366607500315610ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyId; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.util.Uri; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.OptionArgumentException; import com.thaiopensource.validate.OptionArgumentPresenceException; import com.thaiopensource.validate.ResolverFactory; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.xml.sax.CountingErrorHandler; import com.thaiopensource.xml.sax.DelegatingContentHandler; import com.thaiopensource.xml.sax.XmlBaseHandler; import com.thaiopensource.xml.util.WellKnownNamespaces; 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.XMLReader; import org.xml.sax.helpers.LocatorImpl; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; import java.util.Vector; /** * Schema implementation for NVDL scripts. */ class SchemaImpl extends AbstractSchema { /** * Mode name used when the script does not define modes and just enters * namespace and anyNamespace mappings directly inside rules. */ static private final String IMPLICIT_MODE_NAME = "#implicit"; /** * Mode name used when we have to use this script as an attributes schema. * The wrapper mode allows elements from any namespace. */ static private final String WRAPPER_MODE_NAME = "#wrapper"; /** * The NVDL URI. */ static final String NVDL_URI = "http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"; /** * A hash with the modes. */ private final Hashtable modeMap = new Hashtable(); /** * A hash with the triggers on namespace. * Element names are stored concatenated in a string, each name preceded by #. */ private final List triggers = new ArrayList(); /** * The start mode. */ private Mode startMode; /** * Default base mode, rejects everything. */ private final Mode defaultBaseMode; /** * Flag indicating if the schema needs to be changed to handle * attributes only, the element in this case is a placeholder. */ private final boolean attributesSchema; /** * Wrapps an IOException as a RuntimeException. * */ static private final class WrappedIOException extends RuntimeException { /** * The actual IO Exception. */ private final IOException exception; /** * Creates a wrapped exception. * @param exception The IOException. */ private WrappedIOException(IOException exception) { this.exception = exception; } /** * Get the actual IO Exception. * @return IOException. */ private IOException getException() { return exception; } } /** * Stores information about options that must be supported by the * validator. */ static private class MustSupportOption { /** * The option name. */ private final String name; /** * The property id. */ private final PropertyId pid; /** * Locator pointing to where this option is declared. */ private final Locator locator; /** * Creates a must support option. * @param name The option name * @param pid property id. * @param locator locator pointing to where this option is declared. */ MustSupportOption(String name, PropertyId pid, Locator locator) { this.name = name; this.pid = pid; this.locator = locator; } } /** * This class is registered as content handler on the XMLReader that * parses the NVDL script. * It creates the Schema representation for this script and also validates * the script against the NVDL schema. */ private class Handler extends DelegatingContentHandler implements SchemaFuture { /** * The schema receiver. Used to cretae other schemas and access options. */ private final SchemaReceiverImpl sr; /** * Flag indicating that we encountered an error. */ private boolean hadError = false; /** * The error handler. */ private final ErrorHandler eh; /** * A counting error handler that wraps the error handler. * It is useful to stop early if we encounter errors. */ private final CountingErrorHandler ceh; /** * The Resolver to use for resolving URIs and entities. */ private final SAXResolver resolver; /** * Convert error keys to messages. */ private final Localizer localizer = new Localizer(SchemaImpl.class); /** * Error locator. */ private Locator locator; /** * Handle xml:base attributes. */ private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler(); /** * For ignoring foreign elements. */ private int foreignDepth = 0; /** * The value of rules/@schemaType */ private String defaultSchemaType; /** * The validator that checks the script against the * NVDL RelaxNG schema. */ private Validator validator; /** * Stores mode data. * We use this to handle included and nested modes. */ class ModeData { /** * Points to the current mode. */ private Mode currentMode = null; /** * The value of the match attribute on the current rule. */ private ElementsOrAttributes match; /** * The current element actions. */ private ActionSet actions; /** * The current attribute actions. */ private AttributeActionSet attributeActions; /** * The URI reference for the schema for the current validate action. * This is as specified in the attribute before any resolution. */ private String schemaUriRef; /** * The base URI to be used for resolving schemaUriRef. */ private String schemaUriBase; /** * The current validate action schema type. */ private String schemaType; /** * The options defined for a validate action. */ private PropertyMapBuilder options; /** * The options that must be supported by the validator * for the current validate action. */ private final Vector mustSupportOptions = new Vector(); /** * The current mode usage, for the current action. */ private ModeUsage modeUsage; /** * Flag indicating if we are in a namespace rule or in an anyNamespace rule. */ private boolean anyNamespace; /** * The lastMode stores the last created mode. * For example when we have an action we need to create the * ModeUsage for it and lastMode points to the mode for that action. * It is possible that lastMode is created without having encountered * its definition, in the case of nested modes. In that case we have * no useMode attribute but a mode element can appear further inside * the action (a nested mode). If no mode appears inside the action then * we need to resolve the anonymous mode that is not defined to the current mode. */ private Mode lastMode; } /** * Stores mode data. */ ModeData md = new ModeData(); /** * Keeps the mode data stack. */ private Stack modeDataStack = new Stack(); /** * Keeps the elements from NVDL representing the current context. * We need it to distinguish between modes, included modes and * nested modes. */ private Stack nvdlStack = new Stack(); /** * Creates a handler. * @param sr The Schema Receiver implementation for NVDL schemas. */ Handler(SchemaReceiverImpl sr) { this.sr = sr; this.eh = sr.getProperties().get(ValidateProperty.ERROR_HANDLER); this.ceh = new CountingErrorHandler(this.eh); this.resolver = ResolverFactory.createResolver(sr.getProperties()); } /** * Callback with the document locator. * @param locator The document locator. */ public void setDocumentLocator(Locator locator) { xmlBaseHandler.setLocator(locator); this.locator = locator; } /** * On start document. */ public void startDocument() throws SAXException { // creates a validator that validates against the schema for NVDL. try { PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties()); builder.put(ValidateProperty.ERROR_HANDLER, ceh); validator = sr.getNvdlSchema().createValidator(builder.toPropertyMap()); } catch (IOException e) { throw new WrappedIOException(e); } catch (IncorrectSchemaException e) { throw new RuntimeException("internal error in RNG schema for NVDL"); } // set that validator content handler as delegate to receive the NVDL schema content. setDelegate(validator.getContentHandler()); // forward the setDocumentLocator and startDocument to the delegate handler. if (locator != null) super.setDocumentLocator(locator); super.startDocument(); } public Schema getSchema() throws IncorrectSchemaException, SAXException { if (validator == null || ceh.getHadErrorOrFatalError()) throw new IncorrectSchemaException(); Hashset openModes = new Hashset(); Hashset checkedModes = new Hashset(); for (Enumeration e = modeMap.keys(); e.hasMoreElements();) { String modeName = (String)e.nextElement(); Mode mode = (Mode)modeMap.get(modeName); if (!mode.isDefined()) error("undefined_mode", modeName, mode.getWhereUsed()); for (Mode tem = mode; tem != null; tem = tem.getBaseMode()) { if (checkedModes.contains(tem)) break; if (openModes.contains(tem)) { error("mode_cycle", tem.getName(), tem.getWhereDefined()); break; } openModes.add(tem); } checkedModes.addAll(openModes); openModes.clear(); } if (hadError) throw new IncorrectSchemaException(); return SchemaImpl.this; } public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException { if (e instanceof WrappedIOException) throw ((WrappedIOException)e).getException(); return e; } /** * Start element callback. * @param uri The namespace uri for this element. * @param localName The element local name. * @param qName The element qualified name. * @param attributes The attributes of this element. */ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // call delegate handler super.startElement(uri, localName, qName, attributes); // handle xml:base xmlBaseHandler.startElement(); String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base"); if (xmlBase != null) xmlBaseHandler.xmlBaseAttribute(xmlBase); // ignore foreign elements if (!NVDL_URI.equals(uri) || foreignDepth > 0) { foreignDepth++; return; } // stop if we got errors. if (ceh.getHadErrorOrFatalError()) return; // dispatch based on the element name if (localName.equals("rules")) parseRules(attributes); else if (localName.equals("mode")) { String parent = (String)nvdlStack.peek(); if ("rules".equals(parent)) parseMode(attributes); else if ("mode".equals(parent)) // mode inside mode - included mode. parseIncludedMode(attributes); else // nested mode parseNestedMode(attributes); } else if (localName.equals("namespace")) parseNamespace(attributes); else if (localName.equals("anyNamespace")) parseAnyNamespace(attributes); else if (localName.equals("validate")) parseValidate(attributes); else if (localName.equals("reject")) parseReject(attributes); else if (localName.equals("attach")) parseAttach(attributes); else if (localName.equals("unwrap")) parseUnwrap(attributes); else if (localName.equals("attachPlaceholder")) parseAttachPlaceholder(attributes); else if (localName.equals("allow")) parseAllow(attributes); else if (localName.equals("context")) parseContext(attributes); else if (localName.equals("option")) parseOption(attributes); else if (localName.equals("trigger")) parseTrigger(attributes); else if (localName.equals("schema")) error("embedded_schemas"); else if (localName.equals("cancelNestedActions")) parseCancelNestedActions(attributes); else if (localName.equals("message")) ; // noop else throw new RuntimeException("unexpected element \"" + localName + "\""); // add the NVDL element on the stack nvdlStack.push(localName); } /** * End element callback. * @param namespaceURI The namespace uri for this element. * @param localName The element local name. * @param qName The element qualified name. */ public void endElement(String namespaceURI, String localName, String qName) throws SAXException { // call the delegate handler super.endElement(namespaceURI, localName, qName); // handle xml:base xmlBaseHandler.endElement(); // ignore foreign elements if (foreignDepth > 0) { foreignDepth--; return; } // exit early if we got errors. if (ceh.getHadErrorOrFatalError()) return; // pop the NVDL element from the stack nvdlStack.pop(); // dispatch based on element name. if (localName.equals("validate")) finishValidate(); else if (localName.equals("mode")) { String parent = (String)nvdlStack.peek(); if ("rules".equals(parent)) finishMode(); else if ("mode".equals(parent)) // mode inside mode - included mode. finishIncludedMode(); else // nested mode. finishNestedMode(); } } /** * Parse the rules element. * Initializes * the start mode * the current mode * the defaultSchemaType * @param attributes The rule element attributes. */ private void parseRules(Attributes attributes) { startMode = getModeAttribute(attributes, "startMode"); // If not start mode specified we create an implicit mode. if (startMode == null) { startMode = lookupCreateMode(IMPLICIT_MODE_NAME); md.currentMode = startMode; // mark this implicit mode as not defined in the schema. startMode.noteDefined(null); } // Set the current location as the location the start mode is first used. startMode.noteUsed(locator); // if the schema should be used for validating only attributes // we need to create a wrapper that allows any element from any namespace // as the placeholder for the attributes we want to validate. if (attributesSchema) { Mode wrapper = lookupCreateMode(WRAPPER_MODE_NAME); // creates element actions - allow and set them for any namespace // the attributes will be validated further in the real schema start mode. ActionSet actions = new ActionSet(); actions.addNoResultAction(new AllowAction(new ModeUsage(startMode, startMode))); wrapper.bindElement(NamespaceSpecification.ANY_NAMESPACE, NamespaceSpecification.DEFAULT_WILDCARD, actions); wrapper.noteDefined(null); // we use the wrapper mode as the start mode. startMode = wrapper; } // Get the default value for schema type if it is specified in rule/@schemaType. defaultSchemaType = getSchemaType(attributes); } /** * Parse a mode element. * @param attributes The element attributes. * @throws SAXException */ private void parseMode(Attributes attributes) throws SAXException { // Get the mode (create it if it does not exists) corresponding to the name attribute. md.currentMode = getModeAttribute(attributes, "name"); // If already defined, report errors. if (md.currentMode.isDefined()) { error("duplicate_mode", md.currentMode.getName()); error("first_mode", md.currentMode.getName(), md.currentMode.getWhereDefined()); } else { // Check if we have a base mode and set that as the base mode for this mode. Mode base = getModeAttribute(attributes, "extends"); if (base != null) md.currentMode.setBaseMode(base); // record the location where this mode is defined. md.currentMode.noteDefined(locator); } } /** * Parse a mode element. * @param attributes The element attributes. * @throws SAXException */ private void parseIncludedMode(Attributes attributes) throws SAXException { // Create an anonymous mode. Mode parent = md.currentMode; modeDataStack.push(md); md = new ModeData(); md.currentMode = new Mode(defaultBaseMode); md.currentMode.noteDefined(locator); parent.addIncludedMode(md.currentMode); } /** * Parse a mode element. * @param attributes The element attributes. * @throws SAXException */ private void parseNestedMode(Attributes attributes) throws SAXException { // Nested mode is an anonymous mode inside an action. The action does // not have a useMode attribute and we alrady have the mode for that // created in the current mode data lastMode, so we use that and define it // as this nested mode. ModeData oldMd = md; modeDataStack.push(md); md = new ModeData(); md.currentMode = oldMd.lastMode; // If already defined, report errors. if (md.currentMode.isDefined()) { error("duplicate_mode", md.currentMode.getName()); error("first_mode", md.currentMode.getName(), md.currentMode.getWhereDefined()); } else { // record the location where this mode is defined. md.currentMode.noteDefined(locator); } } /** * Parse a namespace rule. * @param attributes The namespace element attributes. * @throws SAXException */ private void parseNamespace(Attributes attributes) throws SAXException { md.anyNamespace = false; parseRule(getNs(attributes), attributes); } /** * Parse an anyNamespace rule. * @param attributes The anyNamespace element attributes. * @throws SAXException */ private void parseAnyNamespace(Attributes attributes) throws SAXException { md.anyNamespace = true; parseRule(NamespaceSpecification.ANY_NAMESPACE, attributes); } /** * Parse namespace and anyNamespace rules/ * @param ns The namespace, ##any for anyNamespace * @param attributes The rule attributes. * @throws SAXException */ private void parseRule(String ns, Attributes attributes) throws SAXException { // gets the value of the match attribute, defaults to match elements only. md.match = toElementsOrAttributes(attributes.getValue("", "match"), ElementsOrAttributes.ELEMENTS); String wildcard = attributes.getValue("", "wildCard"); if (wildcard == null) { wildcard = NamespaceSpecification.DEFAULT_WILDCARD; } // check if match attributes if (md.match.containsAttributes()) { // creates an empty attributes action set. md.attributeActions = new AttributeActionSet(); // if we already have attribute actions for this namespace // signal an error. if (!md.currentMode.bindAttribute(ns, wildcard, md.attributeActions)) { if (ns.equals(NamespaceSpecification.ANY_NAMESPACE)) error("duplicate_attribute_action_any_namespace"); else error("duplicate_attribute_action", ns); } } else md.attributeActions = null; // XXX: george // } else md.attributeActions=null; //??? // check if match elements if (md.match.containsElements()) { // creates an empty action set. md.actions = new ActionSet(); // if we already have actions for this namespace // signal an error. if (!md.currentMode.bindElement(ns, wildcard, md.actions)) { if (ns.equals(NamespaceSpecification.ANY_NAMESPACE)) error("duplicate_element_action_any_namespace"); else error("duplicate_element_action", ns); } } else md.actions = null; } /** * Parse a validate action. * @param attributes The validate element attributes. * @throws SAXException */ private void parseValidate(Attributes attributes) throws SAXException { // get the resolved URI pointing to the schema. md.schemaUriRef = getSchema(attributes); md.schemaUriBase = xmlBaseHandler.getBaseUri(); // get the schema type md.schemaType = getSchemaType(attributes); // if no schemaType attribute, use the default schema type. if (md.schemaType == null) md.schemaType = defaultSchemaType; if (SchemaReceiverImpl.LEGACY_RNC_MEDIA_TYPE.equals(md.schemaType)) warning("legacy_rnc_media_type", locator); // if we matched on elements create a mode usage. if (md.actions != null) md.modeUsage = getModeUsage(attributes); else md.modeUsage = null; // prepare to receive validate options. md.options = new PropertyMapBuilder(); md.mustSupportOptions.clear(); } /** * Notification that the validate element ends. * @throws SAXException */ private void finishValidate() throws SAXException { if (md.schemaUriRef != null) { try { // if we had attribute actions, that is matching attributes // we add a schema to the attributes action set. if (md.attributeActions != null) { Schema schema = createSubSchema(true); md.attributeActions.addSchema(schema); } // if we had element actions, that is macting elements // we add a validate action with the schema and the specific mode usage. if (md.actions != null) { Schema schema = createSubSchema(false); md.actions.addNoResultAction(new ValidateAction(md.modeUsage, schema)); } } catch (IncorrectSchemaException e) { hadError = true; } catch (IOException e) { throw new WrappedIOException(e); } } } /** * Notification that the mode element ends. * @throws SAXException */ private void finishMode() throws SAXException { } /** * Notification that the mode element ends. * @throws SAXException */ private void finishIncludedMode() throws SAXException { md = (ModeData)modeDataStack.pop(); } /** * Notification that the mode element ends. * @throws SAXException */ private void finishNestedMode() throws SAXException { md = (ModeData)modeDataStack.pop(); } /** * Creates a sub schema for the ending validate action (this is * called from finishValidate). * * @param isAttributesSchema If the schema is intended to validate only attributes. * @return A Schema. * @throws IOException * @throws IncorrectSchemaException * @throws SAXException */ private Schema createSubSchema(boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException { // the user specified options PropertyMap requestedProperties = md.options.toPropertyMap(); // let the schema receiver create a child schema // XXX parse the media type to the resolver Schema schema = sr.createChildSchema(resolver.resolve(md.schemaUriRef, md.schemaUriBase), md.schemaType, requestedProperties, isAttributesSchema); // get the schema properties PropertyMap actualProperties = schema.getProperties(); // Check if the actual properties match the must support properties. for (Enumeration e = md.mustSupportOptions.elements(); e.hasMoreElements();) { MustSupportOption mso = (MustSupportOption)e.nextElement(); Object actualValue = actualProperties.get(mso.pid); if (actualValue == null) error("unsupported_option", mso.name, mso.locator); else if (!actualValue.equals(requestedProperties.get(mso.pid))) error("unsupported_option_arg", mso.name, mso.locator); } return schema; } /** * Parse a validate option. * @param attributes The option element attributes. * @throws SAXException */ private void parseOption(Attributes attributes) throws SAXException { // get the mustSupport flag boolean mustSupport; String mustSupportValue = attributes.getValue("", "mustSupport"); if (mustSupportValue != null) { mustSupportValue = mustSupportValue.trim(); mustSupport = mustSupportValue.equals("1") || mustSupportValue.equals("true"); } else mustSupport = false; // Resolve the option if specified relative to the NVDL URI. String name = Uri.resolve(NVDL_URI, attributes.getValue("", "name")); Option option = sr.getOption(name); // check if we got a known option. if (option == null) { if (mustSupport) error("unknown_option", name); } else { // known option, look for arguments String arg = attributes.getValue("", "arg"); try { PropertyId pid = option.getPropertyId(); Object value = option.valueOf(arg); Object oldValue = md.options.get(pid); if (oldValue != null) { value = option.combine(new Object[]{oldValue, value}); if (value == null) error("duplicate_option", name); else md.options.put(pid, value); } else { md.options.put(pid, value); md.mustSupportOptions.addElement(new MustSupportOption(name, pid, locator == null ? null : new LocatorImpl(locator))); } } catch (OptionArgumentPresenceException e) { error(arg == null ? "option_requires_argument" : "option_unexpected_argument", name); } catch (OptionArgumentException e) { if (arg == null) error("option_requires_argument", name); else error("option_bad_argument", name, arg); } } } /** * Parse a trigger element. * @param attributes The trigger element attributes. * @throws SAXException */ private void parseTrigger(Attributes attributes) throws SAXException { // get the ns and nameList, we know they are not null as we validate against the nvdl.rng schema. String ns = attributes.getValue("", "ns"); String nameList = attributes.getValue("", "nameList"); StringTokenizer st = new StringTokenizer(nameList); Set names = new HashSet(st.countTokens()); while (st.hasMoreTokens()) { names.add(st.nextToken()); } triggers.add(new Trigger(ns, names)); } /** * Parse an attach action. * @param attributes The attach element attributes. */ private void parseAttach(Attributes attributes) { // if the rule matched attributes set the attach flag in the attribute actions. if (md.attributeActions != null) md.attributeActions.setAttach(true); // if the rule matched elements, the the mode usage and create a attach result action // with that mode usage. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.setResultAction(new AttachAction(md.modeUsage)); } // no element action -> no modeUsage. else md.modeUsage = null; } /** * Parse an unwrap action. * @param attributes The unwrap element attributes. */ private void parseUnwrap(Attributes attributes) { // this makes sense only on elements // if we have element actions, create the mode usage and add // an unwrap action with this mode usage. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.setResultAction(new UnwrapAction(md.modeUsage)); } // no element actions, no modeUsage. else md.modeUsage = null; } /** * Parse an attachPlaceholder action. * @param attributes The attachPlaceholder element attributes. */ private void parseAttachPlaceholder(Attributes attributes) { // this makes sense only on elements // if we have element actions, create the mode usage and add // an attachPlaceholder action with this mode usage. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.setResultAction(new AttachPlaceholderAction(md.modeUsage)); } // no element actions, no modeUsage. else md.modeUsage = null; } /** * Parse an allow action. * * @param attributes The allow element attributes. */ private void parseAllow(Attributes attributes) { // if we match on elements, create the mode usage and add an allow action. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.addNoResultAction(new AllowAction(md.modeUsage)); } // no actions, no mode usage. else md.modeUsage = null; // no need to add anything in the attribute actions, allow // is equivalent with a noop action. } /** * Parse a reject action. * @param attributes The reject element attributes. */ private void parseReject(Attributes attributes) { // if element actions, get the mode usage and add a reject // action with this mode usage. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.addNoResultAction(new RejectAction(md.modeUsage)); } // no actions, no mode usage else md.modeUsage = null; // if attribute actions, set the reject flag. if (md.attributeActions != null) md.attributeActions.setReject(true); } /** * Parse a cancel nested actions action. * * @param attributes The cancelNestedActions element attributes. */ private void parseCancelNestedActions(Attributes attributes) { // if we match on elements, create the mode usage and add a // cancelNestedActions action. if (md.actions != null) { md.modeUsage = getModeUsage(attributes); md.actions.setCancelNestedActions(true); } // no actions, no mode usage. else md.modeUsage = null; // if attribute actions set the cancelNestedActions flag. if (md.attributeActions != null) { md.attributeActions.setCancelNestedActions(true); } } /** * Parse context dependent mode usages. * @param attributes The context element attributes. * @throws SAXException */ private void parseContext(Attributes attributes) throws SAXException { // TODO: check this in the NVDL spec. // context not allowed within anyNamespace.??? // IT SEEMS IT IS ALLOWED IN NVDL... //if (md.anyNamespace) { // error("context_any_namespace"); // return; //} // Get the mode to be used further on this context. Mode mode = getUseMode(attributes); md.lastMode = mode; try { // parse the path value into a list of Path objects // and add them to the mode usage Vector paths = Path.parse(attributes.getValue("", "path")); // XXX warning if modeUsage is null if (md.modeUsage != null) { for (int i = 0, len = paths.size(); i < len; i++) { Path path = (Path)paths.elementAt(i); if (!md.modeUsage.addContext(path.isRoot(), path.getNames(), mode)) error("duplicate_path", path.toString()); } } } catch (Path.ParseException e) { error(e.getMessageKey()); } } /** * Get the URI specified by a schema attribute and if we have a * relative location resolve that against the base URI taking into * account also eventual xml:base attributes. * @param attributes The validate element attributes. * @return A resolved URI as string. * @throws SAXException If the schema contains a fragment id. */ private String getSchema(Attributes attributes) throws SAXException { String schemaUri = attributes.getValue("", "schema"); if ("".equals(schemaUri)) { error("no_schema"); schemaUri = null; } if (schemaUri != null) { if (Uri.hasFragmentId(schemaUri)) error("schema_fragment_id"); return schemaUri; } return null; } /** * Get the schema type * @param attributes The attributes * @return The value of the schemaType attribute. */ private String getSchemaType(Attributes attributes) { return attributes.getValue("", "schemaType"); } /** * Get an ElementsOrAttributes instance depending on the match attribute value. * @param value The match attribute value. * @param defaultValue The default value if value is null. * @return an ElementsOrAttributes constant. */ private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) { if (value == null) return defaultValue; ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER; if (value.indexOf("elements") >= 0) eoa = eoa.addElements(); if (value.indexOf("attributes") >= 0) eoa = eoa.addAttributes(); return eoa; } /** * Creates a mode usage that matches current mode and uses further * the mode specified by the useMode attribute. * @param attributes The action element attributes. * @return A mode usage from currentMode to the mode specified * by the useMode attribute. */ private ModeUsage getModeUsage(Attributes attributes) { md.lastMode = getUseMode(attributes); return new ModeUsage(md.lastMode, md.currentMode); } /** * Get the Mode for the useMode attribute. * @param attributes the attributes * @return the mode with the useMode name or the special Mode.CURRENT mode that * will be resolved to the current mode in a Mode usage. */ private Mode getUseMode(Attributes attributes) { Mode mode = getModeAttribute(attributes, "useMode"); if (mode == null) return new Mode(defaultBaseMode); mode.noteUsed(locator); return mode; } /** * Get the namespace from the ns attribute. * Also check that the namespace is an absolute URI and report an * error otherwise. * @param attributes The list of attributes of the namespace element * @return The ns value. * @throws SAXException */ private String getNs(Attributes attributes) throws SAXException { String ns = attributes.getValue("", "ns"); if (ns != null && !Uri.isAbsolute(ns) && !ns.equals("")) error("ns_absolute"); return ns; } /** * Report a no arguments error from a key. * @param key The error key. * @throws SAXException */ void error(String key) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key), locator)); } /** * Report an one argument error. * @param key The error key. * @param arg The argument. * @throws SAXException */ void error(String key, String arg) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } /** * Report an one argument error with location. * @param key The error key. * @param arg The argument. * @param locator The location. * @throws SAXException */ void error(String key, String arg, Locator locator) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg), locator)); } /** * Report a two arguments error. * @param key The error key. * @param arg1 The first argument. * @param arg2 The second argument. * @throws SAXException */ void error(String key, String arg1, String arg2) throws SAXException { hadError = true; if (eh == null) return; eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator)); } /** * Report a no argument warning with location. * @param key The warning key. * @param locator The location. * @throws SAXException */ void warning(String key, Locator locator) throws SAXException { if (eh == null) return; eh.warning(new SAXParseException(localizer.message(key), locator)); } } /** * Creates a NVDL schema implementation. * Initializes the attributesSchema flag and the built in modes. * @param properties Properties. */ SchemaImpl(PropertyMap properties) { super(properties); this.attributesSchema = properties.contains(WrapProperty.ATTRIBUTE_OWNER); makeBuiltinMode("#allow", AllowAction.class); makeBuiltinMode("#attach", AttachAction.class); makeBuiltinMode("#unwrap", UnwrapAction.class); defaultBaseMode = makeBuiltinMode("#reject", RejectAction.class); } /** * Makes a built in mode. * @param name The mode name. * @param cls The action class. * @return A Mode object. */ private Mode makeBuiltinMode(String name, Class cls) { // lookup/create a mode with the given name. Mode mode = lookupCreateMode(name); // Init the element action set for this mode. ActionSet actions = new ActionSet(); // from the current mode we will use further the built in mode. ModeUsage modeUsage = new ModeUsage(Mode.CURRENT, mode); // Add the action corresponding to the built in mode. if (cls == AttachAction.class) actions.setResultAction(new AttachAction(modeUsage)); else if (cls == AllowAction.class) actions.addNoResultAction(new AllowAction(modeUsage)); else if (cls == UnwrapAction.class) actions.setResultAction(new UnwrapAction(modeUsage)); else actions.addNoResultAction(new RejectAction(modeUsage)); // set the actions on any namespace. mode.bindElement(NamespaceSpecification.ANY_NAMESPACE, NamespaceSpecification.DEFAULT_WILDCARD, actions); // the mode is not defined in the script explicitelly mode.noteDefined(null); // creates attribute actions AttributeActionSet attributeActions = new AttributeActionSet(); // if we have a schema for attributes then in the built in modes // we reject attributes by default // otherwise we attach attributes by default in the built in modes if (attributesSchema) attributeActions.setReject(true); else attributeActions.setAttach(true); // set the attribute actions on any namespace mode.bindAttribute(NamespaceSpecification.ANY_NAMESPACE, NamespaceSpecification.DEFAULT_WILDCARD, attributeActions); return mode; } /** * Installs the schema handler on the reader. * * @param in The reader. * @param sr The schema receiver. * @return The installed handler that implements also SchemaFuture. */ SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) { Handler h = new Handler(sr); in.setContentHandler(h); return h; } /** * Creates a Validator for validating XML documents against this * NVDL script. * @param properties properties. */ public Validator createValidator(PropertyMap properties) { return new ValidatorImpl(startMode, triggers, properties); } /** * Get the mode specified by an attribute from no namespace. * * @param attributes The attributes. * @param localName The attribute name. * @return The mode refered by the licanName attribute. */ private Mode getModeAttribute(Attributes attributes, String localName) { return lookupCreateMode(attributes.getValue("", localName)); } /** * Gets a mode with the given name from the mode map. * If not present then it creates a new mode extending the default base mode. * * @param name The mode to look for or create if it does not exist. * @return Always a not null mode. */ private Mode lookupCreateMode(String name) { if (name == null) return null; name = name.trim(); Mode mode = (Mode)modeMap.get(name); if (mode == null) { mode = new Mode(name, defaultBaseMode); modeMap.put(name, mode); } return mode; } } SchemaReceiverImpl.java000066400000000000000000000150151225366607500331700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdlpackage com.thaiopensource.validate.nvdl; import com.thaiopensource.util.PropertyId; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.validate.rng.SAXSchemaReader; import com.thaiopensource.xml.util.Name; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.transform.sax.SAXSource; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * Schema receiver implementation for NVDL scripts. * */ class SchemaReceiverImpl implements SchemaReceiver { /** * Relax NG schema for NVDL scripts. */ private static final String NVDL_SCHEMA = "nvdl.rng"; /** * The type used for specifying RNC schemas. */ private static final String RNC_MEDIA_TYPE = "application/relax-ng-compact-syntax"; /** * Legacy type used for specifying RNC schemas. */ static final String LEGACY_RNC_MEDIA_TYPE = "application/x-rnc"; /** * Properties. */ private final PropertyMap properties; /** * Property indicating if we need to check only attributes, * that means the root element is just a placeholder for the attributes. */ private final Name attributeOwner; /** * The schema reader capable of parsing the input schema file. * It will be an auto schema reader as NVDL is XML. */ private final SchemaReader autoSchemaReader; /** * Schema object created by this schema receiver. */ private Schema nvdlSchema = null; /** * Properties that will be passed to sub-schemas. */ private static final PropertyId subSchemaProperties[] = { ValidateProperty.ERROR_HANDLER, ValidateProperty.XML_READER_CREATOR, ValidateProperty.ENTITY_RESOLVER, ValidateProperty.URI_RESOLVER, ValidateProperty.RESOLVER, SchemaReceiverFactory.PROPERTY, }; /** * Creates a schema receiver for NVDL schemas. * * @param properties Properties. */ public SchemaReceiverImpl(PropertyMap properties) { this.attributeOwner = properties.get(WrapProperty.ATTRIBUTE_OWNER); PropertyMapBuilder builder = new PropertyMapBuilder(); for (int i = 0; i < subSchemaProperties.length; i++) { Object value = properties.get(subSchemaProperties[i]); if (value != null) builder.put(subSchemaProperties[i], value); } this.properties = builder.toPropertyMap(); this.autoSchemaReader = new AutoSchemaReader(properties.get(SchemaReceiverFactory.PROPERTY)); } public SchemaFuture installHandlers(XMLReader xr) { PropertyMapBuilder builder = new PropertyMapBuilder(properties); if (attributeOwner != null) builder.put(WrapProperty.ATTRIBUTE_OWNER, attributeOwner); return new SchemaImpl(builder.toPropertyMap()).installHandlers(xr, this); } Schema getNvdlSchema() throws IOException, IncorrectSchemaException, SAXException { if (nvdlSchema == null) { String className = SchemaReceiverImpl.class.getName(); String resourceName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + NVDL_SCHEMA; URL nvdlSchemaUrl = getResource(resourceName); InputStream stream = nvdlSchemaUrl.openStream(); // this is just to ensure that there aren't any problems with the parser opening the schema resource InputSource inputSource = new InputSource(nvdlSchemaUrl.toString()); inputSource.setByteStream(stream); nvdlSchema = SAXSchemaReader.getInstance().createSchema(inputSource, properties); } return nvdlSchema; } /** * Get a resource using this class class loader. * @param resourceName the resource. * @return An URL pointing to the resource. */ private static URL getResource(String resourceName) { ClassLoader cl = SchemaReceiverImpl.class.getClassLoader(); // XXX see if we should borrow 1.2 code from Service if (cl == null) return ClassLoader.getSystemResource(resourceName); else return cl.getResource(resourceName); } /** * Get the properties. * @return a PropertyMap. */ PropertyMap getProperties() { return properties; } /** * Creates a child schema. This schema is referred in a validate action. * * @param source the SAXSource for the schema. * @param schemaType the schema type. * @param options options specified for this schema in the NVDL script. * @param isAttributesSchema flag indicating if the schema should be modified * to check attributes only. * @return * @throws IOException In case of IO problems. * @throws IncorrectSchemaException In case of invalid schema. * @throws SAXException In case if XML problems while creating the schema. */ Schema createChildSchema(SAXSource source, String schemaType, PropertyMap options, boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException { SchemaReader reader = isRnc(schemaType) ? CompactSchemaReader.getInstance() : autoSchemaReader; PropertyMapBuilder builder = new PropertyMapBuilder(properties); if (isAttributesSchema) builder.put(WrapProperty.ATTRIBUTE_OWNER, ValidatorImpl.OWNER_NAME); builder.add(options); return reader.createSchema(source, builder.toPropertyMap()); } /** * Get an option for the given URI. * @param uri The URI for an option. * @return Either the option from the auto schema reader or * from the compact schema reader. */ Option getOption(String uri) { Option option = autoSchemaReader.getOption(uri); if (option != null) return option; return CompactSchemaReader.getInstance().getOption(uri); } /** * Checks is a schema type is RNC. * @param schemaType The schema type specification. * @return true if the schema type refers to a RNC schema. */ private static boolean isRnc(String schemaType) { if (schemaType == null) return false; schemaType = schemaType.trim(); return schemaType.equals(RNC_MEDIA_TYPE) || schemaType.equals(LEGACY_RNC_MEDIA_TYPE); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/SectionState.java000066400000000000000000000012461225366607500321460ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.validate.Schema; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; interface SectionState { /** * * @param modeUsage * @param handler may be null */ void addChildMode(ModeUsage modeUsage, ContentHandler handler); void addValidator(Schema schema, ModeUsage modeUsage); /** * * @param handler must not be null */ void addActiveHandler(ContentHandler handler, ModeUsage attributeModeUsage); void addAttributeValidationModeUsage(ModeUsage modeUsage); void reject() throws SAXException; void attachPlaceholder(ModeUsage modeUsage, ContentHandler handler); } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/Trigger.java000066400000000000000000000011741225366607500311440ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import java.util.Set; /** * Stores trigger information. * @author george */ public class Trigger { /** * The namespace name for the local element names. */ String namespace; /** * List with local names. */ Set elementNames; /** * Creates a trigger to store the elements that break sections * for a given namespace. * @param namespace The namespace for all the elements. * @param elementNames A list of local element names. */ Trigger(String namespace, Set elementNames) { this.elementNames = elementNames; this.namespace = namespace; } }jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/UnwrapAction.java000066400000000000000000000016731225366607500321570ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import org.xml.sax.ContentHandler; /** * Unwrap result action. * This action an element but allows its content. */ class UnwrapAction extends ResultAction { /** * Creates an unwrap action with a given mode usage. * @param modeUsage The action mode usage. */ UnwrapAction(ModeUsage modeUsage) { super(modeUsage); } /** * Perform this action. * * @param handler ??? * @param state the section state. */ void perform(ContentHandler handler, SectionState state) { state.addChildMode(getModeUsage(), handler); } /** * Get a new unwrap action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ ResultAction changeCurrentMode(Mode mode) { return new UnwrapAction(getModeUsage().changeCurrentMode(mode)); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ValidateAction.java000066400000000000000000000025531225366607500324320ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.validate.Schema; import org.xml.sax.SAXException; /** * Validate no result action. * */ class ValidateAction extends NoResultAction { /** * The schema to validate with. */ private final Schema schema; /** * Creates a validate action. * @param modeUsage The mode usage. * @param schema The schema. */ ValidateAction(ModeUsage modeUsage, Schema schema) { super(modeUsage); this.schema = schema; } /** * Perform this action on the section state. * @param state the section state. */ void perform(SectionState state) throws SAXException { state.addValidator(schema, getModeUsage()); } /** * Get a new validate action with a mode usage with the current mode changed. * This is useful when we have modes extending other modes as we need to get * the actions from the base mode as actions on the new mode. */ NoResultAction changeCurrentMode(Mode mode) { return new ValidateAction(getModeUsage().changeCurrentMode(mode), schema); } /** * Checks if this action is equal with a given action. */ public boolean equals(Object obj) { return super.equals(obj) && schema.equals(((ValidateAction)obj).schema); } /** * Computes a hashCode. */ public int hashCode() { return super.hashCode() ^ schema.hashCode(); } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ValidatorImpl.java000066400000000000000000000773531225366607500323240ustar00rootroot00000000000000package com.thaiopensource.validate.nvdl; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.xml.util.Name; 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.SAXParseException; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Stack; import java.util.Vector; /** * Implementation of a validator of XML documents against NVDL scripts. */ class ValidatorImpl extends DefaultHandler implements Validator { /** * The name for the virtual element that we use for attribute section validation. * It has http://purl.oclc.org/dsdl/nvdl/ns/instance/1.0 as namespace and * virtualElement as name. */ static final Name OWNER_NAME = new Name("http://purl.oclc.org/dsdl/nvdl/ns/instance/1.0", "virtualElement"); /** * A value for really no namespace, that is different than any other value * for any possible namespace including no namespace which is an empty string. */ private static final String NO_NS = "\0"; /** * The error handler. */ private final ErrorHandler eh; /** * Properties. */ private final PropertyMap properties; /** * Triggers. * Specifies elements that start a new section. */ private final List triggers; /** * Source locator. */ private Locator locator; /** * Points to the current section. */ private Section currentSection; /** * The current namespace context, points to the last prefix mapping * the previous can be found on getParent and so on. */ private PrefixMapping prefixMapping = null; /** * A hashtable that keeps a stack of validators for schemas. */ private final Hashtable validatorHandlerCache = new Hashtable(); /** * Message localizer to report error messages from keys. */ private final Localizer localizer = new Localizer(ValidatorImpl.class); /** * keeps the no result actions for a section to avoid duplicating them * as the same action can be specified by multiple programs in a section. */ private final Hashset noResultActions = new Hashset(); /** * Stores index sets for attributed for each namespace. */ private final Hashtable attributeNamespaceIndexSets = new Hashtable(); /** * Sores the index sets for attributes for each active handler. * The index set specifies what attributes should be given to what handlers. */ private final Vector activeHandlersAttributeIndexSets = new Vector(); /** * Attribute schemas for a namespace. * It is used to avoid validating twice the set of attributes * from a namespace with the same schema. */ private final Hashset attributeSchemas = new Hashset(); /** * Flag indicating if we had a reject action on attributes from this namespace. * Useful to avoid reporting the same error multiple times. */ private boolean attributeNamespaceRejected; /** * We use this to compute * only once the filtered attributes for a namespace, * laysily when we will need them for the first time. */ private Attributes filteredAttributes; /** * The start mode for this NVDL script. */ private final Mode startMode; /** * Stores the element local names. Used for triggers. * This is a Stack. */ private final Stack elementsLocalNameStack; /** * Namespace context. Alinked list of proxy namespace * mapping linking to parent. */ static private class PrefixMapping { /** * Prefix. */ final String prefix; /** * Namespace uri. */ final String uri; /** * Link to parent mapping. */ final PrefixMapping parent; /** * Constructor. * @param prefix The prefix. * @param uri The namespace. * @param parent Parent mapping. */ PrefixMapping(String prefix, String uri, PrefixMapping parent) { this.prefix = prefix; this.uri = uri; this.parent = parent; } } /** * Store section information. */ private class Section implements SectionState { /** * The parent section. */ final Section parent; /** * Namespace of this section. Empty string for absent. */ final String ns; /** * Number of open elements in this section. */ int depth = 0; /** * List of the Validators rooted in this section */ final Vector validators = new Vector(); final Vector schemas = new Vector(); /** * List of the ContentHandlers that want to see the elements in this section */ final Vector activeHandlers = new Vector(); final Vector activeHandlersAttributeModeUsage = new Vector(); final Vector attributeValidationModeUsages = new Vector(); /** * List of Programs saying what to do with child sections */ final Vector childPrograms = new Vector(); /** * Keep the context stack if we have a context dependent section. */ final Stack context = new Stack(); /** * Flag indicating is this section depends on context or not. */ boolean contextDependent = false; /** * Max attribute processing value from all modes * in this section. */ int attributeProcessing = Mode.ATTRIBUTE_PROCESSING_NONE; /** * Stores the attach placeholder handlers. */ final Vector placeholderHandlers = new Vector(); /** * Stores the attach place holder mode usages. */ final Vector placeholderModeUsages = new Vector(); /** * Creates a section for a given namespace and links to to its parent section. * * @param ns The section namespace. * @param parent The parent section. */ Section(String ns, Section parent) { this.ns = ns; this.parent = parent; } /** * @param modeUsage The mode usage that determines the next mode. * @param handler The content handler that receives notifications. */ public void addChildMode(ModeUsage modeUsage, ContentHandler handler) { childPrograms.addElement(new Program(modeUsage, handler)); if (modeUsage.isContextDependent()) contextDependent = true; } /** * Adds a validator. * @param schema The schema to validate against. * @param modeUsage The mode usage for this validate action. */ public void addValidator(Schema schema, ModeUsage modeUsage) { // adds the schema to this section schemas schemas.addElement(schema); // creates the validator Validator validator = createValidator(schema); // adds the validator to this section validators validators.addElement(validator); // add the validator handler to the list of active handlers activeHandlers.addElement(validator.getContentHandler()); // add the mode usage to the active handlers attribute mode usage list activeHandlersAttributeModeUsage.addElement(modeUsage); // compute the attribute processing attributeProcessing = Math.max(attributeProcessing, modeUsage.getAttributeProcessing()); // add a child mode with this mode usage and the validator content handler childPrograms.addElement(new Program(modeUsage, validator.getContentHandler())); if (modeUsage.isContextDependent()) contextDependent = true; } /** * Adds a handler for a mode usage. * @param handler The content handler to be added. * @param attributeModeUsage The mode usage. */ public void addActiveHandler(ContentHandler handler, ModeUsage attributeModeUsage) { activeHandlers.addElement(handler); activeHandlersAttributeModeUsage.addElement(attributeModeUsage); attributeProcessing = Math.max(attributeProcessing, attributeModeUsage.getAttributeProcessing()); if (attributeModeUsage.isContextDependent()) contextDependent = true; } /** * Adds a mode usage to the attributeValidationModeUsages list * if we process attributes. */ public void addAttributeValidationModeUsage(ModeUsage modeUsage) { int ap = modeUsage.getAttributeProcessing(); if (ap != Mode.ATTRIBUTE_PROCESSING_NONE) { attributeValidationModeUsages.addElement(modeUsage); attributeProcessing = Math.max(ap, attributeProcessing); if (modeUsage.isContextDependent()) contextDependent = true; } } /** * Reject content, report an error. */ public void reject() throws SAXException { if (eh != null) eh.error(new SAXParseException(localizer.message("reject_element", ns), locator)); } public void attachPlaceholder(ModeUsage modeUsage, ContentHandler handler) { placeholderHandlers.add(handler); placeholderModeUsages.add(modeUsage); } } /** * A program is a pair of mode usage and handler. * */ static private class Program { /** * The mode usage associated with the handler. */ final ModeUsage modeUsage; /** * The handler associated with the mode usage. */ final ContentHandler handler; /** * Creates an association between a mode usage and a handler. * @param modeUsage The mode usage. * @param handler The handler. */ Program(ModeUsage modeUsage, ContentHandler handler) { this.modeUsage = modeUsage; this.handler = handler; } } /** * Creates a NVDL validator. The initial mode is specified by the mode parameter. * Initializes the current section. * @param mode The start mode. * param triggers The triggers specified by the NVDL script. * @param properties Validation properties. */ ValidatorImpl(Mode mode, List triggers, PropertyMap properties) { this.properties = properties; this.triggers = triggers; this.eh = properties.get(ValidateProperty.ERROR_HANDLER); this.startMode = mode; this.elementsLocalNameStack = new Stack(); initCurrentSection(); } /** * Initializes the current session. * Creates a section for a dummy namespace (differnet of "", that is no namespace). * Adds as child mode usage for this a mode usage with start mode as current mode * and that uses start mode. No content handler is set on addChildMode. * */ private void initCurrentSection() { currentSection = new Section(NO_NS, null); currentSection.addChildMode(new ModeUsage(startMode, startMode), null); } /** * Set document locator callback. * @param locator The document locator. */ public void setDocumentLocator(Locator locator) { this.locator = locator; } /** * characters callback. * Dispatch it to all active handlers from the current section. */ public void characters(char ch[], int start, int length) throws SAXException { for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).characters(ch, start, length); } /** * ignorable whitespace callback. * Dispatch it to all active handlers from the current section. */ public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).ignorableWhitespace(ch, start, length); } /** * startElement callback. * * @param uri The element namespace. * @param localName The element local name. * @param qName The element qualified name. * @param attributes The attributes for this element. */ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // if we have a different namespace than the current section namespace // or there's an applicable trigger // then we start a new section on the new namespace. if (!uri.equals(currentSection.ns) || trigger(uri, localName, (String)elementsLocalNameStack.peek())) startSection(uri); elementsLocalNameStack.push(localName); // increase the depth in the current section as we have a new element currentSection.depth++; // if the current section contains context dependent mode usages then // we record the local elements in a stack as they form the current path // that determines the context if (currentSection.contextDependent) currentSection.context.push(localName); // check if we need to filter attributes or not // and process attributes, eventually validating attribute sections boolean transformAttributes = processAttributes(attributes); // iterate the active session handlers and call start element on them for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) { ContentHandler handler = (ContentHandler)(currentSection.activeHandlers.elementAt(i)); handler.startElement(uri, localName, qName, transformAttributes // if we need to filter attributes keep the ones the handler is interested in. ? filterAttributes((IntSet)activeHandlersAttributeIndexSets.elementAt(i), attributes) // otherwise just pass all the attributes : attributes); } if (currentSection.depth == 1 && currentSection.placeholderHandlers.size() > 0) { AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "ns", "ns", "", uri); atts.addAttribute("", "localName", "localName", "", localName); for (int i = 0, len = currentSection.placeholderHandlers.size(); i < len; i++) { ContentHandler handler = (ContentHandler)(currentSection.placeholderHandlers.elementAt(i)); handler.startPrefixMapping("", "http://purl.oclc.org/dsdl/nvdl/ns/instance/1.0"); handler.startElement("http://purl.oclc.org/dsdl/nvdl/ns/instance/1.0", "placeholder", "placeholder", atts); } } } /** * Checks if a trigger matches. * @param namespace The namespace. * @param name The local name. * @param parent The local name of the parent. * @return true if we have a trigger set, otherwise false. */ private boolean trigger(String namespace, String name, String parent) { // iterate triggers Iterator i = triggers.iterator(); while (i.hasNext()) { Trigger t = (Trigger)i.next(); if ((t.namespace.equals(namespace) && t.elementNames.contains(name) && !t.elementNames.contains(parent))) { return true; } } return false; } /** * Get the filtered attributes. * It checks if we want all the attributes and in that case returns the initial attributes, * otherwise creates a FilteredAttributes instance based on the index set and on the attributes. * @param indexSet The set with the indexes of the attributes we want to keep. * @param attributes The list of attributes * @return the attributes containing only those whose indexes are in the indexSet. */ private static Attributes filterAttributes(IntSet indexSet, Attributes attributes) { if (indexSet.size() == attributes.getLength()) return attributes; return new FilteredAttributes(indexSet, attributes); } /** * Processes the element attributes. * * @param attributes The element attributes * @return true if we need to filter attributes when we pass them to the * active handlers, false if we can just pass the initial attributes * to all the active content handlers * @throws SAXException */ private boolean processAttributes(Attributes attributes) throws SAXException { // if no match on attributes or no attributes -> no need to filter them. if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_NONE || attributes.getLength() == 0) return false; // clear the attributeNamespaceIndexSets hashtable. attributeNamespaceIndexSets.clear(); // creates index sets based on namespace for the attributes // and places them in the attributeNamespaceIndexSets hashtable for (int i = 0, len = attributes.getLength(); i < len; i++) { String ns = attributes.getURI(i); IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); if (indexSet == null) { indexSet = new IntSet(); attributeNamespaceIndexSets.put(ns, indexSet); } indexSet.add(i); } // if we need to process only qualified attributes and we have attributes // only in no namespace then return false, no need to filter the attributes if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_QUALIFIED && attributeNamespaceIndexSets.size() == 1 && attributeNamespaceIndexSets.get("") != null) return false; // Computes the index sets for each handler // get the attribute modes for handlers Vector handlerModes = currentSection.activeHandlersAttributeModeUsage; // resize the index set list to the number of handlers activeHandlersAttributeIndexSets.setSize(handlerModes.size()); // creates empty index sets for all handlers - initialization for (int i = 0, len = handlerModes.size(); i < len; i++) activeHandlersAttributeIndexSets.setElementAt(new IntSet(), i); // we hope we will not need attribute filtering, so we start with transform false. boolean transform = false; // get the list of attribute validation mode usages Vector validationModes = currentSection.attributeValidationModeUsages; // iterate on all attribute namespaces for (Enumeration e = attributeNamespaceIndexSets.keys(); e.hasMoreElements();) { String ns = (String)e.nextElement(); // get the index set that represent the attributes in the ns namespace IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); // clear attribute schemas for this namespace // it is used to avoid validating twice the set of attributes // from this namespace with the same schema. attributeSchemas.clear(); // set the filetered attributes to null - we use this to compute // only one the filtered attributes for this namespace, laysily when we // will need them for the first time. filteredAttributes = null; // flag indicating if we had a reject action on attributes from this namespace // we initialize it here in the iteration on attribute namespaces attributeNamespaceRejected = false; // iterates all the handler modes and compute the index sets for all handlers for (int i = 0, len = handlerModes.size(); i < len; i++) { ModeUsage modeUsage = (ModeUsage)handlerModes.elementAt(i); // get the attribute actions for this mode usage, ns namespace // and for the attributes in this namespace AttributeActionSet actions = processAttributeSection(modeUsage, ns, indexSet, attributes); // if we need to attach the attributes we mark that they should be passed // to the handler by adding them to the index set for the handler if (actions.getAttach()) ((IntSet)activeHandlersAttributeIndexSets.get(i)).addAll(indexSet); else // if that attributes are not attached then we set the transform flag to // true as that means we need to filter out these attributes for the current handler transform = true; } // iterate the attribute validation mode usages // and process the attribute section with the attributes // from the current namespace for (int i = 0, len = validationModes.size(); i < len; i++) { ModeUsage modeUsage = (ModeUsage)validationModes.elementAt(i); // validation means no result actions, so we are not // interested in the attribute action set returned by // the processAttributeSection method processAttributeSection(modeUsage, ns, indexSet, attributes); } } return transform; } /** * Process an attributes section in a specific mode usage. * @param modeUsage The mode usage * @param ns The attribute section namespace * @param indexSet The indexes of the attributes in the given namespace * @param attributes All the attributes * @return The set of attribute actions * @throws SAXException */ private AttributeActionSet processAttributeSection(ModeUsage modeUsage, String ns, IntSet indexSet, Attributes attributes) throws SAXException { // get the next mode from the mode usage depending on context Mode mode = modeUsage.getMode(currentSection.context); // get the attribute action set AttributeActionSet actions = mode.getAttributeActions(ns); // Check if we have a reject action and if we did not reported already // the reject attribute error for this namespace if (actions.getReject() && !attributeNamespaceRejected) { // set the flag to avoid reporting this error again for the same namespace attributeNamespaceRejected = true; if (eh != null) eh.error(new SAXParseException(localizer.message("reject_attribute", ns), locator)); } // get the eventual schemas and validate the attributes against them Schema[] schemas = actions.getSchemas(); for (int j = 0; j < schemas.length; j++) { // if we already validated against this schema, skip it if (attributeSchemas.contains(schemas[j])) continue; // add the schema so that we will not validate again the same attributes against it attributeSchemas.add(schemas[j]); // if we do not computed the filtered attributes for this namespace, compute them if (filteredAttributes == null) filteredAttributes = filterAttributes(indexSet, attributes); // validate the filtered attributes with the schema validateAttributes(schemas[j], filteredAttributes); } // return the actions in case they are needed further. return actions; } /** * Validates a set of attributes with an attribute schema. * @param schema The attributes schema. * @param attributes The attributes to be validated * @throws SAXException */ private void validateAttributes(Schema schema, Attributes attributes) throws SAXException { // creates a validator for this attributes schema. Validator validator = createValidator(schema); // get its content handler ContentHandler ch = validator.getContentHandler(); // initializes the handler with locator and proxy namespace mapping. initHandler(ch); // notifies a the wrapper element with the attributes ch.startElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName(), attributes); ch.endElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName()); // removes namespaces and signals end document to the handler cleanupHandler(ch); // release the validator so further validate actions with this schema can reuse it releaseValidator(schema, validator); } /** * Start a new section on a given namespace. * Called from startElement when we encounter an element * whose namepsace does not match the current section namespace * or if we get an element declared as a new section trigger in the * NVDL script. * @param uri The new namespace. * @throws SAXException */ private void startSection(String uri) throws SAXException { // creates a new section having the current section as parent section Section section = new Section(uri, currentSection); // get the programs of the current section Vector childPrograms = currentSection.childPrograms; // clear the current no result (validation) actions noResultActions.clear(); // iterates current section programs for (int i = 0, len = childPrograms.size(); i < len; i++) { Program program = (Program)childPrograms.elementAt(i); // get the mode usage for the program // and determine the use mode from the mode usage based on the current section context // and then get the element actions from that determined mode // that apply to the new namespace ActionSet actions = program.modeUsage.getMode(currentSection.context).getElementActions(uri); // check if we have a result action attach/unwrap // and perform it on the program handler and the new section ResultAction resultAction = actions.getResultAction(); if (resultAction != null) resultAction.perform(program.handler, section); // get the no result (validate, allow, reject) actions NoResultAction[] nra = actions.getNoResultActions(); for (int j = 0; j < nra.length; j++) { NoResultAction tem = nra[j]; // if we did not encountered this action already then perform it on the // section and add it to the noResultActions list if (!noResultActions.contains(tem)) { nra[j].perform(section); noResultActions.add(tem); } } } // iterate the validators on the new section and set their content // handler to receive notifications and set the locator, // call start document, and bind the current namespace context. for (int i = 0, len = section.validators.size(); i < len; i++) initHandler(((Validator)section.validators.elementAt(i)).getContentHandler()); // store the new section as the current section currentSection = section; } /** * Initialize a content handler. This content handler will receive the * document fragment starting at the current element. Therefore we need * to set a locator, call startDocument and give the current namespace * content to that content handler. * @param ch The content handler. * @throws SAXException */ private void initHandler(ContentHandler ch) throws SAXException { // set the locator if (locator != null) ch.setDocumentLocator(locator); // start the document ch.startDocument(); // set the namespace context for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) ch.startPrefixMapping(pm.prefix, pm.uri); } /** * endElement callback * @param uri The namespace uri * @param localName The element local name * @param qName The element qualified name */ public void endElement(String uri, String localName, String qName) throws SAXException { elementsLocalNameStack.pop(); // iterate the active handlers from the current section and call // endElement on them for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) ((ContentHandler)(currentSection.activeHandlers.elementAt(i))).endElement(uri, localName, qName); // decrease the current section depth currentSection.depth--; // if we keep context information (if the section is context dependent) // then remove that information if (currentSection.contextDependent) currentSection.context.pop(); // if we have zero depth then the current section was ended, so we call endSection if (currentSection.depth == 0) { for (int i = 0, len = currentSection.placeholderHandlers.size(); i < len; i++) { ContentHandler handler = (ContentHandler)(currentSection.placeholderHandlers.elementAt(i)); handler.endPrefixMapping(""); handler.endElement("http://purl.oclc.org/dsdl/nvdl/ns/instance/1.0", "placeholder", "placeholder"); } endSection(); } } /** * End a section, its depth reached zero. * @throws SAXException */ private void endSection() throws SAXException { // iterate validators for (int i = 0, len = currentSection.validators.size(); i < len; i++) { Validator validator = (Validator)currentSection.validators.elementAt(i); // remove namespaces and call end document on each handler cleanupHandler(validator.getContentHandler()); // release the validators to the cache be reused further on other sections releaseValidator((Schema)currentSection.schemas.elementAt(i), validator); // endDocument() on one of the validators may throw an exception // in this case we don't want to release the validator twice currentSection.validators.setElementAt(null, i); } // set the parent section as the current section currentSection = currentSection.parent; } /** * Cleanup a handler. * Remove proxy namespace mappings calling endPrefixMapping and calls also endDocument * to signal that the source was ended. * @param vh The validator content handler to clean up. * @throws SAXException */ private void cleanupHandler(ContentHandler vh) throws SAXException { for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) vh.endPrefixMapping(pm.prefix); vh.endDocument(); } /** * endDocument callback * We should be in the initial section now so no op is required. */ public void endDocument() throws SAXException { } /** * start prefix mapping callback */ public void startPrefixMapping(String prefix, String uri) throws SAXException { super.startPrefixMapping(prefix, uri); prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); } /** * end prefix mapping callback */ public void endPrefixMapping(String prefix) throws SAXException { super.endPrefixMapping(prefix); prefixMapping = prefixMapping.parent; } /** * Get a validator for a schema. * If we already have a validator for this schema available in cache * then we will use it and remove it from cache. At the end it will be * added back to the cache through releaseValidator. * @param schema The schema we need a validaor for. * @return A Validator for the given schema. */ private Validator createValidator(Schema schema) { Stack stack = (Stack)validatorHandlerCache.get(schema); if (stack == null) { stack = new Stack(); validatorHandlerCache.put(schema, stack); } if (stack.empty()) return schema.createValidator(properties); return (Validator)stack.pop(); } /** * Releases a validator for a given schema. Put that validator in the * cache so that further actions to validate against this schema will * be able to use this validator instead of creating a new one. * @param schema The schema the validator validates against * @param vh The validator. */ private void releaseValidator(Schema schema, Validator vh) { if (vh == null) return; vh.reset(); ((Stack)validatorHandlerCache.get(schema)).push(vh); } /** * Reset the NVDL validator so it can be used further on * other sources. */ public void reset() { // iterrate all sections from the current section up to the root. for (; currentSection != null; currentSection = currentSection.parent) { // if we have validators in this section iterate them for (int i = 0, len = currentSection.validators.size(); i < len; i++) // release the validator releaseValidator((Schema)currentSection.schemas.elementAt(i), (Validator)currentSection.validators.elementAt(i)); } // create the initial section in the start mode. initCurrentSection(); } /** * Get the content handler for this NVDL validator. */ public ContentHandler getContentHandler() { return this; } /** * Get the DTD handler for this NVDL validator. */ public DTDHandler getDTDHandler() { return this; } } jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/resources/000077500000000000000000000000001225366607500307055ustar00rootroot00000000000000Messages.properties000066400000000000000000000033101225366607500345100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/resourcesreject_element=elements from namespace \"{0}\" are not allowed reject_attribute=attributes from namespace \"{0}\" are not allowed undefined_mode=mode \"{0}\" not defined schema_fragment_id=schema URI must not have a fragment identifier ns_absolute=namespace URI must be absolute URI unexpected_slash=unexpected \"/\" expected_slash=expected \"/\" expected_name=expected a name empty_path=empty path invalid_name=invalid name duplicate_path=context with path \"{0}\" already defined duplicate_mode=mode \"{0}\" already defined first_mode=mode \"{0}\" was first defined here duplicate_attribute_action_any_namespace=rule for attributes from any namespace already specified in this mode duplicate_attribute_action=rule for attributes from namespace \"{0}\" already specified in this mode duplicate_element_action_any_namespace=rule for elements from any namespace already specified in this mode duplicate_element_action=rule for elements from namespace \"{0}\" already specified in this mode mode_cycle=mode \"{0}\" directly or indirectly extends itself unknown_option=option \"{0}\" not recognized unsupported_option=option \"{0}\" is not supported for this kind of schema unsupported_option_arg=specified argument for option \"{0}\" is not supported duplicate_option=option \"{0}\" cannot be specified more than once option_requires_argument=option \"{0}\" requires an argument option_unexpected_argument=option \"{0}\" does not take an argument option_bad_argument=invalid argument for option \"{0}\" legacy_rnc_media_type=the application/x-rnc media type is deprecated, please use application/relax-ng-compact-syntax instead embedded_schemas=embedded schemas are not yet supported no_schema=no schema specified for the validate action jing-trang-20131210+dfsg+1/mod/nvdl/src/main/com/thaiopensource/validate/nvdl/resources/nvdl.rng000066400000000000000000000235251225366607500323670ustar00rootroot00000000000000 1 elements attributes attributes elements elements attributes allow reject attach attachPlaceholder unwrap \s*[0-9A-Za-z!#$%&'\*\+\-\.\^_`\{\|\}~]*/[0-9A-Za-z!#$%&'\*\+\-\.\^_`\{\|\}~]*\s* \s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*(\|\s*(/\s*)?\i\c*(\s*/\s*\i\c*)*\s*)* default preserve jing-trang-20131210+dfsg+1/mod/nvdl/test/000077500000000000000000000000001225366607500175755ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/nvdl/test/mnstest.xml000066400000000000000000001121641225366607500220210ustar00rootroot00000000000000 aval bval ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:Description rdf:aboutEach rdf:aboutEachPrefix Literal Resource Collection A title

    Hello.

    A title

    Hello.

    A title<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>

    Hello.

    A title

    Hello.

    element a { empty }
    jing-trang-20131210+dfsg+1/mod/nvdl/test/nrltest.xml000066400000000000000000001461661225366607500220300ustar00rootroot00000000000000 ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:Description rdf:aboutEach rdf:aboutEachPrefix Literal Resource Collection A title

    Hello.

    A title

    Hello.

    A title<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>

    Hello.

    A title

    Hello.

    ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv default namespace = "http://www.example.com/version" element linux|windows { empty } A test A test

    Text.

    A test

    Text.

    A test

    Text.

    Windows.

    A test

    Text.

    • Windows
    • Linux
    A test

    Text.

    • Windows
    • Linux
    namespace a = "http://www.example.org/a" attribute a:x { text }, attribute a:y { text } ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv Prose in the spec does not specify that attributes are allowed on the Body element 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification Fault reporting structure Document 1

    ...

    Document 2

    ...

    Document 1

    ...

    Document 1

    ...

    Document 1

    ...

    Document 1

    ...

    default namespace = "http://example.com/ns/0" element root { empty }
    jing-trang-20131210+dfsg+1/mod/nvdl/test/nvdltest.rng000066400000000000000000000004621225366607500221520ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/nvdl/test/nvdltest.xml000066400000000000000000001471461225366607500221770ustar00rootroot00000000000000 ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:Description rdf:aboutEach rdf:aboutEachPrefix rdf:RDF rdf:ID rdf:about rdf:bagID rdf:parseType rdf:resource rdf:nodeID rdf:datatype rdf:li rdf:Description rdf:aboutEach rdf:aboutEachPrefix Literal Resource Collection A title

    Hello.

    A title

    Hello.

    A title<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>

    Hello.

    A title

    Hello.

    ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv default namespace = "http://www.example.com/version" element linux|windows { empty } A test A test

    Text.

    A test

    Text.

    A test

    Text.

    Windows.

    A test

    Text.

    • Windows
    • Linux
    A test

    Text.

    • Windows
    • Linux
    namespace a = "http://www.example.org/a" attribute a:x { text }, attribute a:y { text } ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv Prose in the spec does not specify that attributes are allowed on the Body element 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification Fault reporting structure Document 1

    ...

    Document 2

    ...

    Document 1

    ...

    Document 1

    ...

    Document 1

    ...

    Document 1

    ...

    default namespace = "http://example.com/ns/0" element root { empty }
    jing-trang-20131210+dfsg+1/mod/pattern/000077500000000000000000000000001225366607500173305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/mod.xml000066400000000000000000000003101225366607500206230ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/pattern/src/000077500000000000000000000000001225366607500201175ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/000077500000000000000000000000001225366607500210435ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/000077500000000000000000000000001225366607500216215ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/000077500000000000000000000000001225366607500246515ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500263115ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/match/000077500000000000000000000000001225366607500274055ustar00rootroot00000000000000IncorrectSchemaException.java000066400000000000000000000001471225366607500351230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/matchpackage com.thaiopensource.relaxng.match; public class IncorrectSchemaException extends Exception { } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/match/MatchContext.java000066400000000000000000000013751225366607500326570ustar00rootroot00000000000000package com.thaiopensource.relaxng.match; import org.relaxng.datatype.ValidationContext; /** * Extends ValidationContext to provide information about which namespace URI is bound * to a prefix. */ public interface MatchContext extends ValidationContext { /** * Return a prefix bound to a namespace URI. When multiple prefixes * are bound to a namespace URI, one of the innermost such ones should be returned. * If namespaceURI is the empty string, null will be returned. * @param namespaceURI a String containing a namespace URI; must not be null * @return a non-empty prefix bound to namespaceURI, or null if no prefix is bound or if it is not * known which prefix is bound to namespaceURI */ String getPrefix(String namespaceURI); } MatchablePattern.java000066400000000000000000000005651225366607500334150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/matchpackage com.thaiopensource.relaxng.match; /** * A RELAX NG pattern that can be matched against an XML document. * A MatchablePattern object is safe for concurrent accesss * from multiple threads. */ public interface MatchablePattern { /** * Create a Matcher for matching against this pattern. * @return a Matcher, never null */ Matcher createMatcher(); } MatchablePatternLoader.java000066400000000000000000000050531225366607500345410ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/matchpackage com.thaiopensource.relaxng.match; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.compact.CompactParseable; import com.thaiopensource.relaxng.parse.sax.SAXParseable; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.FeasibleTransform; import com.thaiopensource.relaxng.pattern.MatchablePatternImpl; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.SchemaBuilderImpl; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.VoidValue; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import java.io.IOException; /** * Provides method to load a MatchablePattern by parsing. */ public class MatchablePatternLoader { public static final int COMPACT_SYNTAX_FLAG = 0x1; public static final int FEASIBLE_FLAG = 0x2; public MatchablePattern load(Input input, SAXResolver saxResolver, ErrorHandler eh, DatatypeLibraryFactory dlf, int flags) throws IOException, SAXException, IncorrectSchemaException { SchemaPatternBuilder spb = new SchemaPatternBuilder(); Parseable parseable; if ((flags & COMPACT_SYNTAX_FLAG) != 0) parseable = new CompactParseable(input, saxResolver.getResolver(), eh); else parseable = new SAXParseable(saxResolver.createSAXSource(input), saxResolver, eh); if (dlf == null) dlf = new DatatypeLibraryLoader(); try { Pattern start = SchemaBuilderImpl.parse(parseable, eh, dlf, spb, false); if ((flags & FEASIBLE_FLAG) != 0) start = FeasibleTransform.transform(spb, start); return new MatchablePatternImpl(spb, start); } catch (IllegalSchemaException e) { throw new IncorrectSchemaException(); } } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/match/Matcher.java000066400000000000000000000240171225366607500316370ustar00rootroot00000000000000package com.thaiopensource.relaxng.match; import com.thaiopensource.xml.util.Name; import java.util.Set; /** * Represents the state of matching an XML document against a RELAX NG pattern. * The XML document is considered as a linear sequence of events of different * kinds. For each kind of event E in the sequence, a call must be made * to a corresponding method matchE on the * Matcher object. The kinds of event are: *

    *

      *
    • StartDocument
    • *
    • StartTagOpen
    • *
    • AttributeName
    • *
    • AttributeValue
    • *
    • StartTagClose
    • *
    • Text
    • *
    • EndTag
    • *
    • EndDocument
    • *
    *

    *

    The method calls must occur in an order corresponding to a well-formed XML * document. In a well-formed document the sequence of events matches * the following grammar: *

    *

     * document ::= StartDocument element EndDocument
     * element ::= startTag child* EndTag
     * startTag ::= StartTagOpen attribute* StartTagClose
     * attribute ::= AttributeName AttributeValue
     * child ::= element | Text
     * 
    *

    *

    Text events must be maximal. Two consecutive Text events are not allowed. * Matching text is special, and is done with matchTextBeforeStartTag * or matchTextBeforeEndTag, according as the Text event is * followed by a StartTagOpen or an EndTag event. Callers may optionally choose * to optimize calls to matchTextBeforeStartTag * or matchTextBeforeEndTag into calls to matchUntypedText, * but this is only allowed when isTextTyped returns false. *

    *

    Each method matchE returns false if matching * the event against the document resulted in an error and true otherwise. * If it returned false, then the error message can be obtained using * getErrorMessage. In either case, the state of the * Matcher changes so the Matcher is prepared * to match the next event. *

    *

    installHandlers(XMLReader xr, SchemaBuilder schemaBuilder, Scope scope) throws SAXException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Parseable.java000066400000000000000000000005011225366607500324010ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface Parseable, A extends Annotations> extends SubParser { P parse(SchemaBuilder f, Scope scope) throws BuildException, IllegalSchemaException; } ParsedPatternFuture.java000066400000000000000000000002151225366607500343750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public interface ParsedPatternFuture

    { P getParsedPattern() throws IllegalSchemaException; } SchemaBuilder.java000066400000000000000000000054771225366607500331540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; import java.util.List; public interface SchemaBuilder, A extends Annotations> { P makeChoice(List

    patterns, L loc, A anno) throws BuildException; P makeInterleave(List

    patterns, L loc, A anno) throws BuildException; P makeGroup(List

    patterns, L loc, A anno) throws BuildException; P makeOneOrMore(P p, L loc, A anno) throws BuildException; P makeZeroOrMore(P p, L loc, A anno) throws BuildException; P makeOptional(P p, L loc, A anno) throws BuildException; P makeList(P p, L loc, A anno) throws BuildException; P makeMixed(P p, L loc, A anno) throws BuildException; P makeEmpty(L loc, A anno); P makeNotAllowed(L loc, A anno); P makeText(L loc, A anno); P makeAttribute(NC nc, P p, L loc, A anno) throws BuildException; P makeElement(NC nc, P p, L loc, A anno) throws BuildException; DataPatternBuilder makeDataPatternBuilder(String datatypeLibrary, String type, L loc) throws BuildException; P makeValue(String datatypeLibrary, String type, String value, Context c, String ns, L loc, A anno) throws BuildException; Grammar makeGrammar(Scope parent); P annotatePattern(P p, A anno) throws BuildException; NC annotateNameClass(NC nc, A anno) throws BuildException; P annotateAfterPattern(P p, EA e) throws BuildException; NC annotateAfterNameClass(NC nc, EA e) throws BuildException; P commentAfterPattern(P p, CL comments) throws BuildException; NC commentAfterNameClass(NC nc, CL comments) throws BuildException; P makeExternalRef(String href, String base, String ns, Scope scope, L loc, A anno) throws BuildException, IllegalSchemaException; NC makeNameClassChoice(List nameClasses, L loc, A anno); // Compare against INHERIT_NS with == not equals. // Doing new String() ensures it is not == if the user specifies #inherit explicitly in the schema. static final String INHERIT_NS = new String("#inherit"); NC makeName(String ns, String localName, String prefix, L loc, A anno); NC makeNsName(String ns, L loc, A anno); /* * Caller must enforce constraints on except. */ NC makeNsName(String ns, NC except, L loc, A anno); NC makeAnyName(L loc, A anno); /* * Caller must enforce constraints on except. */ NC makeAnyName(NC except, L loc, A anno); L makeLocation(String systemId, int lineNumber, int columnNumber); A makeAnnotations(CL comments, Context context); ElementAnnotationBuilder makeElementAnnotationBuilder(String ns, String localName, String prefix, L loc, CL comments, Context context); CL makeCommentList(); P makeErrorPattern(); NC makeErrorNameClass(); boolean usesComments(); } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Scope.java000066400000000000000000000004211225366607500315550ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface Scope, A extends Annotations> { P makeParentRef(String name, L loc, A anno) throws BuildException; P makeRef(String name, L loc, A anno) throws BuildException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/SubParseable.java000066400000000000000000000007301225366607500330570ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface SubParseable, A extends Annotations> extends Parseable { P parseAsInclude(SchemaBuilder f, IncludedGrammar g) throws BuildException, IllegalSchemaException; /* The returned URI will have disallowed characters escaped. May return null for top-level schema. */ String getUri(); } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/SubParser.java000066400000000000000000000003751225366607500324220ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface SubParser, A extends Annotations> { SubParseable createSubParseable(String href, String base) throws BuildException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compact/000077500000000000000000000000001225366607500312725ustar00rootroot00000000000000CompactParseable.java000066400000000000000000000076521225366607500352750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compactpackage com.thaiopensource.relaxng.parse.compact; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.relaxng.parse.SubParseable; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.MediaTypedIdentifier; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.util.Uri; import com.thaiopensource.xml.util.EncodingMap; import org.xml.sax.ErrorHandler; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PushbackInputStream; import java.io.Reader; public class CompactParseable, A extends Annotations> implements SubParseable { private final Input in; private final Resolver resolver; private final ErrorHandler eh; private static final String MEDIA_TYPE = "application/relax-ng-compact-syntax"; public CompactParseable(Input in, Resolver resolver, ErrorHandler eh) { this.in = in; this.resolver = resolver; this.eh = eh; } public P parse(SchemaBuilder sb, Scope scope) throws BuildException, IllegalSchemaException { return new CompactSyntax(makeReader(in), in.getUri(), sb, eh).parse(scope); } public SubParseable createSubParseable(String href, String base) throws BuildException { Identifier id = new MediaTypedIdentifier(href, base, MEDIA_TYPE); Input input = new Input(); try { resolver.resolve(id, input); } catch (ResolverException e) { throw BuildException.fromResolverException(e); } catch (IOException e) { throw new BuildException(e); } return new CompactParseable(input, resolver, eh); } public P parseAsInclude(SchemaBuilder sb, IncludedGrammar g) throws BuildException, IllegalSchemaException { return new CompactSyntax(makeReader(in), in.getUri(), sb, eh).parseInclude(g); } public String getUri() { String uri = in.getUri(); if (uri == null) return null; return Uri.escapeDisallowedChars(uri); } private static final String UTF8 = EncodingMap.getJavaName("UTF-8"); private static final String UTF16 = EncodingMap.getJavaName("UTF-16"); private Reader makeReader(Input in) throws BuildException { try { resolver.open(in); Reader reader = in.getCharacterStream(); if (reader == null) { InputStream byteStream = in.getByteStream(); if (byteStream == null) throw new IllegalArgumentException("invalid input for CompactParseable"); String encoding = in.getEncoding(); if (encoding == null) { PushbackInputStream pb = new PushbackInputStream(byteStream, 2); encoding = detectEncoding(pb); byteStream = pb; } reader = new InputStreamReader(byteStream, encoding); } return reader; } catch (ResolverException e) { throw BuildException.fromResolverException(e); } catch (IOException e) { throw new BuildException(e); } } static private String detectEncoding(PushbackInputStream in) throws IOException { String encoding = UTF8; int b1 = in.read(); if (b1 != -1) { int b2 = in.read(); if (b2 != -1) { in.unread(b2); if ((b1 == 0xFF && b2 == 0xFE) || (b1 == 0xFE && b2 == 0xFF)) encoding = UTF16; } in.unread(b1); } return encoding; } } CompactSyntax.jj000066400000000000000000001407111225366607500343410ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compactoptions { STATIC = false; UNICODE_INPUT = true; JAVA_UNICODE_ESCAPE = true; } PARSER_BEGIN(CompactSyntax) package com.thaiopensource.relaxng.parse.compact; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.Context; import com.thaiopensource.relaxng.parse.DataPatternBuilder; import com.thaiopensource.relaxng.parse.Div; import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; import com.thaiopensource.relaxng.parse.Grammar; import com.thaiopensource.relaxng.parse.GrammarSection; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Include; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.util.Ref; import com.thaiopensource.xml.util.WellKnownNamespaces; import com.thaiopensource.util.Localizer; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.LocatorImpl; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.io.Reader; public class CompactSyntax, AnnotationsImpl extends Annotations> implements Context { private static final int IN_ELEMENT = 0; private static final int IN_ATTRIBUTE = 1; private static final int IN_ANY_NAME = 2; private static final int IN_NS_NAME = 4; private String defaultNamespace = SchemaBuilder.INHERIT_NS; private String compatibilityPrefix = null; private SchemaBuilder sb; private String sourceUri; private ErrorHandler eh; private final Map namespaceMap = new HashMap(); private final Map datatypesMap = new HashMap(); private boolean hadError = false; private static final Localizer localizer = new Localizer(CompactSyntax.class); private final Set attributeNames = new HashSet(); private boolean annotationsIncludeElements = false; final class LocatedString { private final String str; private final Token tok; LocatedString(String str, Token tok) { this.str = str; this.tok = tok; } String getString() { return str; } Location getLocation() { return makeLocation(tok); } Token getToken() { return tok; } } public CompactSyntax(Reader r, String sourceUri, SchemaBuilder sb, ErrorHandler eh) { this(r); this.sourceUri = sourceUri; this.sb = sb; this.eh = eh; // this causes the root pattern to have non-null annotations // which is useful because it gives a context to trang this.topLevelComments = sb.makeCommentList(); } Pattern parse(Scope scope) throws IllegalSchemaException { try { Pattern p = Input(scope); if (!hadError) return p; } catch (ParseException e) { error("syntax_error", e.currentToken.next); } catch (EscapeSyntaxException e) { reportEscapeSyntaxException(e); } throw new IllegalSchemaException(); } Pattern parseInclude(IncludedGrammar g) throws IllegalSchemaException { try { Pattern p = IncludedGrammar(g); if (!hadError) return p; } catch (ParseException e) { error("syntax_error", e.currentToken.next); } catch (EscapeSyntaxException e) { reportEscapeSyntaxException(e); } throw new IllegalSchemaException(); } private void checkNsName(int context, LocatedString ns) { if ((context & IN_NS_NAME) != 0) error("ns_name_except_contains_ns_name", ns.getToken()); } private void checkAnyName(int context, Token t) { if ((context & IN_NS_NAME) != 0) error("ns_name_except_contains_any_name", t); if ((context & IN_ANY_NAME) != 0) error("any_name_except_contains_any_name", t); } private void error(String key, Token tok) { doError(localizer.message(key), tok); } private void error(String key, String arg, Token tok) { doError(localizer.message(key, arg), tok); } private void error(String key, String arg1, String arg2, Token tok) { doError(localizer.message(key, arg1, arg2), tok); } private void doError(String message, Token tok) { hadError = true; if (eh != null) { LocatorImpl loc = new LocatorImpl(); loc.setLineNumber(tok.beginLine); loc.setColumnNumber(tok.beginColumn); loc.setSystemId(sourceUri); try { eh.error(new SAXParseException(message, loc)); } catch (SAXException se) { throw new BuildException(se); } } } private void reportEscapeSyntaxException(EscapeSyntaxException e) { if (eh != null) { LocatorImpl loc = new LocatorImpl(); loc.setLineNumber(e.getLineNumber()); loc.setColumnNumber(e.getColumnNumber()); loc.setSystemId(sourceUri); try { eh.error(new SAXParseException(localizer.message(e.getKey()), loc)); } catch (SAXException se) { throw new BuildException(se); } } } private static String unquote(String s) { if (s.length() >= 6 && s.charAt(0) == s.charAt(1)) { s = s.replace('\u0000', '\n'); return s.substring(3, s.length() - 3); } else return s.substring(1, s.length() - 1); } Location makeLocation(Token t) { return sb.makeLocation(sourceUri, t.beginLine, t.beginColumn); } String getCompatibilityPrefix() { if (compatibilityPrefix == null) { compatibilityPrefix = "a"; while (namespaceMap.get(compatibilityPrefix) != null) compatibilityPrefix = compatibilityPrefix + "a"; } return compatibilityPrefix; } public String resolveNamespacePrefix(String prefix) { String result = namespaceMap.get(prefix); if (result == null || result.length() == 0) return null; return result; } public Set prefixes() { return namespaceMap.keySet(); } public String getBaseUri() { return sourceUri; } public boolean isUnparsedEntity(String entityName) { return false; } public boolean isNotation(String notationName) { return false; } public Context copy() { return this; } private Context getContext() { return this; } private CommentListImpl getComments() { return getComments(getTopLevelComments()); } private CommentListImpl topLevelComments; private CommentListImpl getTopLevelComments() { CommentListImpl tem = topLevelComments; topLevelComments = null; return tem; } private void noteTopLevelComments() { topLevelComments = getComments(topLevelComments); } private void topLevelComments(GrammarSection section) { section.topLevelComment(getComments(null)); } private Token lastCommentSourceToken = null; private CommentListImpl getComments(CommentListImpl comments) { Token nextToken = getToken(1); if (lastCommentSourceToken != nextToken) { if (lastCommentSourceToken == null) lastCommentSourceToken = token; do { lastCommentSourceToken = lastCommentSourceToken.next; Token t = lastCommentSourceToken.specialToken; if (t != null) { while (t.specialToken != null) t = t.specialToken; if (comments == null) comments = sb.makeCommentList(); for (; t != null; t = t.next) { String s = mungeComment(t.image); Location loc = makeLocation(t); if (t.next != null && t.next.kind == CompactSyntaxConstants.SINGLE_LINE_COMMENT_CONTINUE) { StringBuffer buf = new StringBuffer(s); do { t = t.next; buf.append('\n'); buf.append(mungeComment(t.image)); } while (t.next != null && t.next.kind == CompactSyntaxConstants.SINGLE_LINE_COMMENT_CONTINUE); s = buf.toString(); } comments.addComment(s, loc); } } } while (lastCommentSourceToken != nextToken); } return comments; } private Pattern afterPatternComments(Pattern p) { CommentListImpl comments = getComments(null); if (comments == null) return p; return sb.commentAfterPattern(p, comments); } private NameClass afterNameClassComments(NameClass nc) { CommentListImpl comments = getComments(null); if (comments == null) return nc; return sb.commentAfterNameClass(nc, comments); } private static String mungeComment(String image) { int i = image.indexOf('#') + 1; while (i < image.length() && image.charAt(i) == '#') i++; if (i < image.length() && image.charAt(i) == ' ') i++; return image.substring(i); } private AnnotationsImpl getCommentsAsAnnotations() { CommentListImpl comments = getComments(); if (comments == null) return null; return sb.makeAnnotations(comments, getContext()); } private AnnotationsImpl addCommentsToChildAnnotations(AnnotationsImpl a) { CommentListImpl comments = getComments(); if (comments == null) return a; if (a == null) a = sb.makeAnnotations(null, getContext()); a.addComment(comments); return a; } private AnnotationsImpl addCommentsToLeadingAnnotations(AnnotationsImpl a) { CommentListImpl comments = getComments(); if (comments == null) return a; if (a == null) return sb.makeAnnotations(comments, getContext()); a.addLeadingComment(comments); return a; } private AnnotationsImpl getTopLevelCommentsAsAnnotations() { CommentListImpl comments = getTopLevelComments(); if (comments == null) return null; return sb.makeAnnotations(comments, getContext()); } private void clearAttributeList() { attributeNames.clear(); } private void addAttribute(Annotations a, String ns, String localName, String prefix, String value, Token tok) { String key = ns + "#" + localName; if (attributeNames.contains(key)) error("duplicate_attribute", ns, localName, tok); else { attributeNames.add(key); a.addAttribute(ns, localName, prefix, value, makeLocation(tok)); } } private void checkExcept(Token[] except) { if (except[0] != null) error("except_missing_parentheses", except[0]); } private String lookupPrefix(String prefix, Token t) { String ns = namespaceMap.get(prefix); if (ns == null) { error("undeclared_prefix", prefix, t); return "#error"; } return ns; } private String lookupDatatype(String prefix, Token t) { String ns = datatypesMap.get(prefix); if (ns == null) { error("undeclared_prefix", prefix, t); return ""; // XXX } return ns; } } PARSER_END(CompactSyntax) Pattern Input(Scope scope) : { Pattern p; } { Preamble() (LOOKAHEAD(TopLevelLookahead()) p = TopLevelGrammar(scope) | p = Expr(true, scope, null, null) { p = afterPatternComments(p); } ) { return p; } } void TopLevelLookahead() : {} { "[" | Identifier() ("[" | "=" | "&=" | "|=") | LookaheadGrammarKeyword() | LookaheadBody() LookaheadAfterAnnotations() | LookaheadDocumentation() (LookaheadBody())? LookaheadAfterAnnotations() } void LookaheadAfterAnnotations() : {} { Identifier() ("=" | "&=" | "|=") | LookaheadGrammarKeyword() } void LookaheadGrammarKeyword() : {} { "start" | "div" | "include" } void LookaheadDocumentation() : {} { (( | ) ()*)+ } void LookaheadBody() : {} { "[" ( | UnprefixedName() | "=" | | "~" | LookaheadBody() )* "]" } Pattern IncludedGrammar(IncludedGrammar g) : { AnnotationsImpl a; Pattern p; } { Preamble() (LOOKAHEAD(TopLevelLookahead()) a = GrammarBody(g, g, getTopLevelCommentsAsAnnotations()) | a = AnnotationsImpl() "grammar" "{" a = GrammarBody(g, g, a) { topLevelComments(g); } "}") { p = afterPatternComments(g.endIncludedGrammar(sb.makeLocation(sourceUri, 1, 1), a)); } { return p; } } Pattern TopLevelGrammar(Scope scope) : { AnnotationsImpl a = getTopLevelCommentsAsAnnotations(); Grammar g; Pattern p; } { { g = sb.makeGrammar(scope); } a = GrammarBody(g, g, a) { p = afterPatternComments(g.endGrammar(sb.makeLocation(sourceUri, 1, 1), a)); } { return p; } } void Preamble() : {} { (NamespaceDecl() | DatatypesDecl())* { namespaceMap.put("xml", WellKnownNamespaces.XML); if (datatypesMap.get("xsd") == null) datatypesMap.put("xsd", WellKnownNamespaces.XML_SCHEMA_DATATYPES); } } void NamespaceDecl() : { LocatedString prefix = null; boolean isDefault = false; String namespaceName; } { { noteTopLevelComments(); } (("namespace" prefix = UnprefixedName()) | ("default" { isDefault = true; } "namespace" (prefix = UnprefixedName())?)) "=" namespaceName = NamespaceName() { if (isDefault) defaultNamespace = namespaceName; if (prefix != null) { if (prefix.getString().equals("xmlns")) error("xmlns_prefix", prefix.getToken()); else if (prefix.getString().equals("xml")) { if (!namespaceName.equals(WellKnownNamespaces.XML)) error("xml_prefix_bad_uri", prefix.getToken()); } else if (namespaceName.equals(WellKnownNamespaces.XML)) error("xml_uri_bad_prefix", prefix.getToken()); else { if (namespaceName.equals(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS)) compatibilityPrefix = prefix.getString(); namespaceMap.put(prefix.getString(), namespaceName); } } } } String NamespaceName() : { String r; } { (r = Literal() | "inherit" { r = SchemaBuilder.INHERIT_NS; }) { return r; } } void DatatypesDecl() : { LocatedString prefix; String uri; } { { noteTopLevelComments(); } "datatypes" prefix = UnprefixedName() "=" uri = Literal() { datatypesMap.put(prefix.getString(), uri); } } Pattern AnnotatedPrimaryExpr(boolean topLevel, Scope scope, Token[] except) : { AnnotationsImpl a; Pattern p; ElementAnnotation e; Token t; } { a = AnnotationsImpl() p = PrimaryExpr(topLevel, scope, a, except) ( t = e = AnnotationElement(false) { if (topLevel) error("top_level_follow_annotation", t); else p = sb.annotateAfterPattern(p, e); })* { return p; } } Pattern PrimaryExpr(boolean topLevel, Scope scope, AnnotationsImpl a, Token[] except) : { Pattern p; } { (p = ElementExpr(scope, a) | p = AttributeExpr(scope, a) | p = GrammarExpr(scope, a) | p = ExternalRefExpr(scope, a) | p = ListExpr(scope, a) | p = MixedExpr(scope, a) | p = ParenExpr(topLevel, scope, a) | p = IdentifierExpr(scope, a) | p = ParentExpr(scope, a) | p = DataExpr(topLevel, scope, a, except) | p = ValueExpr(topLevel, a) | p = TextExpr(a) | p = EmptyExpr(a) | p = NotAllowedExpr(a)) { return p; } } Pattern EmptyExpr(AnnotationsImpl a) : { Token t; } { t = "empty" { return sb.makeEmpty(makeLocation(t), a); } } Pattern TextExpr(AnnotationsImpl a) : { Token t; } { t = "text" { return sb.makeText(makeLocation(t), a); } } Pattern NotAllowedExpr(AnnotationsImpl a) : { Token t; } { t = "notAllowed" { return sb.makeNotAllowed(makeLocation(t), a); } } Pattern Expr(boolean topLevel, Scope scope, Token t, AnnotationsImpl a) : { Pattern p; List patterns = new ArrayList(); boolean[] hadOccur = new boolean[1]; Token[] except = new Token[1]; } { p = UnaryExpr(topLevel, scope, hadOccur, except) { patterns.add(p); } ( { checkExcept(except); } (t = "|" p = UnaryExpr(topLevel, scope, null, except) { patterns.add(p); checkExcept(except); } )+ { p = sb.makeChoice(patterns, makeLocation(t), a); } | (t = "&" p = UnaryExpr(topLevel, scope, null, except) { patterns.add(p); checkExcept(except); } )+ { p = sb.makeInterleave(patterns, makeLocation(t), a); } | (t = "," p = UnaryExpr(topLevel, scope, null, except) { patterns.add(p); checkExcept(except); } )+ { p = sb.makeGroup(patterns, makeLocation(t), a); } )? { if (patterns.size() == 1 && a != null) { if (hadOccur[0]) p = sb.annotatePattern(p, a); else p = sb.makeGroup(patterns, makeLocation(t), a); } return p; } } Pattern UnaryExpr(boolean topLevel, Scope scope, boolean[] hadOccur, Token[] except) : { Pattern p; Token t; ElementAnnotation e; } { p = AnnotatedPrimaryExpr(topLevel, scope, except) ( { if (hadOccur != null) hadOccur[0] = true; p = afterPatternComments(p); } (t = "+" { checkExcept(except); p = sb.makeOneOrMore(p, makeLocation(t), null); } | t = "?" { checkExcept(except); p = sb.makeOptional(p, makeLocation(t), null); } | t = "*" { checkExcept(except); p = sb.makeZeroOrMore(p, makeLocation(t), null); }) ( t = e = AnnotationElement(false) { if (topLevel) error("top_level_follow_annotation", t); else p = sb.annotateAfterPattern(p, e); } )* )? { return p; } } Pattern ElementExpr(Scope scope, AnnotationsImpl a) : { Token t; NameClass nc; Pattern p; } { t = "element" nc = NameClass(IN_ELEMENT, null) "{" p = Expr(false, scope, null, null) { p = afterPatternComments(p); } "}" { return sb.makeElement(nc, p, makeLocation(t), a); } } Pattern AttributeExpr(Scope scope, AnnotationsImpl a) : { Token t; NameClass nc; Pattern p; } { t = "attribute" nc = NameClass(IN_ATTRIBUTE, null) "{" p = Expr(false, scope, null, null) { p = afterPatternComments(p); } "}" { return sb.makeAttribute(nc, p, makeLocation(t), a); } } NameClass NameClass(int context, Ref ra) : { AnnotationsImpl a; NameClass nc; } { a = AnnotationsImpl() (nc = PrimaryNameClass(context, a) nc = AnnotateAfter(nc) nc = NameClassAlternatives(context, nc, ra) | nc = AnyNameExceptClass(context, a, ra) | nc = NsNameExceptClass(context, a, ra)) { return nc; } } NameClass AnnotateAfter(NameClass nc) : { ElementAnnotation e; } { ( e = AnnotationElement(false) { nc = sb.annotateAfterNameClass(nc, e); })* { return nc; } } NameClass NameClassAlternatives(int context, NameClass nc, Ref ra) : { Token t; List nameClasses; } { ( { nameClasses = new ArrayList(); nameClasses.add(nc); } (t = "|" nc = BasicNameClass(context) nc = AnnotateAfter(nc) { nameClasses.add(nc); })+ { AnnotationsImpl a; if (ra == null) a = null; else { a = ra.get(); ra.clear(); } nc = sb.makeNameClassChoice(nameClasses, makeLocation(t), a); } )? { return nc; } } NameClass BasicNameClass(int context) : { AnnotationsImpl a; NameClass nc; } { a = AnnotationsImpl() (nc = PrimaryNameClass(context, a) | nc = OpenNameClass(context, a)) { return nc; } } NameClass PrimaryNameClass(int context, AnnotationsImpl a) : { NameClass nc; } { (nc = UnprefixedNameClass(context, a) | nc = PrefixedNameClass(a) | nc = ParenNameClass(context, a)) { return nc; } } NameClass OpenNameClass(int context, AnnotationsImpl a) : { Token t; LocatedString ns; } { ns = NsName() { checkNsName(context, ns); return sb.makeNsName(ns.getString(), ns.getLocation(), a); } | t = "*" { checkAnyName(context, t); return sb.makeAnyName(makeLocation(t), a); } } NameClass UnprefixedNameClass(int context, AnnotationsImpl a) : { LocatedString name; } { name = UnprefixedName() { String ns; if ((context & (IN_ATTRIBUTE|IN_ELEMENT)) == IN_ATTRIBUTE) ns = ""; else ns = defaultNamespace; return sb.makeName(ns, name.getString(), null, name.getLocation(), a); } } NameClass PrefixedNameClass(AnnotationsImpl a) : { Token t; } { t = { String qn = t.image; int colon = qn.indexOf(':'); String prefix = qn.substring(0, colon); return sb.makeName(lookupPrefix(prefix, t), qn.substring(colon + 1), prefix, makeLocation(t), a); } } NameClass NsNameExceptClass(int context, AnnotationsImpl a, Ref ra) : { LocatedString ns; NameClass nc; } { ns = NsName() { checkNsName(context, ns); } (nc = ExceptNameClass(context | IN_NS_NAME) { nc = sb.makeNsName(ns.getString(), nc, ns.getLocation(), a); } nc = AnnotateAfter(nc) | { nc = sb.makeNsName(ns.getString(), ns.getLocation(), a); } nc = AnnotateAfter(nc) nc = NameClassAlternatives(context, nc, ra)) { return nc; } } LocatedString NsName() : { Token t; } { t = { String qn = t.image; String prefix = qn.substring(0, qn.length() - 2); return new LocatedString(lookupPrefix(prefix, t), t); } } NameClass AnyNameExceptClass(int context, AnnotationsImpl a, Ref ra) : { Token t; NameClass nc; } { t = "*" { checkAnyName(context, t); } (nc = ExceptNameClass(context | IN_ANY_NAME) { nc = sb.makeAnyName(nc, makeLocation(t), a); } nc = AnnotateAfter(nc) | { nc = sb.makeAnyName(makeLocation(t), a); } nc = AnnotateAfter(nc) nc = NameClassAlternatives(context, nc, ra)) { return nc; } } NameClass ParenNameClass(int context, AnnotationsImpl a) : { Token t; NameClass nc; Ref ra = new Ref(a); } { t = "(" nc = NameClass(context, ra) { nc = afterNameClassComments(nc); } ")" { if (ra.get() != null) nc = sb.makeNameClassChoice(Collections.singletonList(nc), makeLocation(t), ra.get()); return nc; } } NameClass ExceptNameClass(int context) : { NameClass nc; } { "-" nc = BasicNameClass(context) { return nc; } } Pattern ListExpr(Scope scope, AnnotationsImpl a) : { Token t; Pattern p; } { t = "list" "{" p = Expr(false, scope, null, null) { p = afterPatternComments(p); } "}" { return sb.makeList(p, makeLocation(t), a); } } Pattern MixedExpr(Scope scope, AnnotationsImpl a) : { Token t; Pattern p; } { t = "mixed" "{" p = Expr(false, scope, null, null) { p = afterPatternComments(p); } "}" { return sb.makeMixed(p, makeLocation(t), a); } } Pattern GrammarExpr(Scope scope, AnnotationsImpl a) : { Token t; Grammar g; } { t = "grammar" { g = sb.makeGrammar(scope); } "{" a = GrammarBody(g, g, a) { topLevelComments(g); } "}" { return g.endGrammar(makeLocation(t), a); } } Pattern ParenExpr(boolean topLevel, Scope scope, AnnotationsImpl a) : { Token t; Pattern p; } { t = "(" p = Expr(topLevel, scope, t, a) { p = afterPatternComments(p); } ")" { return p; } } AnnotationsImpl GrammarBody(GrammarSection section, Scope scope, AnnotationsImpl a) : { ElementAnnotation e; } { (LOOKAHEAD(2) e = AnnotationElementNotKeyword() { if (a == null) a = sb.makeAnnotations(null, getContext()); a.addElement(e); })* (GrammarComponent(section, scope))* { return a; } } void GrammarComponent(GrammarSection section, Scope scope) : { ElementAnnotation e; AnnotationsImpl a; } { (a = AnnotationsImpl() (Definition(section, scope, a) | Include(section, scope, a) | Div(section, scope, a))) (LOOKAHEAD(2) e = AnnotationElementNotKeyword() { section.topLevelAnnotation(e); })* } void Definition(GrammarSection section, Scope scope, AnnotationsImpl a) : {} { (Define(section, scope, a) | Start(section, scope, a)) } void Start(GrammarSection section, Scope scope, AnnotationsImpl a) : { Token t; GrammarSection.Combine combine; Pattern p; } { t = "start" combine = AssignOp() p = Expr(false, scope, null, null) { section.define(GrammarSection.START, combine, p, makeLocation(t), a); } } void Define(GrammarSection section, Scope scope, AnnotationsImpl a) : { LocatedString name; GrammarSection.Combine combine; Pattern p; } { name = Identifier() combine = AssignOp() p = Expr(false, scope, null, null) { section.define(name.getString(), combine, p, name.getLocation(), a); } } GrammarSection.Combine AssignOp() : {} { "=" { return null; } | "|=" { return GrammarSection.COMBINE_CHOICE; } | "&=" { return GrammarSection.COMBINE_INTERLEAVE; } } void Include(GrammarSection section, Scope scope, AnnotationsImpl a) : { Token t; String href; String ns; Include include = section.makeInclude(); } { t = "include" href = Literal() ns = Inherit() ("{" a = IncludeBody(include, scope, a) { topLevelComments(include); } "}")? { try { include.endInclude(href, sourceUri, ns, makeLocation(t), a); } catch (IllegalSchemaException e) { } } } AnnotationsImpl IncludeBody(GrammarSection section, Scope scope, AnnotationsImpl a) : { ElementAnnotation e; } { (LOOKAHEAD(2) e = AnnotationElementNotKeyword() { if (a == null) a = sb.makeAnnotations(null, getContext()); a.addElement(e); })* (IncludeComponent(section, scope))* { return a; } } void IncludeComponent(GrammarSection section, Scope scope) : { ElementAnnotation e; AnnotationsImpl a; } { (a = AnnotationsImpl() (Definition(section, scope, a) | IncludeDiv(section, scope, a))) (LOOKAHEAD(2) e = AnnotationElementNotKeyword() { section.topLevelAnnotation(e); })* } void Div(GrammarSection section, Scope scope, AnnotationsImpl a) : { Token t; Div div = section.makeDiv(); } { t = "div" "{" a = GrammarBody(div, scope, a) { topLevelComments(div); } "}" { div.endDiv(makeLocation(t), a); } } void IncludeDiv(GrammarSection section, Scope scope, AnnotationsImpl a) : { Token t; Div div = section.makeDiv(); } { t = "div" "{" a = IncludeBody(div, scope, a) { topLevelComments(div); } "}" { div.endDiv(makeLocation(t), a); } } Pattern ExternalRefExpr(Scope scope, AnnotationsImpl a) : { Token t; String href; String ns; } { t = "external" href = Literal() ns = Inherit() { try { return sb.makeExternalRef(href, sourceUri, ns, scope, makeLocation(t), a); } catch (IllegalSchemaException e) { return sb.makeErrorPattern(); } } } String Inherit() : { String ns = null; } { ("inherit" "=" ns = Prefix())? { if (ns == null) ns = defaultNamespace; return ns; } } Pattern ParentExpr(Scope scope, AnnotationsImpl a) : { LocatedString name; } { "parent" { a = addCommentsToChildAnnotations(a); } name = Identifier() { return scope.makeParentRef(name.getString(), name.getLocation(), a); } } Pattern IdentifierExpr(Scope scope, AnnotationsImpl a) : { LocatedString name; } { name = Identifier() { return scope.makeRef(name.getString(), name.getLocation(), a); } } Pattern ValueExpr(boolean topLevel, AnnotationsImpl a) : { LocatedString s; } { s = LocatedLiteral() { if (topLevel && annotationsIncludeElements) { error("top_level_follow_annotation", s.getToken()); a = null; } return sb.makeValue("", "token", s.getString(), getContext(), defaultNamespace, s.getLocation(), a); } } Pattern DataExpr(boolean topLevel, Scope scope, AnnotationsImpl a, Token[] except) : { Token datatypeToken; Location loc; String datatype; String datatypeUri = null; String s = null; Pattern e = null; DataPatternBuilder dpb; } { datatypeToken = DatatypeName() { datatype = datatypeToken.image; loc = makeLocation(datatypeToken); int colon = datatype.indexOf(':'); if (colon < 0) datatypeUri = ""; else { String prefix = datatype.substring(0, colon); datatypeUri = lookupDatatype(prefix, datatypeToken); datatype = datatype.substring(colon + 1); } } ((s = Literal() { if (topLevel && annotationsIncludeElements) { error("top_level_follow_annotation", datatypeToken); a = null; } return sb.makeValue(datatypeUri, datatype, s, getContext(), defaultNamespace, loc, a); } ) | ( { dpb = sb.makeDataPatternBuilder(datatypeUri, datatype, loc); } ( (Params(dpb) (e = Except(scope, except))?) | (e = Except(scope, except))?) { return e == null ? dpb.makePattern(loc, a) : dpb.makePattern(e, loc, a); })) } Token DatatypeName() : { Token t; } { (t = "string" | t = "token" | t = ) { return t; } } LocatedString Identifier() : { LocatedString s; Token t; } { (t = { s = new LocatedString(t.image, t); } | t = { s = new LocatedString(t.image.substring(1), t); }) { return s; } } String Prefix() : { Token t; String prefix; } { (t = { prefix = t.image; } | t = { prefix = t.image.substring(1); } | t = Keyword() { prefix = t.image; }) { return lookupPrefix(prefix, t); } } LocatedString UnprefixedName() : { LocatedString s; Token t; } { (s = Identifier() | t = Keyword() { s = new LocatedString(t.image, t); }) { return s; } } void Params(DataPatternBuilder dpb) : {} { "{" (Param(dpb))* "}" } void Param(DataPatternBuilder dpb) : { LocatedString name; AnnotationsImpl a; String value; } { a = AnnotationsImpl() name = UnprefixedName() "=" { a = addCommentsToLeadingAnnotations(a); } value = Literal() { dpb.addParam(name.getString(), value, getContext(), defaultNamespace, name.getLocation(), a); } } Pattern Except(Scope scope, Token[] except) : { AnnotationsImpl a; Pattern p; Token t; Token[] innerExcept = new Token[1]; } { t = "-" a = AnnotationsImpl() p = PrimaryExpr(false, scope, a, innerExcept) { checkExcept(innerExcept); except[0] = t; return p; } } ElementAnnotation Documentation() : { CommentListImpl comments = getComments(); ElementAnnotationBuilder eab; Token t; } { (t = | t = ) { eab = sb.makeElementAnnotationBuilder(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS, "documentation", getCompatibilityPrefix(), makeLocation(t), comments, getContext()); eab.addText(mungeComment(t.image), makeLocation(t), null); } (t = { eab.addText("\n" + mungeComment(t.image), makeLocation(t), null); })* { return eab.makeElementAnnotation(); } } AnnotationsImpl AnnotationsImpl() : { CommentListImpl comments = getComments(); AnnotationsImpl a = null; ElementAnnotation e; } { ( { a = sb.makeAnnotations(comments, getContext()); } (e = Documentation() { a.addElement(e); })+ { comments = getComments(); if (comments != null) a.addLeadingComment(comments); } )? ("[" { if (a == null) a = sb.makeAnnotations(comments, getContext()); clearAttributeList(); annotationsIncludeElements = false; } (LOOKAHEAD(2) PrefixedAnnotationAttribute(a, false) )* ( e = AnnotationElement(false) { a.addElement(e); annotationsIncludeElements = true; } )* { a.addComment(getComments()); } "]")? { if (a == null && comments != null) a = sb.makeAnnotations(comments, getContext()); return a; } } void AnnotationAttribute(Annotations a) : {} { PrefixedAnnotationAttribute(a, true) | UnprefixedAnnotationAttribute(a) } void PrefixedAnnotationAttribute(Annotations a, boolean nested) : { Token t; String value; } { t = "=" value = Literal() { String qn = t.image; int colon = qn.indexOf(':'); String prefix = qn.substring(0, colon); String ns = lookupPrefix(prefix, t); if (ns == SchemaBuilder.INHERIT_NS) error("inherited_annotation_namespace", t); else if (ns.length() == 0 && !nested) error("unqualified_annotation_attribute", t); else if (ns.equals(WellKnownNamespaces.RELAX_NG) && !nested) error("relax_ng_namespace", t); /*else if (ns.length() == 0 && qn.length() - colon - 1 == 5 && qn.regionMatches(colon + 1, "xmlns", 0, 5)) error("xmlns_annotation_attribute", t);*/ else if (ns.equals(WellKnownNamespaces.XMLNS)) error("xmlns_annotation_attribute_uri", t); else { if (ns.length() == 0) prefix = null; addAttribute(a, ns, qn.substring(colon + 1), prefix, value, t); } } } void UnprefixedAnnotationAttribute(Annotations a) : { LocatedString name; String value; } { name = UnprefixedName() "=" value = Literal() { if (name.getString().equals("xmlns")) error("xmlns_annotation_attribute", name.getToken()); else addAttribute(a, "", name.getString(), null, value, name.getToken()); } } ElementAnnotation AnnotationElement(boolean nested) : { ElementAnnotation a; } { (a = PrefixedAnnotationElement(nested) | a = UnprefixedAnnotationElement()) { return a; } } ElementAnnotation AnnotationElementNotKeyword() : { ElementAnnotation a; } { (a = PrefixedAnnotationElement(false) | a = IdentifierAnnotationElement()) { return a; } } ElementAnnotation PrefixedAnnotationElement(boolean nested) : { CommentListImpl comments = getComments(); Token t; ElementAnnotationBuilder eab; } { t = { String qn = t.image; int colon = qn.indexOf(':'); String prefix = qn.substring(0, colon); String ns = lookupPrefix(prefix, t); if (ns == SchemaBuilder.INHERIT_NS) { error("inherited_annotation_namespace", t); ns = ""; } else if (!nested && ns.equals(WellKnownNamespaces.RELAX_NG)) { error("relax_ng_namespace", t); ns = ""; } else { if (ns.length() == 0) prefix = null; } eab = sb.makeElementAnnotationBuilder(ns, qn.substring(colon + 1), prefix, makeLocation(t), comments, getContext()); } AnnotationElementContent(eab) { return eab.makeElementAnnotation(); } } ElementAnnotation UnprefixedAnnotationElement() : { CommentListImpl comments = getComments(); LocatedString name; ElementAnnotationBuilder eab; } { name = UnprefixedName() { eab = sb.makeElementAnnotationBuilder("", name.getString(), null, name.getLocation(), comments, getContext()); } AnnotationElementContent(eab) { return eab.makeElementAnnotation(); } } ElementAnnotation IdentifierAnnotationElement() : { CommentListImpl comments = getComments(); LocatedString name; ElementAnnotationBuilder eab; } { name = Identifier() { eab = sb.makeElementAnnotationBuilder("", name.getString(), null, name.getLocation(), comments, getContext()); } AnnotationElementContent(eab) { return eab.makeElementAnnotation(); } } void AnnotationElementContent(ElementAnnotationBuilder eab) : { ElementAnnotation e; } { "[" { clearAttributeList(); } (LOOKAHEAD(2) AnnotationAttribute(eab))* ((AnnotationElementLiteral(eab) ("~" AnnotationElementLiteral(eab))*) | e = AnnotationElement(true) { eab.addElement(e); })* { eab.addComment(getComments()); } "]" } void AnnotationElementLiteral(ElementAnnotationBuilder eab) : { Token t; CommentListImpl comments = getComments(); } { t = { eab.addText(unquote(t.image), makeLocation(t), comments); } } String Literal() : { Token t; String s; StringBuffer buf; } { t = { s = unquote(t.image); } ( { buf = new StringBuffer(s); } ("~" t = { buf.append(unquote(t.image)); })+ { s = buf.toString(); } )? { return s; } } LocatedString LocatedLiteral() : { Token t; Token t2; String s; StringBuffer buf; } { t = { s = unquote(t.image); } ( { buf = new StringBuffer(s); } ("~" t2 = { buf.append(unquote(t2.image)); })+ { s = buf.toString(); } )? { return new LocatedString(s, t); } } Token Keyword() : { Token t; } { (t = "element" | t = "attribute" | t = "namespace" | t = "list" | t = "mixed" | t = "grammar" | t = "empty" | t = "text" | t = "parent" | t = "external" | t = "notAllowed" | t = "start" | t = "include" | t = "default" | t = "inherit" | t = "string" | t = "token" | t = "datatypes" | t = "div") { return t; } } <*> SKIP: { < #NEWLINE : [ "\u0000", "\n" ] > | < #NOT_NEWLINE : ~[ "\u0000", "\n" ] > | < WS: ([ "\u0000", " ", "\n", "\t" ])+ > : DEFAULT } TOKEN : { < DOCUMENTATION: "##" ()* > : AFTER_DOCUMENTATION } TOKEN : { < DOCUMENTATION_CONTINUE: ([" ", "\t"])* > } SPECIAL_TOKEN: { < SINGLE_LINE_COMMENT: "#" ()* > : AFTER_SINGLE_LINE_COMMENT } TOKEN : { < DOCUMENTATION_AFTER_SINGLE_LINE_COMMENT: ([" ", "\t"])* > : AFTER_DOCUMENTATION } SPECIAL_TOKEN : { < SINGLE_LINE_COMMENT_CONTINUE: ([" ", "\t"])* > } TOKEN : { < #BASE_CHAR : [ "\u0041" - "\u005a", "\u0061" - "\u007a", "\u00c0" - "\u00d6", "\u00d8" - "\u00f6", "\u00f8" - "\u00ff", "\u0100" - "\u0131", "\u0134" - "\u013e", "\u0141" - "\u0148", "\u014a" - "\u017e", "\u0180" - "\u01c3", "\u01cd" - "\u01f0", "\u01f4" - "\u01f5", "\u01fa" - "\u0217", "\u0250" - "\u02a8", "\u02bb" - "\u02c1", "\u0386", "\u0388" - "\u038a", "\u038c", "\u038e" - "\u03a1", "\u03a3" - "\u03ce", "\u03d0" - "\u03d6", "\u03da", "\u03dc", "\u03de", "\u03e0", "\u03e2" - "\u03f3", "\u0401" - "\u040c", "\u040e" - "\u044f", "\u0451" - "\u045c", "\u045e" - "\u0481", "\u0490" - "\u04c4", "\u04c7" - "\u04c8", "\u04cb" - "\u04cc", "\u04d0" - "\u04eb", "\u04ee" - "\u04f5", "\u04f8" - "\u04f9", "\u0531" - "\u0556", "\u0559", "\u0561" - "\u0586", "\u05d0" - "\u05ea", "\u05f0" - "\u05f2", "\u0621" - "\u063a", "\u0641" - "\u064a", "\u0671" - "\u06b7", "\u06ba" - "\u06be", "\u06c0" - "\u06ce", "\u06d0" - "\u06d3", "\u06d5", "\u06e5" - "\u06e6", "\u0905" - "\u0939", "\u093d", "\u0958" - "\u0961", "\u0985" - "\u098c", "\u098f" - "\u0990", "\u0993" - "\u09a8", "\u09aa" - "\u09b0", "\u09b2", "\u09b6" - "\u09b9", "\u09dc" - "\u09dd", "\u09df" - "\u09e1", "\u09f0" - "\u09f1", "\u0a05" - "\u0a0a", "\u0a0f" - "\u0a10", "\u0a13" - "\u0a28", "\u0a2a" - "\u0a30", "\u0a32" - "\u0a33", "\u0a35" - "\u0a36", "\u0a38" - "\u0a39", "\u0a59" - "\u0a5c", "\u0a5e", "\u0a72" - "\u0a74", "\u0a85" - "\u0a8b", "\u0a8d", "\u0a8f" - "\u0a91", "\u0a93" - "\u0aa8", "\u0aaa" - "\u0ab0", "\u0ab2" - "\u0ab3", "\u0ab5" - "\u0ab9", "\u0abd", "\u0ae0", "\u0b05" - "\u0b0c", "\u0b0f" - "\u0b10", "\u0b13" - "\u0b28", "\u0b2a" - "\u0b30", "\u0b32" - "\u0b33", "\u0b36" - "\u0b39", "\u0b3d", "\u0b5c" - "\u0b5d", "\u0b5f" - "\u0b61", "\u0b85" - "\u0b8a", "\u0b8e" - "\u0b90", "\u0b92" - "\u0b95", "\u0b99" - "\u0b9a", "\u0b9c", "\u0b9e" - "\u0b9f", "\u0ba3" - "\u0ba4", "\u0ba8" - "\u0baa", "\u0bae" - "\u0bb5", "\u0bb7" - "\u0bb9", "\u0c05" - "\u0c0c", "\u0c0e" - "\u0c10", "\u0c12" - "\u0c28", "\u0c2a" - "\u0c33", "\u0c35" - "\u0c39", "\u0c60" - "\u0c61", "\u0c85" - "\u0c8c", "\u0c8e" - "\u0c90", "\u0c92" - "\u0ca8", "\u0caa" - "\u0cb3", "\u0cb5" - "\u0cb9", "\u0cde", "\u0ce0" - "\u0ce1", "\u0d05" - "\u0d0c", "\u0d0e" - "\u0d10", "\u0d12" - "\u0d28", "\u0d2a" - "\u0d39", "\u0d60" - "\u0d61", "\u0e01" - "\u0e2e", "\u0e30", "\u0e32" - "\u0e33", "\u0e40" - "\u0e45", "\u0e81" - "\u0e82", "\u0e84", "\u0e87" - "\u0e88", "\u0e8a", "\u0e8d", "\u0e94" - "\u0e97", "\u0e99" - "\u0e9f", "\u0ea1" - "\u0ea3", "\u0ea5", "\u0ea7", "\u0eaa" - "\u0eab", "\u0ead" - "\u0eae", "\u0eb0", "\u0eb2" - "\u0eb3", "\u0ebd", "\u0ec0" - "\u0ec4", "\u0f40" - "\u0f47", "\u0f49" - "\u0f69", "\u10a0" - "\u10c5", "\u10d0" - "\u10f6", "\u1100", "\u1102" - "\u1103", "\u1105" - "\u1107", "\u1109", "\u110b" - "\u110c", "\u110e" - "\u1112", "\u113c", "\u113e", "\u1140", "\u114c", "\u114e", "\u1150", "\u1154" - "\u1155", "\u1159", "\u115f" - "\u1161", "\u1163", "\u1165", "\u1167", "\u1169", "\u116d" - "\u116e", "\u1172" - "\u1173", "\u1175", "\u119e", "\u11a8", "\u11ab", "\u11ae" - "\u11af", "\u11b7" - "\u11b8", "\u11ba", "\u11bc" - "\u11c2", "\u11eb", "\u11f0", "\u11f9", "\u1e00" - "\u1e9b", "\u1ea0" - "\u1ef9", "\u1f00" - "\u1f15", "\u1f18" - "\u1f1d", "\u1f20" - "\u1f45", "\u1f48" - "\u1f4d", "\u1f50" - "\u1f57", "\u1f59", "\u1f5b", "\u1f5d", "\u1f5f" - "\u1f7d", "\u1f80" - "\u1fb4", "\u1fb6" - "\u1fbc", "\u1fbe", "\u1fc2" - "\u1fc4", "\u1fc6" - "\u1fcc", "\u1fd0" - "\u1fd3", "\u1fd6" - "\u1fdb", "\u1fe0" - "\u1fec", "\u1ff2" - "\u1ff4", "\u1ff6" - "\u1ffc", "\u2126", "\u212a" - "\u212b", "\u212e", "\u2180" - "\u2182", "\u3041" - "\u3094", "\u30a1" - "\u30fa", "\u3105" - "\u312c", "\uac00" - "\ud7a3" ] > | < #IDEOGRAPHIC : [ "\u4e00" - "\u9fa5", "\u3007", "\u3021" - "\u3029" ] > | < #LETTER : ( | ) > | < #COMBINING_CHAR : [ "\u0300" - "\u0345", "\u0360" - "\u0361", "\u0483" - "\u0486", "\u0591" - "\u05a1", "\u05a3" - "\u05b9", "\u05bb" - "\u05bd", "\u05bf", "\u05c1" - "\u05c2", "\u05c4", "\u064b" - "\u0652", "\u0670", "\u06d6" - "\u06dc", "\u06dd" - "\u06df", "\u06e0" - "\u06e4", "\u06e7" - "\u06e8", "\u06ea" - "\u06ed", "\u0901" - "\u0903", "\u093c", "\u093e" - "\u094c", "\u094d", "\u0951" - "\u0954", "\u0962" - "\u0963", "\u0981" - "\u0983", "\u09bc", "\u09be", "\u09bf", "\u09c0" - "\u09c4", "\u09c7" - "\u09c8", "\u09cb" - "\u09cd", "\u09d7", "\u09e2" - "\u09e3", "\u0a02", "\u0a3c", "\u0a3e", "\u0a3f", "\u0a40" - "\u0a42", "\u0a47" - "\u0a48", "\u0a4b" - "\u0a4d", "\u0a70" - "\u0a71", "\u0a81" - "\u0a83", "\u0abc", "\u0abe" - "\u0ac5", "\u0ac7" - "\u0ac9", "\u0acb" - "\u0acd", "\u0b01" - "\u0b03", "\u0b3c", "\u0b3e" - "\u0b43", "\u0b47" - "\u0b48", "\u0b4b" - "\u0b4d", "\u0b56" - "\u0b57", "\u0b82" - "\u0b83", "\u0bbe" - "\u0bc2", "\u0bc6" - "\u0bc8", "\u0bca" - "\u0bcd", "\u0bd7", "\u0c01" - "\u0c03", "\u0c3e" - "\u0c44", "\u0c46" - "\u0c48", "\u0c4a" - "\u0c4d", "\u0c55" - "\u0c56", "\u0c82" - "\u0c83", "\u0cbe" - "\u0cc4", "\u0cc6" - "\u0cc8", "\u0cca" - "\u0ccd", "\u0cd5" - "\u0cd6", "\u0d02" - "\u0d03", "\u0d3e" - "\u0d43", "\u0d46" - "\u0d48", "\u0d4a" - "\u0d4d", "\u0d57", "\u0e31", "\u0e34" - "\u0e3a", "\u0e47" - "\u0e4e", "\u0eb1", "\u0eb4" - "\u0eb9", "\u0ebb" - "\u0ebc", "\u0ec8" - "\u0ecd", "\u0f18" - "\u0f19", "\u0f35", "\u0f37", "\u0f39", "\u0f3e", "\u0f3f", "\u0f71" - "\u0f84", "\u0f86" - "\u0f8b", "\u0f90" - "\u0f95", "\u0f97", "\u0f99" - "\u0fad", "\u0fb1" - "\u0fb7", "\u0fb9", "\u20d0" - "\u20dc", "\u20e1", "\u302a" - "\u302f", "\u3099", "\u309a" ] > | < #DIGIT : [ "\u0030" - "\u0039", "\u0660" - "\u0669", "\u06f0" - "\u06f9", "\u0966" - "\u096f", "\u09e6" - "\u09ef", "\u0a66" - "\u0a6f", "\u0ae6" - "\u0aef", "\u0b66" - "\u0b6f", "\u0be7" - "\u0bef", "\u0c66" - "\u0c6f", "\u0ce6" - "\u0cef", "\u0d66" - "\u0d6f", "\u0e50" - "\u0e59", "\u0ed0" - "\u0ed9", "\u0f20" - "\u0f29" ] > | < #EXTENDER : [ "\u00b7", "\u02d0", "\u02d1", "\u0387", "\u0640", "\u0e46", "\u0ec6", "\u3005", "\u3031" - "\u3035", "\u309d" - "\u309e", "\u30fc" - "\u30fe" ] > | < #NMSTART : ( | "_") > | < #NMCHAR : ( | | | | "." | "-" | "_") > | < #NCNAME: ()* > } TOKEN : { < IDENTIFIER: > | < ESCAPED_IDENTIFIER: "\\" > | < PREFIX_STAR: ":*" > | < PREFIXED_NAME: ":" > | < LITERAL : ("\"" (~["\u0000", "\""])* "\"") | ("'" (~["\u0000", "'"])* "'") | ("\"\"\"" (~["\""] | ("\"" ~["\""]) | ("\"\"" ~["\""]))* "\"\"\"") | ("'''" (~["'"] | ("'" ~["'"]) | ("''" ~["'"]))* "'''") > | < FANNOTATE : ">>" > } /* This avoids lexical errors from JavaCC. */ <*> TOKEN : { < ILLEGAL_CHAR : [ "\u0000" - "\u0008", "\u000b" - "\uffff" ] > } EOFException.java000066400000000000000000000001341225366607500343440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compactpackage com.thaiopensource.relaxng.parse.compact; class EOFException extends Exception { } EscapeSyntaxException.java000066400000000000000000000010101225366607500363340ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compactpackage com.thaiopensource.relaxng.parse.compact; class EscapeSyntaxException extends RuntimeException { private final String key; private final int lineNumber; private final int columnNumber; EscapeSyntaxException(String key, int lineNumber, int columnNumber) { this.key = key; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } String getKey() { return key; } int getLineNumber() { return lineNumber; } int getColumnNumber() { return columnNumber; } } JavaCharStream.java000066400000000000000000000364361225366607500347250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compact/* Generated By:JavaCC: Do not edit this line. UCode_UCodeESC_CharStream.java Version 0.7pre6 */ /* The previous line keeps JavaCC quiet. In fact, the JavaCC generated file has been edited to fix some bugs. */ package com.thaiopensource.relaxng.parse.compact; import com.thaiopensource.util.Utf16; import com.thaiopensource.relaxng.parse.BuildException; import java.io.IOException; /** * An implementation of interface CharStream, where the stream is assumed to * contain 16-bit unicode characters. */ public final class JavaCharStream { public static final boolean staticFlag = false; static final int hexval(char c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; } return -1; } public int bufpos = -1; int bufsize; int available; int tokenBegin; private int bufline[]; private int bufcolumn[]; private int column = 0; private int line = 1; private java.io.Reader inputStream; private boolean closed = false; private boolean prevCharIsLF = false; private char[] nextCharBuf; private char[] buffer; private int maxNextCharInd = 0; private int nextCharInd = -1; private int inBuf = 0; private int tabSize = 8; protected void setTabSize(int i) { tabSize = i; } protected int getTabSize(int i) { return tabSize; } private final void ExpandBuff(boolean wrapAround) { char[] newbuffer = new char[bufsize + 2048]; int newbufline[] = new int[bufsize + 2048]; int newbufcolumn[] = new int[bufsize + 2048]; if (wrapAround) { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); bufcolumn = newbufcolumn; bufpos += (bufsize - tokenBegin); } else { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); bufcolumn = newbufcolumn; bufpos -= tokenBegin; } available = (bufsize += 2048); tokenBegin = 0; } private final void FillBuff() throws EOFException { int i; if (maxNextCharInd == 4096) maxNextCharInd = nextCharInd = 0; if (closed) throw new EOFException(); try { if ((i = inputStream.read(nextCharBuf, maxNextCharInd, 4096 - maxNextCharInd)) == -1) { closed = true; inputStream.close(); throw new EOFException(); } else maxNextCharInd += i; } catch (IOException e) { throw new BuildException(e); } } private final char ReadChar() throws EOFException { if (++nextCharInd >= maxNextCharInd) FillBuff(); return nextCharBuf[nextCharInd]; } private final char PeekChar() throws EOFException { char c = ReadChar(); --nextCharInd; return c; } public final char BeginToken() throws EOFException { if (inBuf > 0) { --inBuf; if (++bufpos == bufsize) bufpos = 0; tokenBegin = bufpos; return buffer[bufpos]; } tokenBegin = 0; bufpos = -1; return readChar(); } private final void AdjustBuffSize() { if (available == bufsize) { if (tokenBegin > 2048) { bufpos = 0; available = tokenBegin; } else ExpandBuff(false); } else if (available > tokenBegin) available = bufsize; else if ((tokenBegin - available) < 2048) ExpandBuff(true); else available = tokenBegin; } private final void UpdateLineColumn(char c) { column++; if (prevCharIsLF) { prevCharIsLF = false; line += (column = 1); } switch (c) { case NEWLINE_MARKER: prevCharIsLF = true; break; case '\t': column--; column += (tabSize - (column % tabSize)); break; default : break; } bufline[bufpos] = line; bufcolumn[bufpos] = column; } private final char NEWLINE_MARKER = '\u0000'; public final char readChar() throws EOFException { if (inBuf > 0) { --inBuf; if (++bufpos == bufsize) bufpos = 0; return buffer[bufpos]; } char c; try { c = ReadChar(); switch (c) { case '\r': c = NEWLINE_MARKER; try { if (PeekChar() == '\n') ReadChar(); } catch (EOFException e) { } break; case '\n': c = NEWLINE_MARKER; break; case '\t': break; default: if (c >= 0x20) { if (Utf16.isSurrogate(c)) { if (Utf16.isSurrogate2(c)) throw new EscapeSyntaxException("illegal_surrogate_pair", line, column + 1); if (++bufpos == available) AdjustBuffSize(); buffer[bufpos] = c; // UpdateLineColumn(c); try { c = ReadChar(); } catch (EOFException e) { throw new EscapeSyntaxException("illegal_surrogate_pair", line, column + 1); } if (!Utf16.isSurrogate2(c)) throw new EscapeSyntaxException("illegal_surrogate_pair", line, column + 2); } break; } // fall through case '\uFFFE': case '\uFFFF': throw new EscapeSyntaxException("illegal_char_code", line, column + 1); } } catch (EOFException e) { if (bufpos == -1) { if (++bufpos == available) AdjustBuffSize(); bufline[bufpos] = line; bufcolumn[bufpos] = column; } throw e; } if (++bufpos == available) AdjustBuffSize(); buffer[bufpos] = c; UpdateLineColumn(c); try { if (c != '\\' || PeekChar() != 'x') return c; } catch (EOFException e) { return c; } int xCnt = 1; for (;;) { ReadChar(); if (++bufpos == available) AdjustBuffSize(); buffer[bufpos] = 'x'; UpdateLineColumn('x'); try { c = PeekChar(); } catch (EOFException e) { backup(xCnt); return '\\'; } if (c == '{') { ReadChar(); column++; // backup past the 'x's bufpos -= xCnt; if (bufpos < 0) bufpos += bufsize; break; } if (c != 'x') { backup(xCnt); return '\\'; } xCnt++; } try { int scalarValue = hexval(ReadChar()); column++; if (scalarValue < 0) throw new EscapeSyntaxException("illegal_hex_digit", line, column); while ((c = ReadChar()) != '}') { column++; int n = hexval(c); if (n < 0) throw new EscapeSyntaxException("illegal_hex_digit", line, column); scalarValue <<= 4; scalarValue |= n; if (scalarValue >= 0x110000) throw new EscapeSyntaxException("char_code_too_big", line, column); } column++; // for the '}' if (scalarValue <= 0xFFFF) { c = (char)scalarValue; switch (c) { case '\n': case '\r': case '\t': break; default: if (c >= 0x20 && !Utf16.isSurrogate(c)) break; // fall through case '\uFFFE': case '\uFFFF': throw new EscapeSyntaxException("illegal_char_code_ref", line, column); } buffer[bufpos] = c; return c; } c = Utf16.surrogate1(scalarValue); buffer[bufpos] = c; int bufpos1 = bufpos; if (++bufpos == bufsize) bufpos = 0; buffer[bufpos] = Utf16.surrogate2(scalarValue); bufline[bufpos] = bufline[bufpos1]; bufcolumn[bufpos] = bufcolumn[bufpos1]; backup(1); return c; } catch (EOFException e) { throw new EscapeSyntaxException("incomplete_escape", line, column); } } /** * @deprecated * @see #getEndColumn */ public final int getColumn() { return bufcolumn[bufpos]; } /** * @deprecated * @see #getEndLine */ public final int getLine() { return bufline[bufpos]; } public final int getEndColumn() { return bufcolumn[bufpos]; } public final int getEndLine() { return bufline[bufpos]; } public final int getBeginColumn() { return bufcolumn[tokenBegin]; } public final int getBeginLine() { return bufline[tokenBegin]; } public final void backup(int amount) { inBuf += amount; if ((bufpos -= amount) < 0) bufpos += bufsize; } public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; nextCharBuf = new char[4096]; skipBOM(); } public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } public JavaCharStream(java.io.Reader dstream) { this(dstream, 1, 1, 4096); } public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; closed = false; line = startline; column = startcolumn - 1; if (buffer == null || buffersize != buffer.length) { available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; nextCharBuf = new char[4096]; } prevCharIsLF = false; tokenBegin = inBuf = maxNextCharInd = 0; nextCharInd = bufpos = -1; skipBOM(); } public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } public void ReInit(java.io.Reader dstream) { ReInit(dstream, 1, 1, 4096); } public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); } public JavaCharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { this(dstream, encoding, startline, startcolumn, 4096); } public JavaCharStream(java.io.InputStream dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } public JavaCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { this(dstream, encoding, 1, 1, 4096); } public JavaCharStream(java.io.InputStream dstream) { this(dstream, 1, 1, 4096); } public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); } public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { ReInit(dstream, encoding, startline, startcolumn, 4096); } public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { ReInit(dstream, encoding, 1, 1, 4096); } public void ReInit(java.io.InputStream dstream) { ReInit(dstream, 1, 1, 4096); } static private final char BOM = '\ufeff'; private void skipBOM() { try { if (PeekChar() == BOM) ReadChar(); } catch (EOFException e) { } } public final String GetImage() { if (bufpos >= tokenBegin) return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); else return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); } public final char[] GetSuffix(int len) { char[] ret = new char[len]; if ((bufpos + 1) >= len) System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); else { System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } return ret; } public void Done() { nextCharBuf = null; buffer = null; bufline = null; bufcolumn = null; } /** * Method to adjust line and column numbers for the start of a token.
    */ public void adjustBeginLineColumn(int newLine, int newCol) { int start = tokenBegin; int len; if (bufpos >= tokenBegin) { len = bufpos - tokenBegin + inBuf + 1; } else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } int i = 0, j = 0, k = 0; int nextColDiff = 0, columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff; i++; } if (i < len) { bufline[j] = newLine++; bufcolumn[j] = newCol + columnDiff; while (i++ < len) { if (bufline[j = start % bufsize] != bufline[++start % bufsize]) bufline[j] = newLine++; else bufline[j] = newLine; } } line = bufline[j]; column = bufcolumn[j]; } } resources/000077500000000000000000000000001225366607500332255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compactMessages.properties000066400000000000000000000030401225366607500371070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/compact/resourcessyntax_error=syntax error undeclared_prefix=undeclared prefix \"{0}\" xmlns_prefix=prefix must not be \"xmlns\" unqualified_annotation_attribute=annotation attribute must have a namespace URI inherited_annotation_namespace=namespace URI for annotation cannot be inherited xmlns_annotation_attribute=annotation attribute cannot be named \"xmlns\" duplicate_attribute=multiple attributes with local name \"{0}\" and namespace URI \"{1}\" except_missing_parentheses=parentheses required around \"-\" expression xmlns_annotation_attribute_uri=annotation attribute cannot have namespace URI \"http://www.w3.org/2000/xmlns\" xml_prefix_bad_uri=prefix \"xml\" can only be bound to namespace URI \"http://www.w3.org/XML/1998/namespace\" xml_uri_bad_prefix=only prefix \"xml\" can be bound to namespace URI \"http://www.w3.org/XML/1998/namespace\" illegal_hex_digit=expected hex digit char_code_too_big=character code must be less than 0x110000 illegal_char_code=code of character that is not allowed illegal_char_code_ref=reference to character whose code is not allowed incomplete_escape=incomplete escape sequence any_name_except_contains_any_name=\"except\" in \"anyName\" contains \"anyName\" ns_name_except_contains_any_name=\"except\" in \"nsName\" contains \"anyName\" ns_name_except_contains_ns_name=\"except\" in \"nsName\" contains \"nsName\" illegal_surrogate_pair=illegal surrogate pair relax_ng_namespace=annotations cannot have namespace URI \"http://relaxng.org/ns/structure/1.0\" top_level_follow_annotation=top-level pattern cannot have following annotations jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/sax/000077500000000000000000000000001225366607500304375ustar00rootroot00000000000000DtdContext.java000066400000000000000000000025231225366607500333050ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/saxpackage com.thaiopensource.relaxng.parse.sax; import org.relaxng.datatype.ValidationContext; import org.xml.sax.DTDHandler; import org.xml.sax.SAXException; import java.util.HashSet; import java.util.Set; public abstract class DtdContext implements DTDHandler, ValidationContext { private final Set notations; private final Set unparsedEntities; public DtdContext() { notations = new HashSet(); unparsedEntities = new HashSet(); } public DtdContext(DtdContext dc) { notations = dc.notations; unparsedEntities = dc.unparsedEntities; } public void notationDecl(String name, String publicId, String systemId) throws SAXException { notations.add(name); } public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { unparsedEntities.add(name); } public boolean isNotation(String notationName) { return notations.contains(notationName); } public boolean isUnparsedEntity(String entityName) { return unparsedEntities.contains(entityName); } public void clearDtdContext() { notations.clear(); unparsedEntities.clear(); } } SAXParseReceiver.java000066400000000000000000000021721225366607500343400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/saxpackage com.thaiopensource.relaxng.parse.sax; import com.thaiopensource.relaxng.parse.ParseReceiver; import com.thaiopensource.relaxng.parse.ParsedPatternFuture; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; public class SAXParseReceiver, A extends Annotations> extends SAXSubParser implements ParseReceiver { public SAXParseReceiver(SAXResolver resolver, ErrorHandler eh) { super(resolver, eh); } public ParsedPatternFuture

    installHandlers(XMLReader xr, SchemaBuilder schemaBuilder, Scope scope) throws SAXException { return new SchemaParser(xr, eh, schemaBuilder, null, scope); } } SAXParseable.java000066400000000000000000000047421225366607500335040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/saxpackage com.thaiopensource.relaxng.parse.sax; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.relaxng.parse.SubParseable; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.Uri; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.transform.sax.SAXSource; import java.io.IOException; public class SAXParseable, A extends Annotations> extends SAXSubParser implements SubParseable { private final SAXSource source; /** * * @param source XMLReader must be non-null * @param resolver * @param eh */ public SAXParseable(SAXSource source, SAXResolver resolver, ErrorHandler eh) { super(resolver, eh); this.source = source; } public P parse(SchemaBuilder schemaBuilder, Scope scope) throws BuildException, IllegalSchemaException { try { XMLReader xr = source.getXMLReader(); SchemaParser sp = new SchemaParser(xr, eh, schemaBuilder, null, scope); xr.parse(source.getInputSource()); return sp.getParsedPattern(); } catch (SAXException e) { throw BuildException.fromSAXException(e); } catch (IOException e) { throw new BuildException(e); } } public P parseAsInclude(SchemaBuilder schemaBuilder, IncludedGrammar g) throws BuildException, IllegalSchemaException { try { XMLReader xr = source.getXMLReader(); SchemaParser sp = new SchemaParser(xr, eh, schemaBuilder, g, g); xr.parse(source.getInputSource()); return sp.getParsedPattern(); } catch (SAXException e) { throw BuildException.fromSAXException(e); } catch (IOException e) { throw new BuildException(e); } } public String getUri() { final String uri = source.getInputSource().getSystemId(); if (uri == null) return null; return Uri.escapeDisallowedChars(uri); } } SAXSubParser.java000066400000000000000000000023441225366607500335100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/saxpackage com.thaiopensource.relaxng.parse.sax; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.SubParseable; import com.thaiopensource.relaxng.parse.SubParser; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public class SAXSubParser, A extends Annotations> implements SubParser { final SAXResolver resolver; final ErrorHandler eh; SAXSubParser(SAXResolver resolver, ErrorHandler eh) { this.resolver = resolver; this.eh = eh; } public SubParseable createSubParseable(String href, String base) throws BuildException { try { return new SAXParseable(resolver.resolve(href, base, WellKnownNamespaces.RELAX_NG), resolver, eh); } catch (SAXException e) { throw BuildException.fromSAXException(e); } catch (IOException e) { throw new BuildException(e); } } } SchemaParser.java000066400000000000000000001343671225366607500336160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/saxpackage com.thaiopensource.relaxng.parse.sax; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.Context; import com.thaiopensource.relaxng.parse.DataPatternBuilder; import com.thaiopensource.relaxng.parse.Div; import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; import com.thaiopensource.relaxng.parse.Grammar; import com.thaiopensource.relaxng.parse.GrammarSection; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Include; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.ParsedPatternFuture; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.Uri; import com.thaiopensource.xml.sax.AbstractLexicalHandler; import com.thaiopensource.xml.sax.XmlBaseHandler; import com.thaiopensource.xml.util.Naming; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.ErrorHandler; 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.helpers.DefaultHandler; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; class SchemaParser, AnnotationsImpl extends Annotations> implements ParsedPatternFuture { private static final String relaxngURIPrefix = WellKnownNamespaces.RELAX_NG.substring(0, WellKnownNamespaces.RELAX_NG.lastIndexOf('/') + 1); static final String relaxng10URI = WellKnownNamespaces.RELAX_NG; private static final Localizer localizer = new Localizer(SchemaParser.class); private String relaxngURI; private final XMLReader xr; private final ErrorHandler eh; private final SchemaBuilder schemaBuilder; private Pattern startPattern; private Locator locator; private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler(); private final ContextImpl context = new ContextImpl(); private boolean hadError = false; private Map patternMap; private Map nameClassMap; static class PrefixMapping { final String prefix; final String uri; final PrefixMapping next; PrefixMapping(String prefix, String uri, PrefixMapping next) { this.prefix = prefix; this.uri = uri; this.next = next; } } static abstract class AbstractContext extends DtdContext implements Context { PrefixMapping prefixMapping; AbstractContext() { prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); } AbstractContext(AbstractContext context) { super(context); prefixMapping = context.prefixMapping; } public String resolveNamespacePrefix(String prefix) { for (PrefixMapping p = prefixMapping; p != null; p = p.next) if (p.prefix.equals(prefix)) return p.uri; return null; } public Set prefixes() { Set set = new HashSet(); for (PrefixMapping p = prefixMapping; p != null; p = p.next) set.add(p.prefix); return set; } public Context copy() { return new SavedContext(this); } } static class SavedContext extends AbstractContext { private final String baseUri; SavedContext(AbstractContext context) { super(context); this.baseUri = context.getBaseUri(); } public String getBaseUri() { return baseUri; } } class ContextImpl extends AbstractContext { public String getBaseUri() { return xmlBaseHandler.getBaseUri(); } } static interface CommentHandler { void comment(String value); } abstract class Handler implements ContentHandler, CommentHandler { CommentListImpl comments; CommentListImpl getComments() { CommentListImpl tem = comments; comments = null; return tem; } public void comment(String value) { if (comments == null) comments = schemaBuilder.makeCommentList(); comments.addComment(value, makeLocation()); } public void processingInstruction(String target, String date) { } public void skippedEntity(String name) { } public void ignorableWhitespace(char[] ch, int start, int len) { } public void startDocument() { } public void endDocument() { } public void startPrefixMapping(String prefix, String uri) { context.prefixMapping = new PrefixMapping(prefix, uri, context.prefixMapping); } public void endPrefixMapping(String prefix) { context.prefixMapping = context.prefixMapping.next; } public void setDocumentLocator(Locator loc) { locator = loc; xmlBaseHandler.setLocator(loc); } } abstract class State extends Handler { State parent; String nsInherit; String ns; String datatypeLibrary; Scope scope; Location startLocation; AnnotationsImpl annotations; void set() { xr.setContentHandler(this); } abstract State create(); abstract State createChildState(String localName) throws SAXException; RootState toRootState() { return null; } NameClassChoiceState toNameClassChoiceState() { return null; } void setParent(State parent) { this.parent = parent; this.nsInherit = parent.getNs(); this.datatypeLibrary = parent.datatypeLibrary; this.scope = parent.scope; this.startLocation = makeLocation(); if (parent.comments != null) { annotations = schemaBuilder.makeAnnotations(parent.comments, getContext()); parent.comments = null; } else if (parent.toRootState() != null) annotations = schemaBuilder.makeAnnotations(null, getContext()); } String getNs() { return ns == null ? nsInherit : ns; } boolean isRelaxNGElement(String uri) throws SAXException { return uri.equals(relaxngURI); } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { xmlBaseHandler.startElement(); if (isRelaxNGElement(namespaceURI)) { State state = createChildState(localName); if (state == null) { xr.setContentHandler(new Skipper(this)); return; } state.setParent(this); state.set(); state.attributes(atts); } else { checkForeignElement(); ForeignElementHandler feh = new ForeignElementHandler(this, getComments()); feh.startElement(namespaceURI, localName, qName, atts); xr.setContentHandler(feh); } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { xmlBaseHandler.endElement(); parent.set(); end(); } void setName(String name) throws SAXException { error("illegal_name_attribute"); } void setOtherAttribute(String name, String value) throws SAXException { error("illegal_attribute_ignored", name); } void endAttributes() throws SAXException { } void checkForeignElement() throws SAXException { } void attributes(Attributes atts) throws SAXException { int len = atts.getLength(); for (int i = 0; i < len; i++) { String uri = atts.getURI(i); if (uri.length() == 0) { String name = atts.getLocalName(i); if (name.equals("name")) setName(atts.getValue(i).trim()); else if (name.equals("ns")) ns = atts.getValue(i); else if (name.equals("datatypeLibrary")) { datatypeLibrary = atts.getValue(i); checkUri(datatypeLibrary); if (!datatypeLibrary.equals("") && !Uri.isAbsolute(datatypeLibrary)) error("relative_datatype_library"); if (Uri.hasFragmentId(datatypeLibrary)) error("fragment_identifier_datatype_library"); datatypeLibrary = Uri.escapeDisallowedChars(datatypeLibrary); } else setOtherAttribute(name, atts.getValue(i)); } else if (uri.equals(relaxngURI)) error("qualified_attribute", atts.getLocalName(i)); else if (uri.equals(WellKnownNamespaces.XML) && atts.getLocalName(i).equals("base")) xmlBaseHandler.xmlBaseAttribute(atts.getValue(i)); else { if (annotations == null) annotations = schemaBuilder.makeAnnotations(null, getContext()); annotations.addAttribute(uri, atts.getLocalName(i), findPrefix(atts.getQName(i), uri), atts.getValue(i), startLocation); } } endAttributes(); } abstract void end() throws SAXException; void endPatternChild(Pattern pattern) { // XXX cannot happen; throw exception } void endNameClassChild(NameClass nc) { // XXX cannot happen; throw exception } public void startDocument() { } public void endDocument() { if (comments != null && startPattern != null) { startPattern = schemaBuilder.commentAfterPattern(startPattern, comments); comments = null; } } public void characters(char[] ch, int start, int len) throws SAXException { for (int i = 0; i < len; i++) { switch(ch[start + i]) { case ' ': case '\r': case '\n': case '\t': break; default: error("illegal_characters_ignored"); break; } } } boolean isPatternNamespaceURI(String s) { return s.equals(relaxngURI); } void endForeignChild(ElementAnnotation ea) { if (annotations == null) annotations = schemaBuilder.makeAnnotations(null, getContext()); annotations.addElement(ea); } void mergeLeadingComments() { if (comments != null) { if (annotations == null) annotations = schemaBuilder.makeAnnotations(comments, getContext()); else annotations.addLeadingComment(comments); comments = null; } } } class ForeignElementHandler extends Handler { final State nextState; ElementAnnotationBuilder builder; final Stack> builderStack = new Stack>(); StringBuffer textBuf; Location textLoc; ForeignElementHandler(State nextState, CommentListImpl comments) { this.nextState = nextState; this.comments = comments; } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) { flushText(); if (builder != null) builderStack.push(builder); Location loc = makeLocation(); builder = schemaBuilder.makeElementAnnotationBuilder(namespaceURI, localName, findPrefix(qName, namespaceURI), loc, getComments(), getContext()); int len = atts.getLength(); for (int i = 0; i < len; i++) { String uri = atts.getURI(i); builder.addAttribute(uri, atts.getLocalName(i), findPrefix(atts.getQName(i), uri), atts.getValue(i), loc); } } public void endElement(String namespaceURI, String localName, String qName) { flushText(); if (comments != null) builder.addComment(getComments()); ElementAnnotation ea = builder.makeElementAnnotation(); if (builderStack.empty()) { nextState.endForeignChild(ea); nextState.set(); } else { builder = builderStack.pop(); builder.addElement(ea); } } public void characters(char ch[], int start, int length) { if (textBuf == null) textBuf = new StringBuffer(); textBuf.append(ch, start, length); if (textLoc == null) textLoc = makeLocation(); } public void comment(String value) { flushText(); super.comment(value); } void flushText() { if (textBuf != null && textBuf.length() != 0) { builder.addText(textBuf.toString(), textLoc, getComments()); textBuf.setLength(0); } textLoc = null; } } class Skipper extends DefaultHandler implements CommentHandler { int level = 1; final State nextState; Skipper(State nextState) { this.nextState = nextState; } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { ++level; } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (--level == 0) nextState.set(); } public void comment(String value) { } } abstract class EmptyContentState extends State { State createChildState(String localName) throws SAXException { error("expected_empty", localName); return null; } abstract Pattern makePattern() throws SAXException; void end() throws SAXException { if (comments != null) { if (annotations == null) annotations = schemaBuilder.makeAnnotations(null, getContext()); annotations.addComment(comments); comments = null; } parent.endPatternChild(makePattern()); } } abstract class PatternContainerState extends State { List childPatterns = new ArrayList(); State createChildState(String localName) throws SAXException { State state = patternMap.get(localName); if (state == null) { error("expected_pattern", localName); return null; } return state.create(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { if (patterns.size() == 1 && anno == null) return patterns.get(0); return schemaBuilder.makeGroup(patterns, loc, anno); } void endPatternChild(Pattern pattern) { childPatterns.add(pattern); } void endForeignChild(ElementAnnotation ea) { int nChildPatterns = childPatterns.size(); if (nChildPatterns == 0) super.endForeignChild(ea); else childPatterns.set(nChildPatterns - 1, schemaBuilder.annotateAfterPattern(childPatterns.get(nChildPatterns - 1), ea)); } void end() throws SAXException { if (childPatterns.size() == 0) { error("missing_children"); endPatternChild(schemaBuilder.makeErrorPattern()); } if (comments != null) { int nChildPatterns = childPatterns.size(); childPatterns.set(nChildPatterns - 1, schemaBuilder.commentAfterPattern(childPatterns.get(nChildPatterns - 1), comments)); comments = null; } sendPatternToParent(buildPattern(childPatterns, startLocation, annotations)); } void sendPatternToParent(Pattern p) { parent.endPatternChild(p); } } class GroupState extends PatternContainerState { State create() { return new GroupState(); } } class ZeroOrMoreState extends PatternContainerState { State create() { return new ZeroOrMoreState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeZeroOrMore(super.buildPattern(patterns, loc, null), loc, anno); } } class OneOrMoreState extends PatternContainerState { State create() { return new OneOrMoreState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeOneOrMore(super.buildPattern(patterns, loc, null), loc, anno); } } class OptionalState extends PatternContainerState { State create() { return new OptionalState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeOptional(super.buildPattern(patterns, loc, null), loc, anno); } } class ListState extends PatternContainerState { State create() { return new ListState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeList(super.buildPattern(patterns, loc, null), loc, anno); } } class ChoiceState extends PatternContainerState { State create() { return new ChoiceState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeChoice(patterns, loc, anno); } } class InterleaveState extends PatternContainerState { State create() { return new InterleaveState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) { return schemaBuilder.makeInterleave(patterns, loc, anno); } } class MixedState extends PatternContainerState { State create() { return new MixedState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeMixed(super.buildPattern(patterns, loc, null), loc, anno); } } static interface NameClassRef { void setNameClass(NC nc); } class ElementState extends PatternContainerState implements NameClassRef { NameClass nameClass; boolean nameClassWasAttribute; String name; void setName(String name) { this.name = name; } public void setNameClass(NameClass nc) { nameClass = nc; } void endAttributes() throws SAXException { if (name != null) { nameClass = expandName(name, getNs(), null); nameClassWasAttribute = true; } else new NameClassChildState(this, this).set(); } State create() { return new ElementState(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeElement(nameClass, super.buildPattern(patterns, loc, null), loc, anno); } void endForeignChild(ElementAnnotation ea) { if (nameClassWasAttribute || childPatterns.size() > 0 || nameClass == null) super.endForeignChild(ea); else nameClass = schemaBuilder.annotateAfterNameClass(nameClass, ea); } } class RootState extends PatternContainerState { IncludedGrammar grammar; RootState() { } RootState(IncludedGrammar grammar, Scope scope, String ns) { this.grammar = grammar; this.scope = scope; this.nsInherit = ns; this.datatypeLibrary = ""; } RootState toRootState() { return this; } State create() { return new RootState(); } State createChildState(String localName) throws SAXException { if (grammar == null) return super.createChildState(localName); if (localName.equals("grammar")) return new MergeGrammarState(grammar); error("expected_grammar", localName); return null; } void checkForeignElement() throws SAXException { error("root_bad_namespace_uri", WellKnownNamespaces.RELAX_NG); } void endPatternChild(Pattern pattern) { startPattern = pattern; } boolean isRelaxNGElement(String uri) throws SAXException { if (!uri.startsWith(relaxngURIPrefix)) return false; if (!uri.equals(WellKnownNamespaces.RELAX_NG)) warning("wrong_uri_version", WellKnownNamespaces.RELAX_NG.substring(relaxngURIPrefix.length()), uri.substring(relaxngURIPrefix.length())); relaxngURI = uri; return true; } } class NotAllowedState extends EmptyContentState { State create() { return new NotAllowedState(); } Pattern makePattern() { return schemaBuilder.makeNotAllowed(startLocation, annotations); } } class EmptyState extends EmptyContentState { State create() { return new EmptyState(); } Pattern makePattern() { return schemaBuilder.makeEmpty(startLocation, annotations); } } class TextState extends EmptyContentState { State create() { return new TextState(); } Pattern makePattern() { return schemaBuilder.makeText(startLocation, annotations); } } class ValueState extends EmptyContentState { final StringBuffer buf = new StringBuffer(); String type; State create() { return new ValueState(); } void setOtherAttribute(String name, String value) throws SAXException { if (name.equals("type")) type = checkNCName(value.trim()); else super.setOtherAttribute(name, value); } public void characters(char[] ch, int start, int len) { buf.append(ch, start, len); } void checkForeignElement() throws SAXException { error("value_contains_foreign_element"); } Pattern makePattern() throws SAXException { if (type == null) return makePattern("", "token"); else return makePattern(datatypeLibrary, type); } void end() throws SAXException { mergeLeadingComments(); super.end(); } Pattern makePattern(String datatypeLibrary, String type) { return schemaBuilder.makeValue(datatypeLibrary, type, buf.toString(), getContext(), getNs(), startLocation, annotations); } } class DataState extends State { String type; Pattern except = null; DataPatternBuilder dpb = null; State create() { return new DataState(); } State createChildState(String localName) throws SAXException { if (localName.equals("param")) { if (except != null) error("param_after_except"); return new ParamState(dpb); } if (localName.equals("except")) { if (except != null) error("multiple_except"); return new ChoiceState(); } error("expected_param_except", localName); return null; } void setOtherAttribute(String name, String value) throws SAXException { if (name.equals("type")) type = checkNCName(value.trim()); else super.setOtherAttribute(name, value); } void endAttributes() throws SAXException { if (type == null) error("missing_type_attribute"); else dpb = schemaBuilder.makeDataPatternBuilder(datatypeLibrary, type, startLocation); } void endForeignChild(ElementAnnotation ea) { dpb.annotation(ea); } void end() throws SAXException { Pattern p; if (dpb != null) { if (except != null) p = dpb.makePattern(except, startLocation, annotations); else p = dpb.makePattern(startLocation, annotations); } else p = schemaBuilder.makeErrorPattern(); // XXX need to capture comments parent.endPatternChild(p); } void endPatternChild(Pattern pattern) { except = pattern; } } class ParamState extends State { private final StringBuffer buf = new StringBuffer(); private final DataPatternBuilder dpb; private String name; ParamState(DataPatternBuilder dpb) { this.dpb = dpb; } State create() { return new ParamState(null); } void setName(String name) throws SAXException { this.name = checkNCName(name); } void endAttributes() throws SAXException { if (name == null) error("missing_name_attribute"); } State createChildState(String localName) throws SAXException { error("expected_empty", localName); return null; } public void characters(char[] ch, int start, int len) { buf.append(ch, start, len); } void checkForeignElement() throws SAXException { error("param_contains_foreign_element"); } void end() throws SAXException { if (name == null) return; if (dpb == null) return; mergeLeadingComments(); dpb.addParam(name, buf.toString(), getContext(), getNs(), startLocation, annotations); } } class AttributeState extends PatternContainerState implements NameClassRef { NameClass nameClass; boolean nameClassWasAttribute; String name; State create() { return new AttributeState(); } void setName(String name) { this.name = name; } public void setNameClass(NameClass nc) { nameClass = nc; } void endAttributes() throws SAXException { if (name != null) { String nsUse; if (ns != null) nsUse = ns; else nsUse = ""; nameClass = expandName(name, nsUse, null); nameClassWasAttribute = true; } else new NameClassChildState(this, this).set(); } void endForeignChild(ElementAnnotation ea) { if (nameClassWasAttribute || childPatterns.size() > 0 || nameClass == null) super.endForeignChild(ea); else nameClass = schemaBuilder.annotateAfterNameClass(nameClass, ea); } void end() throws SAXException { if (childPatterns.size() == 0) endPatternChild(schemaBuilder.makeText(startLocation, null)); super.end(); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return schemaBuilder.makeAttribute(nameClass, super.buildPattern(patterns, loc, null), loc, anno); } State createChildState(String localName) throws SAXException { State tem = super.createChildState(localName); if (tem != null && childPatterns.size() != 0) error("attribute_multi_pattern"); return tem; } } abstract class SinglePatternContainerState extends PatternContainerState { State createChildState(String localName) throws SAXException { if (childPatterns.size() == 0) return super.createChildState(localName); error("too_many_children"); return null; } } class GrammarSectionState extends State { GrammarSection section; GrammarSectionState() { } GrammarSectionState(GrammarSection section) { this.section = section; } State create() { return new GrammarSectionState(null); } State createChildState(String localName) throws SAXException { if (localName.equals("define")) return new DefineState(section); if (localName.equals("start")) return new StartState(section); if (localName.equals("include")) { Include include = section.makeInclude(); if (include != null) return new IncludeState(include); } if (localName.equals("div")) return new DivState(section.makeDiv()); error("expected_define", localName); // XXX better errors return null; } void end() throws SAXException { if (comments != null) { section.topLevelComment(comments); comments = null; } } void endForeignChild(ElementAnnotation ea) { section.topLevelAnnotation(ea); } } class DivState extends GrammarSectionState { final Div div; DivState(Div div) { super(div); this.div = div; } void end() throws SAXException { super.end(); div.endDiv(startLocation, annotations); } } class IncludeState extends GrammarSectionState { String href; String base; final Include include; IncludeState(Include include) { super(include); this.include = include; } void setOtherAttribute(String name, String value) throws SAXException { if (name.equals("href")) { href = value; checkUriNoFragmentId(href); } else super.setOtherAttribute(name, value); } void endAttributes() throws SAXException { if (href == null) error("missing_href_attribute"); else base = xmlBaseHandler.getBaseUri(); } void end() throws SAXException { super.end(); if (href != null) { try { include.endInclude(href, base, getNs(), startLocation, annotations); } catch (IllegalSchemaException e) { } } } } class MergeGrammarState extends GrammarSectionState { final IncludedGrammar grammar; MergeGrammarState(IncludedGrammar grammar) { super(grammar); this.grammar = grammar; } void end() throws SAXException { super.end(); parent.endPatternChild(grammar.endIncludedGrammar(startLocation, annotations)); } } class GrammarState extends GrammarSectionState { Grammar grammar; void setParent(State parent) { super.setParent(parent); grammar = schemaBuilder.makeGrammar(scope); section = grammar; scope = grammar; } State create() { return new GrammarState(); } void end() throws SAXException { super.end(); parent.endPatternChild(grammar.endGrammar(startLocation, annotations)); } } class RefState extends EmptyContentState { String name; State create() { return new RefState(); } void endAttributes() throws SAXException { if (name == null) error("missing_name_attribute"); } void setName(String name) throws SAXException { this.name = checkNCName(name); } Pattern makePattern() { if (name == null) return schemaBuilder.makeErrorPattern(); return scope.makeRef(name, startLocation, annotations); } } class ParentRefState extends RefState { State create() { return new ParentRefState(); } Pattern makePattern() { if (name == null) return schemaBuilder.makeErrorPattern(); return scope.makeParentRef(name, startLocation, annotations); } } class ExternalRefState extends EmptyContentState { String href; String base; Pattern includedPattern; State create() { return new ExternalRefState(); } void setOtherAttribute(String name, String value) throws SAXException { if (name.equals("href")) { href = value; checkUriNoFragmentId(href); } else super.setOtherAttribute(name, value); } void endAttributes() throws SAXException { if (href == null) error("missing_href_attribute"); else base = xmlBaseHandler.getBaseUri(); } Pattern makePattern() { if (href != null) { try { return schemaBuilder.makeExternalRef(href, base, getNs(), scope, startLocation, annotations); } catch (IllegalSchemaException e) { } } return schemaBuilder.makeErrorPattern(); } } abstract class DefinitionState extends PatternContainerState { GrammarSection.Combine combine = null; final GrammarSection section; DefinitionState(GrammarSection section) { this.section = section; } void setOtherAttribute(String name, String value) throws SAXException { if (name.equals("combine")) { value = value.trim(); if (value.equals("choice")) combine = GrammarSection.COMBINE_CHOICE; else if (value.equals("interleave")) combine = GrammarSection.COMBINE_INTERLEAVE; else error("combine_attribute_bad_value", value); } else super.setOtherAttribute(name, value); } Pattern buildPattern(List patterns, Location loc, AnnotationsImpl anno) throws SAXException { return super.buildPattern(patterns, loc, null); } } class DefineState extends DefinitionState { String name; DefineState(GrammarSection section) { super(section); } State create() { return new DefineState(null); } void setName(String name) throws SAXException { this.name = checkNCName(name); } void endAttributes() throws SAXException { if (name == null) error("missing_name_attribute"); } void sendPatternToParent(Pattern p) { if (name != null) section.define(name, combine, p, startLocation, annotations); } } class StartState extends DefinitionState { StartState(GrammarSection section) { super(section); } State create() { return new StartState(null); } void sendPatternToParent(Pattern p) { section.define(GrammarSection.START, combine, p, startLocation, annotations); } State createChildState(String localName) throws SAXException { State tem = super.createChildState(localName); if (tem != null && childPatterns.size() != 0) error("start_multi_pattern"); return tem; } } abstract class NameClassContainerState extends State { State createChildState(String localName) throws SAXException { State state = nameClassMap.get(localName); if (state == null) { error("expected_name_class", localName); return null; } return state.create(); } } class NameClassChildState extends NameClassContainerState { final State prevState; final NameClassRef nameClassRef; State create() { return null; } NameClassChildState(State prevState, NameClassRef nameClassRef) { this.prevState = prevState; this.nameClassRef = nameClassRef; setParent(prevState.parent); this.ns = prevState.ns; } void endNameClassChild(NameClass nameClass) { nameClassRef.setNameClass(nameClass); prevState.set(); } void endForeignChild(ElementAnnotation ea) { prevState.endForeignChild(ea); } void end() throws SAXException { nameClassRef.setNameClass(schemaBuilder.makeErrorNameClass()); error("missing_name_class"); prevState.set(); prevState.end(); } } abstract class NameClassBaseState extends State { abstract NameClass makeNameClass() throws SAXException; void end() throws SAXException { parent.endNameClassChild(makeNameClass()); } } class NameState extends NameClassBaseState { final StringBuffer buf = new StringBuffer(); State createChildState(String localName) throws SAXException { error("expected_name", localName); return null; } State create() { return new NameState(); } public void characters(char[] ch, int start, int len) { buf.append(ch, start, len); } void checkForeignElement() throws SAXException { error("name_contains_foreign_element"); } NameClass makeNameClass() throws SAXException { mergeLeadingComments(); return expandName(buf.toString().trim(), getNs(), annotations); } } private static final int PATTERN_CONTEXT = 0; private static final int ANY_NAME_CONTEXT = 1; private static final int NS_NAME_CONTEXT = 2; class AnyNameState extends NameClassBaseState { NameClass except = null; State create() { return new AnyNameState(); } State createChildState(String localName) throws SAXException { if (localName.equals("except")) { if (except != null) error("multiple_except"); return new NameClassChoiceState(getContext()); } error("expected_except", localName); return null; } int getContext() { return ANY_NAME_CONTEXT; } NameClass makeNameClass() { if (except == null) return makeNameClassNoExcept(); else return makeNameClassExcept(except); } NameClass makeNameClassNoExcept() { return schemaBuilder.makeAnyName(startLocation, annotations); } NameClass makeNameClassExcept(NameClass except) { return schemaBuilder.makeAnyName(except, startLocation, annotations); } void endNameClassChild(NameClass nameClass) { except = nameClass; } } class NsNameState extends AnyNameState { State create() { return new NsNameState(); } NameClass makeNameClassNoExcept() { return schemaBuilder.makeNsName(getNs(), null, null); } NameClass makeNameClassExcept(NameClass except) { return schemaBuilder.makeNsName(getNs(), except, null, null); } int getContext() { return NS_NAME_CONTEXT; } } class NameClassChoiceState extends NameClassContainerState { private List nameClasses = new ArrayList(); private int context; NameClassChoiceState() { this.context = PATTERN_CONTEXT; } NameClassChoiceState(int context) { this.context = context; } NameClassChoiceState toNameClassChoiceState() { return this; } void setParent(State parent) { super.setParent(parent); NameClassChoiceState parentChoice = parent.toNameClassChoiceState(); if (parentChoice != null) this.context = parentChoice.context; } State create() { return new NameClassChoiceState(); } State createChildState(String localName) throws SAXException { if (localName.equals("anyName")) { if (context >= ANY_NAME_CONTEXT) { error(context == ANY_NAME_CONTEXT ? "any_name_except_contains_any_name" : "ns_name_except_contains_any_name"); return null; } } else if (localName.equals("nsName")) { if (context == NS_NAME_CONTEXT) { error("ns_name_except_contains_ns_name"); return null; } } return super.createChildState(localName); } void endNameClassChild(NameClass nc) { nameClasses.add(nc); } void endForeignChild(ElementAnnotation ea) { int nNameClasses = nameClasses.size(); if (nNameClasses == 0) super.endForeignChild(ea); else nameClasses.set(nNameClasses - 1, schemaBuilder.annotateAfterNameClass(nameClasses.get(nNameClasses - 1), ea)); } void end() throws SAXException { if (nameClasses.size() == 0) { error("missing_name_class"); parent.endNameClassChild(schemaBuilder.makeErrorNameClass()); return; } if (comments != null) { int nNameClasses = nameClasses.size(); nameClasses.set(nNameClasses - 1, schemaBuilder.commentAfterNameClass(nameClasses.get(nNameClasses - 1), comments)); comments = null; } parent.endNameClassChild(schemaBuilder.makeNameClassChoice(nameClasses, startLocation, annotations)); } } private void initPatternTable() { patternMap = new HashMap(); patternMap.put("zeroOrMore", new ZeroOrMoreState()); patternMap.put("oneOrMore", new OneOrMoreState()); patternMap.put("optional", new OptionalState()); patternMap.put("list", new ListState()); patternMap.put("choice", new ChoiceState()); patternMap.put("interleave", new InterleaveState()); patternMap.put("group", new GroupState()); patternMap.put("mixed", new MixedState()); patternMap.put("element", new ElementState()); patternMap.put("attribute", new AttributeState()); patternMap.put("empty", new EmptyState()); patternMap.put("text", new TextState()); patternMap.put("value", new ValueState()); patternMap.put("data", new DataState()); patternMap.put("notAllowed", new NotAllowedState()); patternMap.put("grammar", new GrammarState()); patternMap.put("ref", new RefState()); patternMap.put("parentRef", new ParentRefState()); patternMap.put("externalRef", new ExternalRefState()); } private void initNameClassTable() { nameClassMap = new HashMap(); nameClassMap.put("name", new NameState()); nameClassMap.put("anyName", new AnyNameState()); nameClassMap.put("nsName", new NsNameState()); nameClassMap.put("choice", new NameClassChoiceState()); } public Pattern getParsedPattern() throws IllegalSchemaException { if (hadError) throw new IllegalSchemaException(); return startPattern; } private void error(String key) throws SAXException { error(key, locator); } private void error(String key, String arg) throws SAXException { error(key, arg, locator); } void error(String key, String arg1, String arg2) throws SAXException { error(key, arg1, arg2, locator); } private void error(String key, Locator loc) throws SAXException { error(new SAXParseException(localizer.message(key), loc)); } private void error(String key, String arg, Locator loc) throws SAXException { error(new SAXParseException(localizer.message(key, arg), loc)); } private void error(String key, String arg1, String arg2, Locator loc) throws SAXException { error(new SAXParseException(localizer.message(key, arg1, arg2), loc)); } private void error(SAXParseException e) throws SAXException { hadError = true; if (eh != null) eh.error(e); } void warning(String key) throws SAXException { warning(key, locator); } private void warning(String key, String arg) throws SAXException { warning(key, arg, locator); } private void warning(String key, String arg1, String arg2) throws SAXException { warning(key, arg1, arg2, locator); } private void warning(String key, Locator loc) throws SAXException { warning(new SAXParseException(localizer.message(key), loc)); } private void warning(String key, String arg, Locator loc) throws SAXException { warning(new SAXParseException(localizer.message(key, arg), loc)); } private void warning(String key, String arg1, String arg2, Locator loc) throws SAXException { warning(new SAXParseException(localizer.message(key, arg1, arg2), loc)); } private void warning(SAXParseException e) throws SAXException { if (eh != null) eh.warning(e); } SchemaParser(XMLReader xr, ErrorHandler eh, SchemaBuilder schemaBuilder, IncludedGrammar grammar, Scope scope) throws SAXException { this.xr = xr; this.eh = eh; this.schemaBuilder = schemaBuilder; if (eh != null) xr.setErrorHandler(eh); xr.setDTDHandler(context); if (schemaBuilder.usesComments()) { try { xr.setProperty("http://xml.org/sax/properties/lexical-handler", new LexicalHandlerImpl()); } catch (SAXNotRecognizedException e) { warning("no_comment_support", xr.getClass().getName()); } catch (SAXNotSupportedException e) { warning("no_comment_support", xr.getClass().getName()); } } initPatternTable(); initNameClassTable(); new RootState(grammar, scope, SchemaBuilder.INHERIT_NS).set(); } private Context getContext() { return context; } class LexicalHandlerImpl extends AbstractLexicalHandler { private boolean inDtd = false; public void startDTD(String s, String s1, String s2) throws SAXException { inDtd = true; } public void endDTD() throws SAXException { inDtd = false; } public void comment(char[] chars, int start, int length) throws SAXException { if (!inDtd) ((CommentHandler)xr.getContentHandler()).comment(new String(chars, start, length)); } } private NameClass expandName(String name, String ns, AnnotationsImpl anno) throws SAXException { int ic = name.indexOf(':'); if (ic == -1) return schemaBuilder.makeName(ns, checkNCName(name), null, null, anno); String prefix = checkNCName(name.substring(0, ic)); String localName = checkNCName(name.substring(ic + 1)); for (PrefixMapping tem = context.prefixMapping; tem != null; tem = tem.next) if (tem.prefix.equals(prefix)) return schemaBuilder.makeName(tem.uri, localName, prefix, null, anno); error("undefined_prefix", prefix); return schemaBuilder.makeName("", localName, null, null, anno); } private String findPrefix(String qName, String uri) { String prefix = null; if (qName == null || qName.equals("")) { for (PrefixMapping p = context.prefixMapping; p != null; p = p.next) if (p.uri.equals(uri)) { prefix = p.prefix; break; } } else { int off = qName.indexOf(':'); if (off > 0) prefix = qName.substring(0, off); } return prefix; } private String checkNCName(String str) throws SAXException { if (!Naming.isNcname(str)) error("invalid_ncname", str); return str; } private Location makeLocation() { if (locator == null) return null; return schemaBuilder.makeLocation(locator.getSystemId(), locator.getLineNumber(), locator.getColumnNumber()); } private void checkUriNoFragmentId(String s) throws SAXException { checkUri(s); if (Uri.hasFragmentId(s)) error("href_fragment_id"); } private void checkUri(String s) throws SAXException { if (!Uri.isValid(s)) error("invalid_uri", s); } } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/sax/resources/000077500000000000000000000000001225366607500324515ustar00rootroot00000000000000Messages.properties000066400000000000000000000052031225366607500362570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/sax/resourcesno_comment_support=SAX parser \"{0}\" cannot report comments any_name_except_contains_any_name=\"except\" in \"anyName\" contains \"anyName\" attribute_multi_pattern=\"attribute\" pattern must contain at most one pattern combine_attribute_bad_value=bad value \"{0}\" for \"combine\" attribute; value must be \"choice\" or \"interleave\" expected_define=found \"{0}\" element but expected \"define\" or \"start\" or \"include\" or \"div\" element expected_empty=found \"{0}\" element but expected empty content expected_except=found \"{0}\" element but expected \"except\" expected_grammar=found \"{0}\" element but expected \"grammar\" element expected_name=found \"{0}\" element but expected a name expected_name_class=found \"{0}\" element but expected a name-class expected_param_except=only \"param\" and \"except\" child elements are allowed expected_pattern=found \"{0}\" element but expected a pattern fragment_identifier_datatype_library=URI in value of \"datatypeLibrary\" attribute must not have a fragment identifier href_fragment_id=fragment identifier ignored in value of \"href\" attribute illegal_attribute_ignored=illegal attribute \"{0}\" ignored illegal_characters_ignored=illegal characters ignored illegal_name_attribute=illegal \"name\" attribute invalid_ncname=\"{0}\" is not a valid local name invalid_uri=\"{0}\" is not a valid URI reference according to RFC 2396 missing_children=missing children missing_href_attribute=missing \"href\" attribute missing_name_attribute=missing \"name\" attribute missing_name_class=expected child element specifying name class missing_type_attribute=missing \"type\" attribute multiple_except=at most one \"except\" child element is allowed name_contains_foreign_element=\"name\" element cannot contain foreign elements ns_name_except_contains_any_name=\"except\" in \"nsName\" contains \"anyName\" ns_name_except_contains_ns_name=\"except\" in \"nsName\" contains \"nsName\" param_after_except=\"param\" is not allowed after \"except\" param_contains_foreign_element=\"param\" element cannot contain foreign elements qualified_attribute=attribute name \"{0}\" incorrectly qualified with RELAX NG namespace URI relative_datatype_library=URI in value of \"datatypeLibrary\" attribute must not be relative root_bad_namespace_uri=namespace URI of document element must be \"{0}\" start_multi_pattern=\"start\" pattern must contain at most one pattern too_many_children=too many child elements: only one child element is allowed undefined_prefix=undefined prefix \"{0}\" value_contains_foreign_element=\"value\" element cannot contain foreign elements wrong_uri_version=namespace URI has wrong version: expected \"{0}\" but got \"{1}\" jing-trang-20131210+dfsg+1/mod/rng-schema/000077500000000000000000000000001225366607500176775ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/mod.xml000066400000000000000000000003621225366607500212010ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/rng-schema/src/000077500000000000000000000000001225366607500204665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/000077500000000000000000000000001225366607500214125ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/000077500000000000000000000000001225366607500221705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/000077500000000000000000000000001225366607500252205ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500266605ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/000077500000000000000000000000001225366607500276055ustar00rootroot00000000000000AbstractPatternVisitor.java000066400000000000000000000035141225366607500350550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public abstract class AbstractPatternVisitor implements PatternVisitor { public T visitElement(ElementPattern p) { return visitNameClassed(p); } public T visitAttribute(AttributePattern p) { return visitNameClassed(p); } public T visitOneOrMore(OneOrMorePattern p) { return visitUnary(p); } public T visitZeroOrMore(ZeroOrMorePattern p) { return visitUnary(p); } public T visitOptional(OptionalPattern p) { return visitUnary(p); } public T visitInterleave(InterleavePattern p) { return visitComposite(p); } public T visitGroup(GroupPattern p) { return visitComposite(p); } public T visitChoice(ChoicePattern p) { return visitComposite(p); } public T visitGrammar(GrammarPattern p) { return visitPattern(p); } public T visitExternalRef(ExternalRefPattern p) { return visitPattern(p); } public T visitRef(RefPattern p) { return visitPattern(p); } public T visitParentRef(ParentRefPattern p) { return visitPattern(p); } public T visitValue(ValuePattern p) { return visitPattern(p); } public T visitData(DataPattern p) { return visitPattern(p); } public T visitMixed(MixedPattern p) { return visitUnary(p); } public T visitList(ListPattern p) { return visitUnary(p); } public T visitText(TextPattern p) { return visitPattern(p); } public T visitEmpty(EmptyPattern p) { return visitPattern(p); } public T visitNotAllowed(NotAllowedPattern p) { return visitPattern(p); } public T visitNameClassed(NameClassedPattern p) { return visitUnary(p); } public T visitUnary(UnaryPattern p) { return visitPattern(p); } public T visitComposite(CompositePattern p) { return visitPattern(p); } public abstract T visitPattern(Pattern p); } AbstractRefPattern.java000066400000000000000000000004661225366607500341350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public abstract class AbstractRefPattern extends Pattern { private String name; public AbstractRefPattern(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } AbstractVisitor.java000066400000000000000000000031261225366607500335160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import com.thaiopensource.util.VoidValue; public class AbstractVisitor extends AbstractPatternVisitor implements ComponentVisitor, NameClassVisitor, AnnotationChildVisitor, AttributeAnnotationVisitor { public VoidValue visitPattern(Pattern p) { return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { return visitComponent(c); } public VoidValue visitDiv(DivComponent c) { return visitComponent(c); } public VoidValue visitInclude(IncludeComponent c) { return visitComponent(c); } public VoidValue visitComponent(Component c) { return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { return visitNameClass(nc); } public VoidValue visitAnyName(AnyNameNameClass nc) { return visitNameClass(nc); } public VoidValue visitNsName(NsNameNameClass nc) { return visitNameClass(nc); } public VoidValue visitName(NameNameClass nc) { return visitNameClass(nc); } public VoidValue visitNameClass(NameClass nc) { return VoidValue.VOID; } public VoidValue visitText(TextAnnotation ta) { return visitAnnotationChild(ta); } public VoidValue visitComment(Comment c) { return visitAnnotationChild(c); } public VoidValue visitElement(ElementAnnotation ea) { return visitAnnotationChild(ea); } public VoidValue visitAnnotationChild(AnnotationChild ac) { return VoidValue.VOID; } public VoidValue visitAttribute(AttributeAnnotation a) { return VoidValue.VOID; } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Annotated.java000066400000000000000000000040111225366607500323610ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import java.util.List; import java.util.Vector; public abstract class Annotated extends SourceObject { private final List leadingComments = new Vector(); private final List attributeAnnotations = new Vector(); private final List childElementAnnotations = new Vector(); private final List followingElementAnnotations = new Vector(); private NamespaceContext context; public List getLeadingComments() { return leadingComments; } public List getAttributeAnnotations() { return attributeAnnotations; } public List getChildElementAnnotations() { return childElementAnnotations; } public List getFollowingElementAnnotations() { return followingElementAnnotations; } public boolean mayContainText() { return false; } public NamespaceContext getContext() { return context; } public void setContext(NamespaceContext context) { this.context = context; } public String getAttributeAnnotation(String ns, String localName) { for (AttributeAnnotation a : attributeAnnotations) if (a.getNamespaceUri().equals(ns) && a.getLocalName().equals(localName)) return a.getValue(); return null; } public void attributeAnnotationsAccept(AttributeAnnotationVisitor visitor) { for (AttributeAnnotation a : attributeAnnotations) a.accept(visitor); } public void childElementAnnotationsAccept(AnnotationChildVisitor visitor) { for (AnnotationChild a : childElementAnnotations) a.accept(visitor); } public void followingElementAnnotationsAccept(AnnotationChildVisitor visitor) { for (AnnotationChild a : followingElementAnnotations) a.accept(visitor); } public void leadingCommentsAccept(AnnotationChildVisitor visitor) { for (Comment c : leadingComments) c.accept(visitor); } } AnnotationChild.java000066400000000000000000000002541225366607500334500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public abstract class AnnotationChild extends SourceObject { public abstract T accept(AnnotationChildVisitor visitor); } AnnotationChildVisitor.java000066400000000000000000000003001225366607500350200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public interface AnnotationChildVisitor { T visitText(TextAnnotation ta); T visitComment(Comment c); T visitElement(ElementAnnotation ea); } AnyNameNameClass.java000066400000000000000000000004531225366607500335120ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class AnyNameNameClass extends OpenNameClass { public AnyNameNameClass() { } public AnyNameNameClass(NameClass except) { super(except); } public T accept(NameClassVisitor visitor) { return visitor.visitAnyName(this); } } AttributeAnnotation.java000066400000000000000000000021631225366607500343710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class AttributeAnnotation extends SourceObject { private String namespaceUri; private String localName; private String prefix; private String value; /** * namespaceUri is never null; empty string is used for absent namespace */ public AttributeAnnotation(String namespaceUri, String localName, String value) { this.namespaceUri = namespaceUri; this.localName = localName; this.value = value; } public String getNamespaceUri() { return namespaceUri; } public void setNamespaceUri(String namespaceUri) { this.namespaceUri = namespaceUri; } public String getLocalName() { return localName; } public void setLocalName(String localName) { this.localName = localName; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public T accept(AttributeAnnotationVisitor visitor) { return visitor.visitAttribute(this); } } AttributeAnnotationVisitor.java000066400000000000000000000002101225366607500357400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public interface AttributeAnnotationVisitor { T visitAttribute(AttributeAnnotation a); } AttributePattern.java000066400000000000000000000004511225366607500336720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class AttributePattern extends NameClassedPattern { public AttributePattern(NameClass nameClass, Pattern child) { super(nameClass, child); } public T accept(PatternVisitor visitor) { return visitor.visitAttribute(this); } } ChoiceNameClass.java000066400000000000000000000007701225366607500333560ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.ArrayList; import java.util.List; public class ChoiceNameClass extends NameClass { private final List children = new ArrayList(); public List getChildren() { return children; } public T accept(NameClassVisitor visitor) { return visitor.visitChoice(this); } public void childrenAccept(NameClassVisitor visitor) { for (NameClass nc : children) nc.accept(visitor); } } ChoicePattern.java000066400000000000000000000002771225366607500331270ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class ChoicePattern extends CompositePattern { public T accept(PatternVisitor visitor) { return visitor.visitChoice(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Combine.java000066400000000000000000000005311225366607500320230ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class Combine { public static final Combine CHOICE = new Combine("choice"); public static final Combine INTERLEAVE = new Combine("interleave"); private final String value; private Combine(String value) { this.value = value; } public String toString() { return value; } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Comment.java000066400000000000000000000006201225366607500320500ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class Comment extends AnnotationChild { private String value; public Comment(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public T accept(AnnotationChildVisitor visitor) { return visitor.visitComment(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Component.java000066400000000000000000000002351225366607500324120ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public abstract class Component extends Annotated { public abstract T accept(ComponentVisitor visitor); } ComponentVisitor.java000066400000000000000000000002731225366607500337150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public interface ComponentVisitor { T visitDiv(DivComponent c); T visitInclude(IncludeComponent c); T visitDefine(DefineComponent c); } CompositePattern.java000066400000000000000000000006221225366607500336710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.ArrayList; import java.util.List; public abstract class CompositePattern extends Pattern { private final List children = new ArrayList(); public List getChildren() { return children; } public void childrenAccept(PatternVisitor visitor) { for (Pattern p : children) p.accept(visitor); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Container.java000066400000000000000000000002131225366607500323660ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import java.util.List; public interface Container { public List getComponents(); } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/DataPattern.java000066400000000000000000000017251225366607500326640ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import java.util.Vector; import java.util.List; public class DataPattern extends Pattern { private String datatypeLibrary; private String type; private final List params = new Vector(); private Pattern except; public DataPattern(String datatypeLibrary, String type) { this.datatypeLibrary = datatypeLibrary; this.type = type; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getDatatypeLibrary() { return datatypeLibrary; } public void setDatatypeLibrary(String datatypeLibrary) { this.datatypeLibrary = datatypeLibrary; } public List getParams() { return params; } public Pattern getExcept() { return except; } public void setExcept(Pattern except) { this.except = except; } public T accept(PatternVisitor visitor) { return visitor.visitData(this); } } DefineComponent.java000066400000000000000000000014251225366607500334500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class DefineComponent extends Component { public final static String START = new String("#start"); private String name; private Pattern body; private Combine combine; public DefineComponent(String name, Pattern body) { this.name = name; this.body = body; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Pattern getBody() { return body; } public void setBody(Pattern body) { this.body = body; } public Combine getCombine() { return combine; } public void setCombine(Combine combine) { this.combine = combine; } public T accept(ComponentVisitor visitor) { return visitor.visitDefine(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/DivComponent.java000066400000000000000000000010111225366607500330460ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import java.util.List; import java.util.Vector; public class DivComponent extends Component implements Container { private final List components = new Vector(); public List getComponents() { return components; } public T accept(ComponentVisitor visitor) { return visitor.visitDiv(this); } public void componentsAccept(ComponentVisitor visitor) { for (Component c : components) c.accept(visitor); } } ElementAnnotation.java000066400000000000000000000032521225366607500340170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.List; import java.util.Vector; public class ElementAnnotation extends AnnotationChild { private String namespaceUri; private String localName; private String prefix; private NamespaceContext context; private final List attributes = new Vector(); private final List children = new Vector(); public ElementAnnotation(String namespaceUri, String localName) { this.namespaceUri = namespaceUri; this.localName = localName; } public List getAttributes() { return attributes; } public List getChildren() { return children; } public String getNamespaceUri() { return namespaceUri; } public void setNamespaceUri(String namespaceUri) { this.namespaceUri = namespaceUri; } public String getLocalName() { return localName; } public void setLocalName(String localName) { this.localName = localName; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public NamespaceContext getContext() { return context; } public void setContext(NamespaceContext context) { this.context = context; } public T accept(AnnotationChildVisitor visitor) { return visitor.visitElement(this); } public void attributesAccept(AttributeAnnotationVisitor visitor) { for (AttributeAnnotation a : attributes) a.accept(visitor); } public void childrenAccept(AnnotationChildVisitor visitor) { for (AnnotationChild c : children) c.accept(visitor); } } ElementPattern.java000066400000000000000000000004431225366607500333210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class ElementPattern extends NameClassedPattern { public ElementPattern(NameClass nameClass, Pattern child) { super(nameClass, child); } public T accept(PatternVisitor visitor) { return visitor.visitElement(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/EmptyPattern.java000066400000000000000000000003231225366607500331020ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class EmptyPattern extends Pattern { public EmptyPattern() { } public T accept(PatternVisitor visitor) { return visitor.visitEmpty(this); } } ExternalRefPattern.java000066400000000000000000000014501225366607500341460ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class ExternalRefPattern extends Pattern { private String uri; private String ns; private String href; private String baseUri; public ExternalRefPattern(String uri) { this.uri = uri; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public String getNs() { return ns; } public void setNs(String ns) { this.ns = ns; } public String getHref() { return href; } public void setHref(String href) { this.href = href; } public String getBaseUri() { return baseUri; } public void setBaseUri(String baseUri) { this.baseUri = baseUri; } public T accept(PatternVisitor visitor) { return visitor.visitExternalRef(this); } } GrammarPattern.java000066400000000000000000000010131225366607500333100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.List; import java.util.Vector; public class GrammarPattern extends Pattern implements Container { private final List components = new Vector(); public List getComponents() { return components; } public T accept(PatternVisitor visitor) { return visitor.visitGrammar(this); } public void componentsAccept(ComponentVisitor visitor) { for (Component c : components) c.accept(visitor); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/GroupPattern.java000066400000000000000000000002751225366607500331060ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class GroupPattern extends CompositePattern { public T accept(PatternVisitor visitor) { return visitor.visitGroup(this); } } IncludeComponent.java000066400000000000000000000023621225366607500336420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.List; import java.util.Vector; public class IncludeComponent extends Component implements Container { // the actual URI used private String uri; private String ns; // the specified href private String href; // the base for resolving the baseUri private String baseUri; private final List components = new Vector(); public IncludeComponent() { } public IncludeComponent(String uri) { this.uri = uri; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public List getComponents() { return components; } public String getNs() { return ns; } public void setNs(String ns) { this.ns = ns; } public String getHref() { return href; } public void setHref(String href) { this.href = href; } public String getBaseUri() { return baseUri; } public void setBaseUri(String baseUri) { this.baseUri = baseUri; } public T accept(ComponentVisitor visitor) { return visitor.visitInclude(this); } public void componentsAccept(ComponentVisitor visitor) { for (Component c : components) c.accept(visitor); } } InterleavePattern.java000066400000000000000000000003071225366607500340250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class InterleavePattern extends CompositePattern { public T accept(PatternVisitor visitor) { return visitor.visitInterleave(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/ListPattern.java000066400000000000000000000003641225366607500327240ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class ListPattern extends UnaryPattern { public ListPattern(Pattern child) { super(child); } public T accept(PatternVisitor visitor) { return visitor.visitList(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/MixedPattern.java000066400000000000000000000003671225366607500330620ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class MixedPattern extends UnaryPattern { public MixedPattern(Pattern child) { super(child); } public T accept(PatternVisitor visitor) { return visitor.visitMixed(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/NameClass.java000066400000000000000000000004311225366607500323140ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import com.thaiopensource.relaxng.parse.SchemaBuilder; public abstract class NameClass extends Annotated { public static final String INHERIT_NS = SchemaBuilder.INHERIT_NS; public abstract T accept(NameClassVisitor visitor); } NameClassVisitor.java000066400000000000000000000003451225366607500336210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public interface NameClassVisitor { T visitChoice(ChoiceNameClass nc); T visitAnyName(AnyNameNameClass nc); T visitNsName(NsNameNameClass nc); T visitName(NameNameClass nc); } NameClassedPattern.java000066400000000000000000000006321225366607500341070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public abstract class NameClassedPattern extends UnaryPattern { private NameClass nameClass; public NameClassedPattern(NameClass nameClass, Pattern child) { super(child); this.nameClass = nameClass; } public NameClass getNameClass() { return nameClass; } public void setNameClass(NameClass nameClass) { this.nameClass = nameClass; } } NameNameClass.java000066400000000000000000000020341225366607500330370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class NameNameClass extends NameClass { private String namespaceUri; private String localName; private String prefix; public NameNameClass(String namespaceUri, String localName) { this.namespaceUri = namespaceUri; this.localName = localName; } public String getNamespaceUri() { return namespaceUri; } public void setNamespaceUri(String namespaceUri) { this.namespaceUri = namespaceUri; } public String getLocalName() { return localName; } public void setLocalName(String localName) { this.localName = localName; } /** * Returns non-empty string or null if there was no prefix. */ public String getPrefix() { return prefix; } /** * prefix must be non-empty string or null if there is no prefix. */ public void setPrefix(String prefix) { this.prefix = prefix; } public boolean mayContainText() { return true; } public T accept(NameClassVisitor visitor) { return visitor.visitName(this); } } NamespaceContext.java000066400000000000000000000002521225366607500336310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.Set; public interface NamespaceContext { String getNamespace(String prefix); Set getPrefixes(); } NotAllowedPattern.java000066400000000000000000000003421225366607500337760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class NotAllowedPattern extends Pattern { public NotAllowedPattern() { } public T accept(PatternVisitor visitor) { return visitor.visitNotAllowed(this); } } NsNameNameClass.java000066400000000000000000000007331225366607500333440ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class NsNameNameClass extends OpenNameClass { private String ns; public NsNameNameClass(String ns) { this.ns = ns; } public NsNameNameClass(String ns, NameClass except) { super(except); this.ns = ns; } public String getNs() { return ns; } public void setNs(String ns) { this.ns = ns; } public T accept(NameClassVisitor visitor) { return visitor.visitNsName(this); } } OneOrMorePattern.java000066400000000000000000000004031225366607500335710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class OneOrMorePattern extends UnaryPattern { public OneOrMorePattern(Pattern child) { super(child); } public T accept(PatternVisitor visitor) { return visitor.visitOneOrMore(this); } } OpenNameClass.java000066400000000000000000000005561225366607500330670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public abstract class OpenNameClass extends NameClass { private NameClass except; public OpenNameClass() { } public OpenNameClass(NameClass except) { this.except = except; } public NameClass getExcept() { return except; } public void setExcept(NameClass except) { this.except = except; } } OptionalPattern.java000066400000000000000000000004001225366607500335060ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class OptionalPattern extends UnaryPattern { public OptionalPattern(Pattern child) { super(child); } public T accept(PatternVisitor visitor) { return visitor.visitOptional(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Param.java000066400000000000000000000010051225366607500315040ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class Param extends Annotated { private String name; private String value; public Param(String name, String value) { this.name = name; this.value = value; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public boolean mayContainText() { return true; } } ParentRefPattern.java000066400000000000000000000004061225366607500336150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class ParentRefPattern extends AbstractRefPattern { public ParentRefPattern(String name) { super(name); } public T accept(PatternVisitor visitor) { return visitor.visitParentRef(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/Pattern.java000066400000000000000000000002311225366607500320610ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public abstract class Pattern extends Annotated { public abstract T accept(PatternVisitor visitor); } PatternVisitor.java000066400000000000000000000013711225366607500333700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public interface PatternVisitor { T visitElement(ElementPattern p); T visitAttribute(AttributePattern p); T visitOneOrMore(OneOrMorePattern p); T visitZeroOrMore(ZeroOrMorePattern p); T visitOptional(OptionalPattern p); T visitInterleave(InterleavePattern p); T visitGroup(GroupPattern p); T visitChoice(ChoicePattern p); T visitGrammar(GrammarPattern p); T visitExternalRef(ExternalRefPattern p); T visitRef(RefPattern p); T visitParentRef(ParentRefPattern p); T visitValue(ValuePattern p); T visitData(DataPattern p); T visitMixed(MixedPattern p); T visitList(ListPattern p); T visitText(TextPattern p); T visitEmpty(EmptyPattern p); T visitNotAllowed(NotAllowedPattern p); } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/RefPattern.java000066400000000000000000000003641225366607500325250ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class RefPattern extends AbstractRefPattern { public RefPattern(String name) { super(name); } public T accept(PatternVisitor visitor) { return visitor.visitRef(this); } } SchemaCollection.java000066400000000000000000000010061225366607500336020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; import java.util.Map; import java.util.HashMap; public class SchemaCollection { private final Map schemaDocumentMap = new HashMap(); private String mainUri; public SchemaCollection() { } public String getMainUri() { return mainUri; } public void setMainUri(String mainUri) { this.mainUri = mainUri; } public Map getSchemaDocumentMap() { return schemaDocumentMap; } } SchemaDocument.java000066400000000000000000000011271225366607500332710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class SchemaDocument { private Pattern pattern; private String encoding; public SchemaDocument(Pattern pattern) { this.pattern = pattern; } public SchemaDocument(Pattern pattern, String encoding) { this.pattern = pattern; this.encoding = encoding; } public Pattern getPattern() { return pattern; } public void setPattern(Pattern pattern) { this.pattern = pattern; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } } SourceLocation.java000066400000000000000000000007731225366607500333310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class SourceLocation { private final String uri; private final int lineNumber; private final int columnNumber; public SourceLocation(String uri, int lineNumber, int columnNumber) { this.uri = uri; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } public String getUri() { return uri; } public int getLineNumber() { return lineNumber; } public int getColumnNumber() { return columnNumber; } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/SourceObject.java000066400000000000000000000006641225366607500330450ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class SourceObject { private SourceLocation sourceLocation; public SourceObject() { } public SourceObject(SourceLocation sourceLocation) { this.sourceLocation = sourceLocation; } public SourceLocation getSourceLocation() { return sourceLocation; } public void setSourceLocation(SourceLocation sourceLocation) { this.sourceLocation = sourceLocation; } } TextAnnotation.java000066400000000000000000000006331225366607500333520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class TextAnnotation extends AnnotationChild { private String value; public TextAnnotation(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public T accept(AnnotationChildVisitor visitor) { return visitor.visitText(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/TextPattern.java000066400000000000000000000003201225366607500327250ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public class TextPattern extends Pattern { public TextPattern() { } public T accept(PatternVisitor visitor) { return visitor.visitText(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/UnaryPattern.java000066400000000000000000000004701225366607500331050ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; public abstract class UnaryPattern extends Pattern { private Pattern child; public UnaryPattern(Pattern child) { this.child = child; } public Pattern getChild() { return child; } public void setChild(Pattern child) { this.child = child; } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/ValuePattern.java000066400000000000000000000021211225366607500330560ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import java.util.Map; import java.util.HashMap; public class ValuePattern extends Pattern { private String datatypeLibrary; private String type; private String value; private final Map prefixMap = new HashMap(); public ValuePattern(String datatypeLibrary, String type, String value) { this.datatypeLibrary = datatypeLibrary; this.type = type; this.value = value; } public String getDatatypeLibrary() { return datatypeLibrary; } public void setDatatypeLibrary(String datatypeLibrary) { this.datatypeLibrary = datatypeLibrary; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public boolean mayContainText() { return true; } public Map getPrefixMap() { return prefixMap; } public T accept(PatternVisitor visitor) { return visitor.visitValue(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/edit/VoidVisitor.java000066400000000000000000000164671225366607500327470ustar00rootroot00000000000000package com.thaiopensource.relaxng.edit; import com.thaiopensource.util.VoidValue; public class VoidVisitor implements PatternVisitor, NameClassVisitor, ComponentVisitor, AnnotationChildVisitor, AttributeAnnotationVisitor { public final VoidValue visitElement(ElementPattern p) { voidVisitElement(p); return VoidValue.VOID; } public void voidVisitElement(ElementPattern p) { voidVisitPattern(p); p.getNameClass().accept(this); p.getChild().accept(this); } public void voidVisitPattern(Pattern p) { voidVisitAnnotated(p); } public void voidVisitAnnotated(Annotated p) { p.leadingCommentsAccept(this); p.attributeAnnotationsAccept(this); p.childElementAnnotationsAccept(this); p.followingElementAnnotationsAccept(this); } public final VoidValue visitChoice(ChoiceNameClass nc) { voidVisitChoice(nc); return VoidValue.VOID; } public void voidVisitChoice(ChoiceNameClass nc) { voidVisitNameClass(nc); nc.childrenAccept(this); } public void voidVisitNameClass(NameClass nc) { voidVisitAnnotated(nc); } public final VoidValue visitDiv(DivComponent c) { voidVisitDiv(c); return VoidValue.VOID; } public void voidVisitDiv(DivComponent c) { voidVisitComponent(c); c.componentsAccept(this); } public void voidVisitComponent(Component c) { voidVisitAnnotated(c); } public final VoidValue visitAttribute(AttributePattern p) { voidVisitAttribute(p); return VoidValue.VOID; } public void voidVisitAttribute(AttributePattern p) { voidVisitPattern(p); p.getNameClass().accept(this); p.getChild().accept(this); } public final VoidValue visitAnyName(AnyNameNameClass nc) { voidVisitAnyName(nc); return VoidValue.VOID; } public void voidVisitAnyName(AnyNameNameClass nc) { voidVisitNameClass(nc); NameClass e = nc.getExcept(); if (e != null) e.accept(this); } public final VoidValue visitInclude(IncludeComponent c) { voidVisitInclude(c); return VoidValue.VOID; } public void voidVisitInclude(IncludeComponent c) { voidVisitComponent(c); c.componentsAccept(this); } public final VoidValue visitOneOrMore(OneOrMorePattern p) { voidVisitOneOrMore(p); return VoidValue.VOID; } public void voidVisitOneOrMore(OneOrMorePattern p) { voidVisitPattern(p); p.getChild().accept(this); } public final VoidValue visitNsName(NsNameNameClass nc) { voidVisitNsName(nc); return VoidValue.VOID; } public void voidVisitNsName(NsNameNameClass nc) { voidVisitNameClass(nc); NameClass e = nc.getExcept(); if (e != null) e.accept(this); } public final VoidValue visitDefine(DefineComponent c) { voidVisitDefine(c); return VoidValue.VOID; } public void voidVisitDefine(DefineComponent c) { voidVisitComponent(c); c.getBody().accept(this); } public final VoidValue visitZeroOrMore(ZeroOrMorePattern p) { voidVisitPattern(p); p.getChild().accept(this); return VoidValue.VOID; } public final VoidValue visitName(NameNameClass nc) { voidVisitName(nc); return VoidValue.VOID; } public void voidVisitName(NameNameClass nc) { voidVisitNameClass(nc); } public final VoidValue visitOptional(OptionalPattern p) { voidVisitOptional(p); return VoidValue.VOID; } public void voidVisitOptional(OptionalPattern p) { voidVisitPattern(p); p.getChild().accept(this); } public final VoidValue visitInterleave(InterleavePattern p) { voidVisitInterleave(p); return VoidValue.VOID; } public void voidVisitInterleave(InterleavePattern p) { voidVisitPattern(p); p.childrenAccept(this); } public final VoidValue visitGroup(GroupPattern p) { voidVisitGroup(p); return VoidValue.VOID; } public void voidVisitGroup(GroupPattern p) { voidVisitPattern(p); p.childrenAccept(this); } public final VoidValue visitChoice(ChoicePattern p) { voidVisitChoice(p); return VoidValue.VOID; } public void voidVisitChoice(ChoicePattern p) { voidVisitPattern(p); p.childrenAccept(this); } public final VoidValue visitGrammar(GrammarPattern p) { voidVisitGrammar(p); return VoidValue.VOID; } public void voidVisitGrammar(GrammarPattern p) { voidVisitPattern(p); p.componentsAccept(this); } public final VoidValue visitExternalRef(ExternalRefPattern p) { voidVisitExternalRef(p); return VoidValue.VOID; } public void voidVisitExternalRef(ExternalRefPattern p) { voidVisitPattern(p); } public final VoidValue visitRef(RefPattern p) { voidVisitRef(p); return VoidValue.VOID; } public void voidVisitRef(RefPattern p) { voidVisitPattern(p); } public final VoidValue visitParentRef(ParentRefPattern p) { voidVisitParentRef(p); return VoidValue.VOID; } public void voidVisitParentRef(ParentRefPattern p) { voidVisitPattern(p); } public final VoidValue visitValue(ValuePattern p) { voidVisitValue(p); return VoidValue.VOID; } public void voidVisitValue(ValuePattern p) { voidVisitPattern(p); } public final VoidValue visitData(DataPattern p) { voidVisitData(p); return VoidValue.VOID; } public void voidVisitData(DataPattern p) { voidVisitPattern(p); Pattern e = p.getExcept(); if (e != null) e.accept(this); for (Param param : p.getParams()) voidVisitAnnotated(param); } public final VoidValue visitMixed(MixedPattern p) { voidVisitMixed(p); return VoidValue.VOID; } public void voidVisitMixed(MixedPattern p) { voidVisitPattern(p); p.getChild().accept(this); } public final VoidValue visitList(ListPattern p) { voidVisitList(p); return VoidValue.VOID; } public void voidVisitList(ListPattern p) { voidVisitPattern(p); p.getChild().accept(this); } public final VoidValue visitText(TextPattern p) { voidVisitText(p); return VoidValue.VOID; } public void voidVisitText(TextPattern p) { voidVisitPattern(p); } public final VoidValue visitEmpty(EmptyPattern p) { voidVisitEmpty(p); return VoidValue.VOID; } public void voidVisitEmpty(EmptyPattern p) { voidVisitPattern(p); } public final VoidValue visitNotAllowed(NotAllowedPattern p) { voidVisitNotAllowed(p); return VoidValue.VOID; } public void voidVisitNotAllowed(NotAllowedPattern p) { voidVisitPattern(p); } public final VoidValue visitText(TextAnnotation ta) { voidVisitText(ta); return VoidValue.VOID; } public void voidVisitText(TextAnnotation ta) { voidVisitAnnotationChild(ta); } public final VoidValue visitComment(Comment c) { voidVisitComment(c); return VoidValue.VOID; } public void voidVisitComment(Comment c) { voidVisitAnnotationChild(c); } public final VoidValue visitElement(ElementAnnotation ea) { voidVisitElement(ea); return VoidValue.VOID; } public void voidVisitElement(ElementAnnotation ea) { voidVisitAnnotationChild(ea); ea.attributesAccept(this); ea.childrenAccept(this); } public void voidVisitAnnotationChild(AnnotationChild ac) { } public final VoidValue visitAttribute(AttributeAnnotation a) { voidVisitAttribute(a); return VoidValue.VOID; } public void voidVisitAttribute(AttributeAnnotation a) { } } ZeroOrMorePattern.java000066400000000000000000000004061225366607500337720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/editpackage com.thaiopensource.relaxng.edit; public class ZeroOrMorePattern extends UnaryPattern { public ZeroOrMorePattern(Pattern child) { super(child); } public T accept(PatternVisitor visitor) { return visitor.visitZeroOrMore(this); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/000077500000000000000000000000001225366607500300175ustar00rootroot00000000000000AbstractMultiInputFormat.java000066400000000000000000000012501225366607500355500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/inputpackage com.thaiopensource.relaxng.input; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.resolver.Resolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; abstract public class AbstractMultiInputFormat implements MultiInputFormat { public SchemaCollection load(String uri, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InputFailedException, InvalidParamsException, IOException, SAXException { return load(new String[] { uri }, params, outputFormat, eh, resolver); } } CommentTrimmer.java000066400000000000000000000051731225366607500335530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/inputpackage com.thaiopensource.relaxng.input; public class CommentTrimmer { private CommentTrimmer() { } public static String trimComment(String value) { return trim(unindent(value)); } private static String trim(String value) { int len = value.length(); loop1: for (; len > 0; --len) { switch (value.charAt(len - 1)) { case ' ': case '\t': break; case '\n': --len; break loop1; default: break loop1; } } int start = 0; loop2: for (; start < len; start++) { switch (value.charAt(start)) { case ' ': case '\t': break; case '\n': ++start; break loop2; default: break loop2; } } if (start < 0 || len < value.length()) return value.substring(start, len); return value; } private static String unindent(String value) { int minIndent = -1; boolean usedTabs = false; for (int i = value.indexOf('\n'), len = value.length(); i >= 0; i = value.indexOf('\n', i)) { ++i; int currentIndent = 0; loop: for (; i < len; i++) { switch (value.charAt(i)) { case '\n': currentIndent = 0; break; case ' ': ++currentIndent; break; case '\t': currentIndent = ((currentIndent/8) + 1)*8; usedTabs = true; break; default: break loop; } } if (i >= len) break; if (currentIndent < minIndent || minIndent < 0) minIndent = currentIndent; } if (minIndent < 0) return value; StringBuffer buf = new StringBuffer(); int currentIndent = -1; for (int i = 0, len = value.length(); i < len; i++) { char c = value.charAt(i); switch (c) { case ' ': if (currentIndent >= 0) currentIndent++; else buf.append(c); break; case '\t': if (currentIndent >= 0) currentIndent = ((currentIndent/8) + 1)*8; else buf.append(c); break; case '\n': buf.append(c); currentIndent = 0; break; default: if (currentIndent > minIndent) { currentIndent -= minIndent; if (usedTabs) { while (currentIndent >= 8) { buf.append('\t'); currentIndent -= 8; } } while (currentIndent > 0) { buf.append(' '); currentIndent--; } } currentIndent = -1; buf.append(c); break; } } return buf.toString(); } }InputFailedException.java000066400000000000000000000001431225366607500346640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/inputpackage com.thaiopensource.relaxng.input; public class InputFailedException extends Exception { } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/InputFormat.java000066400000000000000000000010431225366607500331300ustar00rootroot00000000000000package com.thaiopensource.relaxng.input; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.resolver.Resolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public interface InputFormat { SchemaCollection load(String uri, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InputFailedException, InvalidParamsException, IOException, SAXException; } MultiInputFormat.java000066400000000000000000000010771225366607500340730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/inputpackage com.thaiopensource.relaxng.input; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.resolver.Resolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public interface MultiInputFormat extends InputFormat { SchemaCollection load(String[] uris, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InputFailedException, InvalidParamsException, IOException, SAXException; } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/000077500000000000000000000000001225366607500311315ustar00rootroot00000000000000AnnotationsImpl.java000066400000000000000000000042251225366607500350370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.Context; import com.thaiopensource.relaxng.parse.BuildException; import java.util.List; import java.util.Vector; /** * */ public class AnnotationsImpl implements Annotations { private CommentListImpl comments; private final List attributes = new Vector(); private final List elements = new Vector(); private final Context context; AnnotationsImpl(CommentListImpl comments, Context context) { this.comments = comments; this.context = context; } public void addAttribute(String ns, String localName, String prefix, String value, SourceLocation loc) throws BuildException { AttributeAnnotation att = new AttributeAnnotation(ns, localName, value); att.setPrefix(prefix); att.setSourceLocation(loc); attributes.add(att); } public void addElement(ElementAnnotationBuilderImpl ea) throws BuildException { ea.addTo(elements); } public void addComment(CommentListImpl comments) throws BuildException { if (comments != null) elements.addAll(comments.list); } public void addLeadingComment(CommentListImpl comments) throws BuildException { if (this.comments == null) this.comments = comments; else if (comments != null) this.comments.add(comments); } void apply(Annotated subject) { subject.setContext(new NamespaceContextImpl(context)); if (comments != null) subject.getLeadingComments().addAll(comments.list); subject.getAttributeAnnotations().addAll(attributes); List list; if (subject.mayContainText()) list = subject.getFollowingElementAnnotations(); else list = subject.getChildElementAnnotations(); list.addAll(elements); } } CommentListImpl.java000066400000000000000000000012721225366607500347770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.BuildException; import java.util.List; import java.util.Vector; public class CommentListImpl implements CommentList { final List list = new Vector(); public void addComment(String value, SourceLocation loc) throws BuildException { Comment comment = new Comment(value); comment.setSourceLocation(loc); list.add(comment); } void add(CommentListImpl comments) { list.addAll(comments.list); } } ElementAnnotationBuilderImpl.java000066400000000000000000000042661225366607500375020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.TextAnnotation; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; import com.thaiopensource.relaxng.parse.BuildException; import java.util.List; public class ElementAnnotationBuilderImpl implements ElementAnnotationBuilder { private final ElementAnnotation element; private CommentListImpl comments; ElementAnnotationBuilderImpl(CommentListImpl comments, ElementAnnotation element) { this.comments = comments; this.element = element; } public void addText(String value, SourceLocation loc, CommentListImpl comments) throws BuildException { TextAnnotation t = new TextAnnotation(value); t.setSourceLocation(loc); if (comments != null) element.getChildren().addAll(comments.list); element.getChildren().add(t); } public void addAttribute(String ns, String localName, String prefix, String value, SourceLocation loc) throws BuildException { AttributeAnnotation att = new AttributeAnnotation(ns, localName, value); att.setPrefix(prefix); att.setSourceLocation(loc); element.getAttributes().add(att); } public ElementAnnotationBuilderImpl makeElementAnnotation() throws BuildException { return this; } public void addElement(ElementAnnotationBuilderImpl ea) throws BuildException { ea.addTo(element.getChildren()); } public void addComment(CommentListImpl comments) throws BuildException { if (comments != null) element.getChildren().addAll(comments.list); } public void addLeadingComment(CommentListImpl comments) throws BuildException { if (this.comments == null) this.comments = comments; else if (comments != null) this.comments.add(comments); } void addTo(List elementList) { if (comments != null) elementList.addAll(comments.list); elementList.add(element); } } NamespaceContextImpl.java000066400000000000000000000012771225366607500360070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.relaxng.edit.NamespaceContext; import com.thaiopensource.relaxng.parse.Context; import java.util.Collections; import java.util.Set; class NamespaceContextImpl implements NamespaceContext { private final Context context; private Set cachedPrefixes = null; NamespaceContextImpl(Context context) { this.context = context.copy(); } public String getNamespace(String prefix) { return context.resolveNamespacePrefix(prefix); } public Set getPrefixes() { if (cachedPrefixes == null) cachedPrefixes = Collections.unmodifiableSet(context.prefixes()); return cachedPrefixes; } } ParseInputFormat.java000066400000000000000000000047171225366607500351710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.input.InputFailedException; import com.thaiopensource.relaxng.input.InputFormat; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.translate.util.EncodingParam; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import com.thaiopensource.relaxng.translate.util.ParamProcessor; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; public abstract class ParseInputFormat implements InputFormat { private final boolean commentsNeedTrimming; protected ParseInputFormat(boolean commentsNeedTrimming) { this.commentsNeedTrimming = commentsNeedTrimming; } public SchemaCollection load(String uri, String[] params, String outputFormat, ErrorHandler eh, Resolver resolver) throws InputFailedException, InvalidParamsException, IOException, SAXException { final InputSource in = new InputSource(uri); ParamProcessor pp = new ParamProcessor(); pp.declare("encoding", new EncodingParam() { protected void setEncoding(String encoding) { in.setEncoding(encoding); } }); pp.process(params, eh); Parseable parseable = makeParseable(in, new SAXResolver(resolver), eh); try { return SchemaBuilderImpl.parse(parseable, uri, eh, new DatatypeLibraryLoader(), commentsNeedTrimming); } catch (IllegalSchemaException e) { throw new InputFailedException(); } } protected abstract Parseable makeParseable(InputSource in, SAXResolver resolver, ErrorHandler eh) throws SAXException; } SchemaBuilderImpl.java000066400000000000000000000622471225366607500352610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parsepackage com.thaiopensource.relaxng.input.parse; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Combine; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.ParentRefPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.input.CommentTrimmer; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import com.thaiopensource.relaxng.parse.Context; import com.thaiopensource.relaxng.parse.DataPatternBuilder; import com.thaiopensource.relaxng.parse.Div; import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; import com.thaiopensource.relaxng.parse.Grammar; import com.thaiopensource.relaxng.parse.GrammarSection; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Include; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.relaxng.parse.SubParseable; import com.thaiopensource.relaxng.parse.SubParser; import com.thaiopensource.util.Localizer; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeBuilder; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.DatatypeLibraryFactory; import org.relaxng.datatype.ValidationContext; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.IOException; import java.util.List; import java.util.Map; class SchemaBuilderImpl implements SchemaBuilder { private final SubParser subParser; private final ErrorHandler eh; private final Map schemas; private final DatatypeLibraryFactory dlf; private final boolean commentsNeedTrimming; private boolean hadError = false; static private final Localizer localizer = new Localizer(SchemaBuilderImpl.class); private SchemaBuilderImpl(SubParser subParser, ErrorHandler eh, Map schemas, DatatypeLibraryFactory dlf, boolean commentsNeedTrimming) { this.subParser = subParser; this.eh = eh; this.schemas = schemas; this.dlf = dlf; this.commentsNeedTrimming = commentsNeedTrimming; } public Pattern makeChoice(List patterns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return makeComposite(new ChoicePattern(), patterns, loc, anno); } private static Pattern makeComposite(CompositePattern p, List patterns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { p.getChildren().addAll(patterns); return finishPattern(p, loc, anno); } public Pattern makeGroup(List patterns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return makeComposite(new GroupPattern(), patterns, loc, anno); } public Pattern makeInterleave(List patterns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return makeComposite(new InterleavePattern(), patterns, loc, anno); } public Pattern makeOneOrMore(Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new OneOrMorePattern(p), loc, anno); } public Pattern makeZeroOrMore(Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new ZeroOrMorePattern(p), loc, anno); } public Pattern makeOptional(Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new OptionalPattern(p), loc, anno); } public Pattern makeList(Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new ListPattern(p), loc, anno); } public Pattern makeMixed(Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new MixedPattern(p), loc, anno); } public Pattern makeEmpty(SourceLocation loc, AnnotationsImpl anno) { return finishPattern(new EmptyPattern(), loc, anno); } public Pattern makeNotAllowed(SourceLocation loc, AnnotationsImpl anno) { return finishPattern(new NotAllowedPattern(), loc, anno); } public Pattern makeText(SourceLocation loc, AnnotationsImpl anno) { return finishPattern(new TextPattern(), loc, anno); } public Pattern makeAttribute(NameClass nc, Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new AttributePattern(nc, p), loc, anno); } public Pattern makeElement(NameClass nc, Pattern p, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new ElementPattern(nc, p), loc, anno); } private static class TraceValidationContext implements ValidationContext { private final Map map; private final ValidationContext vc; private final String ns; TraceValidationContext(Map map, ValidationContext vc, String ns) { this.map = map; this.vc = vc; this.ns = ns.length() == 0 ? null : ns; } public String resolveNamespacePrefix(String prefix) { String result; if (prefix.length() == 0) result = ns; else { result = vc.resolveNamespacePrefix(prefix); if (result == SchemaBuilder.INHERIT_NS) return null; } if (result != null) map.put(prefix, result); return result; } public String getBaseUri() { return vc.getBaseUri(); } public boolean isUnparsedEntity(String entityName) { return vc.isUnparsedEntity(entityName); } public boolean isNotation(String notationName) { return vc.isNotation(notationName); } } public Pattern makeValue(String datatypeLibrary, String type, String value, Context context, String ns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { ValuePattern p = new ValuePattern(datatypeLibrary, type, value); DatatypeLibrary dl = dlf.createDatatypeLibrary(datatypeLibrary); if (dl != null) { try { DatatypeBuilder dtb = dl.createDatatypeBuilder(type); try { Datatype dt = dtb.createDatatype(); try { ValidationContext vc = dt.isContextDependent() ? new TraceValidationContext(p.getPrefixMap(), context, ns) : null; // use createValue rather than isValid so that default namespace gets used with QName if (dt.createValue(value, vc) == null) dt.checkValid(value, vc); } catch (DatatypeException e) { diagnoseDatatypeException("invalid_value_detail", "invalid_value", e, loc); } } catch (DatatypeException e) { diagnoseDatatypeException("invalid_params_detail", "invalid_params", e, loc); } } catch (DatatypeException e) { diagnoseDatatypeException("unsupported_datatype_detail", "unknown_datatype", e, loc); } } return finishPattern(p, loc, anno); } public Pattern makeExternalRef(String href, String base, String ns, Scope scope, SourceLocation loc, AnnotationsImpl anno) throws BuildException, IllegalSchemaException { SubParseable subParseable = subParser.createSubParseable(href, base); String uri = subParseable.getUri(); ExternalRefPattern erp = new ExternalRefPattern(uri); erp.setNs(mapInheritNs(ns)); erp.setHref(href); erp.setBaseUri(base); finishPattern(erp, loc, anno); if (schemas.get(uri) == null) { schemas.put(uri, new SchemaDocument(null)); // avoid possibility of infinite loop schemas.put(uri, new SchemaDocument(subParseable.parse(this, scope))); } return erp; } static private Pattern finishPattern(Pattern p, SourceLocation loc, AnnotationsImpl anno) { finishAnnotated(p, loc, anno); return p; } public NameClass makeNameClassChoice(List nameClasses, SourceLocation loc, AnnotationsImpl anno) { ChoiceNameClass nc = new ChoiceNameClass(); nc.getChildren().addAll(nameClasses); return finishNameClass(nc, loc, anno); } public NameClass makeName(String ns, String localName, String prefix, SourceLocation loc, AnnotationsImpl anno) { NameNameClass nc = new NameNameClass(mapInheritNs(ns), localName); nc.setPrefix(prefix); return finishNameClass(nc, loc, anno); } public NameClass makeNsName(String ns, SourceLocation loc, AnnotationsImpl anno) { return finishNameClass(new NsNameNameClass(mapInheritNs(ns)), loc, anno); } public NameClass makeNsName(String ns, NameClass except, SourceLocation loc, AnnotationsImpl anno) { return finishNameClass(new NsNameNameClass(mapInheritNs(ns), except), loc, anno); } public NameClass makeAnyName(SourceLocation loc, AnnotationsImpl anno) { return finishNameClass(new AnyNameNameClass(), loc, anno); } public NameClass makeAnyName(NameClass except, SourceLocation loc, AnnotationsImpl anno) { return finishNameClass(new AnyNameNameClass(except), loc, anno); } private static class ScopeImpl implements Scope { public Pattern makeRef(String name, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new RefPattern(name), loc, anno); } public Pattern makeParentRef(String name, SourceLocation loc, AnnotationsImpl anno) throws BuildException { return finishPattern(new ParentRefPattern(name), loc, anno); } } private class GrammarSectionImpl extends ScopeImpl implements Grammar, Div, Include, IncludedGrammar { private final Annotated subject; private final List components; Component lastComponent; private GrammarSectionImpl(Annotated subject, Container container) { this.subject = subject; this.components = container.getComponents(); } public void define(String name, GrammarSection.Combine combine, Pattern pattern, SourceLocation loc, AnnotationsImpl anno) throws BuildException { if (name == GrammarSection.START) name = DefineComponent.START; DefineComponent dc = new DefineComponent(name, pattern); if (combine != null) dc.setCombine(mapCombine(combine)); finishAnnotated(dc, loc, anno); add(dc); } public Div makeDiv() { DivComponent dc = new DivComponent(); add(dc); return new GrammarSectionImpl(dc, dc); } public Include makeInclude() { IncludeComponent ic = new IncludeComponent(); add(ic); return new GrammarSectionImpl(ic, ic); } public void topLevelAnnotation(ElementAnnotationBuilderImpl ea) throws BuildException { if (lastComponent == null) ea.addTo(subject.getChildElementAnnotations()); else addAfterAnnotation(lastComponent, ea); } public void topLevelComment(CommentListImpl comments) throws BuildException { if (comments != null) { if (lastComponent == null) subject.getChildElementAnnotations().addAll(comments.list); else addAfterComment(lastComponent, comments); } } private void add(Component c) { components.add(c); lastComponent = c; } public void endDiv(SourceLocation loc, AnnotationsImpl anno) throws BuildException { finishAnnotated(subject, loc, anno); } public void endInclude(String href, String base, String ns, SourceLocation loc, AnnotationsImpl anno) throws BuildException, IllegalSchemaException { IncludeComponent ic = (IncludeComponent)subject; SubParseable subParseable = subParser.createSubParseable(href, base); String uri = subParseable.getUri(); ic.setUri(uri); ic.setBaseUri(base); ic.setHref(href); ic.setNs(mapInheritNs(ns)); finishAnnotated(ic, loc, anno); if (schemas.get(uri) == null) { schemas.put(uri, new SchemaDocument(null)); // avoid possibility of infinite loop GrammarPattern g = new GrammarPattern(); try { Pattern pattern = subParseable.parseAsInclude(SchemaBuilderImpl.this, new GrammarSectionImpl(g, g)); schemas.put(uri, new SchemaDocument(pattern)); } catch (IllegalSchemaException e) { schemas.remove(uri); hadError = true; throw e; } } } public Pattern endGrammar(SourceLocation loc, AnnotationsImpl anno) throws BuildException { finishAnnotated(subject, loc, anno); return (Pattern)subject; } public Pattern endIncludedGrammar(SourceLocation loc, AnnotationsImpl anno) throws BuildException { finishAnnotated(subject, loc, anno); return (Pattern)subject; } } public Grammar makeGrammar(Scope parent) { GrammarPattern g = new GrammarPattern(); return new GrammarSectionImpl(g, g); } private static NameClass finishNameClass(NameClass nc, SourceLocation loc, AnnotationsImpl anno) { finishAnnotated(nc, loc, anno); return nc; } private static void finishAnnotated(Annotated a, SourceLocation loc, AnnotationsImpl anno) { a.setSourceLocation(loc); if (anno != null) anno.apply(a); } public NameClass annotateNameClass(NameClass nc, AnnotationsImpl anno) throws BuildException { if (anno != null) anno.apply(nc); return nc; } public Pattern annotatePattern(Pattern p, AnnotationsImpl anno) throws BuildException { if (anno != null) anno.apply(p); return p; } public Pattern annotateAfterPattern(Pattern p, ElementAnnotationBuilderImpl e) throws BuildException { addAfterAnnotation(p, e); return p; } public NameClass annotateAfterNameClass(NameClass nc, ElementAnnotationBuilderImpl e) throws BuildException { addAfterAnnotation(nc, e); return nc; } static private void addAfterAnnotation(Annotated a, ElementAnnotationBuilderImpl e) { e.addTo(a.getFollowingElementAnnotations()); } public Pattern commentAfterPattern(Pattern p, CommentListImpl comments) throws BuildException { addAfterComment(p, comments); return p; } public NameClass commentAfterNameClass(NameClass nc, CommentListImpl comments) throws BuildException { addAfterComment(nc, comments); return nc; } static private void addAfterComment(Annotated a, CommentList comments) { if (comments != null) a.getFollowingElementAnnotations().addAll(((CommentListImpl)comments).list); } public SourceLocation makeLocation(String systemId, int lineNumber, int columnNumber) { return new SourceLocation(systemId, lineNumber, columnNumber); } static class TrimmingCommentListImpl extends CommentListImpl { public void addComment(String value, SourceLocation loc) throws BuildException { super.addComment(CommentTrimmer.trimComment(value), loc); } } public CommentListImpl makeCommentList() { if (commentsNeedTrimming) return new TrimmingCommentListImpl(); else return new CommentListImpl(); } private class DataPatternBuilderImpl implements DataPatternBuilder { private final DataPattern p; private DatatypeBuilder dtb = null; DataPatternBuilderImpl(DataPattern p) throws BuildException { this.p = p; DatatypeLibrary dl = dlf.createDatatypeLibrary(p.getDatatypeLibrary()); if (dl != null) { try { dtb = dl.createDatatypeBuilder(p.getType()); } catch (DatatypeException e) { String datatypeLibrary = p.getDatatypeLibrary(); String type = p.getType(); SourceLocation loc = p.getSourceLocation(); String detail = e.getMessage(); if (detail != null) error("unsupported_datatype_detail", datatypeLibrary, type, detail, loc); else error("unknown_datatype", datatypeLibrary, type, loc); } } } public void addParam(String name, String value, Context context, String ns, SourceLocation loc, AnnotationsImpl anno) throws BuildException { Param param = new Param(name, value); param.setContext(new NamespaceContextImpl(context)); finishAnnotated(param, loc, anno); p.getParams().add(param); if (dtb != null) { try { dtb.addParameter(name, value, context); } catch (DatatypeException e) { diagnoseDatatypeException("invalid_param_detail", "invalid_param", e, loc); } } } public void annotation(ElementAnnotationBuilderImpl ea) { List params = p.getParams(); ea.addTo(params.isEmpty() ? p.getChildElementAnnotations() : (params.get(params.size() - 1)).getFollowingElementAnnotations()); } public Pattern makePattern(SourceLocation loc, AnnotationsImpl anno) throws BuildException { if (dtb != null) { try { dtb.createDatatype(); } catch (DatatypeException e){ diagnoseDatatypeException("invalid_params_detail", "invalid_params", e, loc); } } return finishPattern(p, loc, anno); } public Pattern makePattern(Pattern except, SourceLocation loc, AnnotationsImpl anno) throws BuildException { p.setExcept(except); return finishPattern(p, loc, anno); } } public DataPatternBuilder makeDataPatternBuilder(String datatypeLibrary, String type, SourceLocation loc) throws BuildException { DataPattern pattern = new DataPattern(datatypeLibrary, type); pattern.setSourceLocation(loc); return new DataPatternBuilderImpl(pattern); } public Pattern makeErrorPattern() { return null; } public NameClass makeErrorNameClass() { return null; } public AnnotationsImpl makeAnnotations(CommentListImpl comments, Context context) { return new AnnotationsImpl(comments, context); } public ElementAnnotationBuilder makeElementAnnotationBuilder(String ns, String localName, String prefix, SourceLocation loc, CommentListImpl comments, Context context) { ElementAnnotation element = new ElementAnnotation(ns, localName); element.setPrefix(prefix); element.setSourceLocation(loc); element.setContext(new NamespaceContextImpl(context)); return new ElementAnnotationBuilderImpl(comments, element); } public boolean usesComments() { return true; } private static Combine mapCombine(GrammarSection.Combine combine) { if (combine == null) return null; return combine == GrammarSection.COMBINE_CHOICE ? Combine.CHOICE : Combine.INTERLEAVE; } private static String mapInheritNs(String ns) { // noop since we represent INHERIT_NS by the same object return ns; } private void parse(Parseable parseable, String uri) throws IllegalSchemaException { schemas.put(uri, new SchemaDocument(parseable.parse(this, new ScopeImpl()))); } static SchemaCollection parse(Parseable parseable, String uri, ErrorHandler eh, DatatypeLibraryFactory dlf, boolean commentsNeedTrimming) throws IllegalSchemaException, IOException, SAXException { try { SchemaCollection sc = new SchemaCollection(); SchemaBuilderImpl sb = new SchemaBuilderImpl(parseable, eh, sc.getSchemaDocumentMap(), dlf, commentsNeedTrimming); sc.setMainUri(uri); sb.parse(parseable, uri); if (sb.hadError) throw new IllegalSchemaException(); return sc; } catch (BuildException e) { Throwable t = e.getCause(); if (t instanceof IOException) throw (IOException)t; if (t instanceof RuntimeException) throw (RuntimeException)t; if (t instanceof SAXException) throw (SAXException)t; if (t instanceof Exception) throw new SAXException((Exception)t); throw new SAXException(t.getClass().getName() + " thrown"); } } private void error(SAXParseException message) throws BuildException { hadError = true; try { if (eh != null) eh.error(message); } catch (SAXException e) { throw new BuildException(e); } } private void diagnoseDatatypeException(String detailKey, String noDetailKey, DatatypeException e, SourceLocation loc) throws BuildException { String detail = e.getMessage(); if (detail != null) error(detailKey, detail, loc); else error(noDetailKey, loc); } static private Locator makeLocator(final SourceLocation loc) { return new Locator() { public String getPublicId() { return null; } public int getColumnNumber() { if (loc == null) return -1; return loc.getColumnNumber(); } public String getSystemId() { if (loc == null) return null; return loc.getUri(); } public int getLineNumber() { if (loc == null) return -1; return loc.getLineNumber(); } }; } private void error(String key, SourceLocation loc) throws BuildException { error(new SAXParseException(localizer.message(key), makeLocator(loc))); } private void error(String key, String arg, SourceLocation loc) throws BuildException { error(new SAXParseException(localizer.message(key, arg), makeLocator(loc))); } private void error(String key, String arg1, String arg2, SourceLocation loc) throws BuildException { error(new SAXParseException(localizer.message(key, arg1, arg2), makeLocator(loc))); } private void error(String key, String arg1, String arg2, String arg3, SourceLocation loc) throws BuildException { error(new SAXParseException(localizer.message(key, new Object[]{arg1, arg2, arg3}), makeLocator(loc))); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/compact/000077500000000000000000000000001225366607500325575ustar00rootroot00000000000000CompactParseInputFormat.java000066400000000000000000000024111225366607500401130ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/compactpackage com.thaiopensource.relaxng.input.parse.compact; import com.thaiopensource.relaxng.input.parse.ParseInputFormat; import com.thaiopensource.relaxng.input.parse.ElementAnnotationBuilderImpl; import com.thaiopensource.relaxng.input.parse.CommentListImpl; import com.thaiopensource.relaxng.input.parse.AnnotationsImpl; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.compact.CompactParseable; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; public class CompactParseInputFormat extends ParseInputFormat { public CompactParseInputFormat() { super(false); } public Parseable makeParseable(InputSource inputSource, SAXResolver saxResolver, ErrorHandler eh) { return new CompactParseable(SAX.createInput(inputSource), saxResolver.getResolver(), eh); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/resources/000077500000000000000000000000001225366607500331435ustar00rootroot00000000000000Messages.properties000066400000000000000000000006411225366607500367520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/resourcesunknown_datatype=datatype library \"{0}\" does not have a datatype \"{1}\" unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters invalid_value_detail=datatype does not permit value: {0} invalid_value=datatype does not permit valuejing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/sax/000077500000000000000000000000001225366607500317245ustar00rootroot00000000000000SAXParseInputFormat.java000066400000000000000000000024241225366607500363310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/input/parse/saxpackage com.thaiopensource.relaxng.input.parse.sax; import com.thaiopensource.relaxng.input.parse.ParseInputFormat; import com.thaiopensource.relaxng.input.parse.ElementAnnotationBuilderImpl; import com.thaiopensource.relaxng.input.parse.CommentListImpl; import com.thaiopensource.relaxng.input.parse.AnnotationsImpl; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.sax.SAXParseable; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.transform.sax.SAXSource; public class SAXParseInputFormat extends ParseInputFormat { public SAXParseInputFormat() { super(true); } public Parseable makeParseable(InputSource in, SAXResolver resolver, ErrorHandler eh) throws SAXException { return new SAXParseable(new SAXSource(resolver.createXMLReader(), in), resolver, eh); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/000077500000000000000000000000001225366607500302205ustar00rootroot00000000000000LocalOutputDirectory.java000066400000000000000000000062421225366607500351500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/outputpackage com.thaiopensource.relaxng.output; import com.thaiopensource.xml.util.EncodingMap; import com.thaiopensource.xml.out.CharRepertoire; import java.io.IOException; import java.io.File; import java.io.OutputStreamWriter; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.util.Map; import java.util.HashMap; public class LocalOutputDirectory implements OutputDirectory { private final File mainOutputFile; private final String lineSeparator; private final String outputExtension; private String defaultEncoding; private boolean alwaysUseDefaultEncoding; private final int lineLength; // maps URIs to filenames private final Map uriMap = new HashMap(); private final String mainInputExtension; private int indent; public LocalOutputDirectory(String mainSourceUri, File mainOutputFile, String extension, String encoding, int lineLength, int indent) { this.mainOutputFile = mainOutputFile; this.outputExtension = extension; this.defaultEncoding = encoding; this.lineSeparator = System.getProperty("line.separator"); this.lineLength = lineLength; this.indent = indent; this.uriMap.put(mainSourceUri, mainOutputFile.getName()); int slashOff = mainSourceUri.lastIndexOf('/'); int dotOff = mainSourceUri.lastIndexOf('.'); this.mainInputExtension = dotOff > 0 && dotOff > slashOff ? mainSourceUri.substring(dotOff) : ""; } public void setEncoding(String encoding) { defaultEncoding = encoding; alwaysUseDefaultEncoding = true; } public OutputDirectory.Stream open(String sourceUri, String encoding) throws IOException { if (encoding == null || alwaysUseDefaultEncoding) encoding = defaultEncoding; String javaEncoding = EncodingMap.getJavaName(encoding); File file = new File(mainOutputFile.getParentFile(), mapFilename(sourceUri)); return new OutputDirectory.Stream(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), javaEncoding), encoding, CharRepertoire.getInstance(javaEncoding)); } public String reference(String fromSourceUri, String toSourceUri) { return mapFilename(toSourceUri); } private String mapFilename(String sourceUri) { String filename = uriMap.get(sourceUri); if (filename == null) { filename = chooseFilename(sourceUri); uriMap.put(sourceUri, filename); } return filename; } private String chooseFilename(String sourceUri) { String filename = sourceUri.substring(sourceUri.lastIndexOf('/') + 1); String base; if (filename.endsWith(mainInputExtension)) base = filename.substring(0, filename.length() - mainInputExtension.length()); else base = filename; filename = base + outputExtension; for (int i = 1; uriMap.containsValue(filename); i++) filename = base + Integer.toString(i) + outputExtension; return filename; } public String getLineSeparator() { return lineSeparator; } public int getLineLength() { return lineLength; } public int getIndent() { return indent; } public void setIndent(int indent) { this.indent = indent; } } OutputDirectory.java000066400000000000000000000020611225366607500341700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/outputpackage com.thaiopensource.relaxng.output; import com.thaiopensource.xml.out.CharRepertoire; import java.io.Writer; import java.io.IOException; public interface OutputDirectory { static public class Stream { private final Writer writer; private final String encoding; private final CharRepertoire charRepertoire; public Stream(Writer writer, String encoding, CharRepertoire charRepertoire) { this.writer = writer; this.encoding = encoding; this.charRepertoire = charRepertoire; } public Writer getWriter() { return writer; } public String getEncoding() { return encoding; } public CharRepertoire getCharRepertoire() { return charRepertoire; } } Stream open(String sourceUri, String encoding) throws IOException; String reference(String fromSourceUri, String toSourceUri); String getLineSeparator(); int getLineLength(); int getIndent(); void setIndent(int indent); /** * This overrides the encoding specified with open. */ void setEncoding(String encoding); } OutputDirectoryParamProcessor.java000066400000000000000000000017431225366607500370570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/outputpackage com.thaiopensource.relaxng.output; import com.thaiopensource.relaxng.translate.util.ParamProcessor; import com.thaiopensource.relaxng.translate.util.EncodingParam; import com.thaiopensource.relaxng.translate.util.IntegerParam; public class OutputDirectoryParamProcessor extends ParamProcessor { private final OutputDirectory od; private static final int MAX_INDENT = 16; public OutputDirectoryParamProcessor(OutputDirectory od) { this.od = od; super.declare("encoding", new EncodingParam() { protected void setEncoding(String encoding) { OutputDirectoryParamProcessor.this.od.setEncoding(encoding); } }); super.declare("indent", new IntegerParam(0, MAX_INDENT) { protected void setInteger(int value) { OutputDirectoryParamProcessor.this.od.setIndent(value); } }); } } OutputFailedException.java000066400000000000000000000001451225366607500352700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/outputpackage com.thaiopensource.relaxng.output; public class OutputFailedException extends Exception { } OutputFormat.java000066400000000000000000000007701225366607500334610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/outputpackage com.thaiopensource.relaxng.output; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; public interface OutputFormat { void output(SchemaCollection sc, OutputDirectory od, String[] params, String inputFormat, ErrorHandler eh) throws SAXException, IOException, OutputFailedException, InvalidParamsException; } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/common/000077500000000000000000000000001225366607500315105ustar00rootroot00000000000000ErrorReporter.java000066400000000000000000000056761225366607500351260ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/commonpackage com.thaiopensource.relaxng.output.common; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import org.xml.sax.SAXException; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.util.Localizer; public class ErrorReporter { private final Localizer localizer; private final ErrorHandler eh; private boolean hadError = false; static public class WrappedSAXException extends RuntimeException { private final SAXException exception; private WrappedSAXException(SAXException exception) { this.exception = exception; } public SAXException getException() { return exception; } } public ErrorReporter(ErrorHandler eh, Class cls) { this.eh = eh; this.localizer = new Localizer(cls); } public void error(String key, SourceLocation loc) { hadError = true; if (eh == null) return; try { eh.error(makeParseException(localizer.message(key), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void error(String key, String arg, SourceLocation loc) { hadError = true; if (eh == null) return; try { eh.error(makeParseException(localizer.message(key, arg), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void error(String key, String arg1, String arg2, SourceLocation loc) { hadError = true; if (eh == null) return; try { eh.error(makeParseException(localizer.message(key, arg1, arg2), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void warning(String key, SourceLocation loc) { if (eh == null) return; try { eh.warning(makeParseException(localizer.message(key), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void warning(String key, String arg, SourceLocation loc) { if (eh == null) return; try { eh.warning(makeParseException(localizer.message(key, arg), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void warning(String key, String arg1, String arg2, SourceLocation loc) { if (eh == null) return; try { eh.warning(makeParseException(localizer.message(key, arg1, arg2), loc)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public boolean getHadError() { return hadError; } private static SAXParseException makeParseException(String message, SourceLocation loc) { if (loc == null) return new SAXParseException(message, null); return new SAXParseException(message, null, loc.getUri(), loc.getLineNumber(), loc.getColumnNumber()); } public Localizer getLocalizer() { return localizer; } } NameClassSplitter.java000066400000000000000000000036331225366607500356760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/commonpackage com.thaiopensource.relaxng.output.common; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassVisitor; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.util.VoidValue; import java.util.List; import java.util.Vector; public class NameClassSplitter implements NameClassVisitor { private final List names = new Vector(); private boolean negative = false; static public List split(NameClass nc) { NameClassSplitter splitter = new NameClassSplitter(); nc.accept(splitter); return splitter.names; } private NameClassSplitter() { } public VoidValue visitName(NameNameClass nc) { if (!negative) names.add(nc); return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { for (NameClass child : nc.getChildren()) child.accept(this); return VoidValue.VOID; } public VoidValue visitAnyName(AnyNameNameClass nc) { if (!negative) { NameClass except = nc.getExcept(); if (except != null) { negative = true; except.accept(this); negative = false; } } return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { if (negative) { NameClass except = nc.getExcept(); if (except != null) { int startIndex = names.size(); negative = false; except.accept(this); negative = true; for (int i = startIndex, len = names.size(); i < len; i++) { if (!(names.get(i)).getNamespaceUri().equals(nc.getNs())) { names.remove(i); i--; len--; } } } } return VoidValue.VOID; } } XmlWriter.java000066400000000000000000000123111225366607500342270ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/commonpackage com.thaiopensource.relaxng.output.common; import com.thaiopensource.xml.out.CharRepertoire; import com.thaiopensource.util.Utf16; import java.io.Writer; import java.io.IOException; import java.io.CharConversionException; import java.util.Stack; public class XmlWriter { private final String lineSep; private final String indentString; private final Writer w; private final CharRepertoire cr; private final Stack tagStack = new Stack(); private boolean inStartTag = false; private boolean inText = false; private int level = 0; private final String[] topLevelAttributes; public static class WrappedException extends RuntimeException { private final IOException cause; public Throwable getCause() { return cause; } public IOException getIOException() { return cause; } private WrappedException(IOException cause) { this.cause = cause; } } public XmlWriter(Writer w, String encoding, CharRepertoire cr, String lineSep, int indent, String[] topLevelAttributes) { this.w = w; this.lineSep = lineSep; this.cr = cr; this.topLevelAttributes = topLevelAttributes; char[] tem = new char[indent]; for (int i = 0; i < indent; i++) tem[i] = ' '; this.indentString = new String(tem); write(""); newline(); } public void startElement(String name) { if (inStartTag) { maybeWriteTopLevelAttributes(); inStartTag = false; write(">"); newline(); } if (inText) inText = false; else indent(); write('<'); write(name); tagStack.push(name); inStartTag = true; level++; } public void endElement() { if (inStartTag) { maybeWriteTopLevelAttributes(); level--; inStartTag = false; tagStack.pop(); write("/>"); } else { level--; if (inText) inText = false; else indent(); write(""); } newline(); } public void attribute(String name, String value) { if (!inStartTag) throw new IllegalStateException("attribute outside of start-tag"); write(' '); write(name); write('='); write('"'); data(value); write('"'); } public void text(String s) { if (s.length() == 0) return; if (inStartTag) { maybeWriteTopLevelAttributes(); inStartTag = false; write(">"); } data(s); inText = true; } public void comment(String s) { if (inStartTag) { maybeWriteTopLevelAttributes(); inStartTag = false; write(">"); newline(); } if (!inText) indent(); write(""); if (!inText) newline(); } private void data(String s) { int n = s.length(); for (int i = 0; i < n; i++) { char c = s.charAt(i); switch (c) { case '<': write("<"); break; case '>': write(">"); break; case '&': write("&"); break; case '\r': write(" "); break; case '\n': write(lineSep); break; default: if (Utf16.isSurrogate(c)) { if (!Utf16.isSurrogate1(c) || i + 1 == n || !Utf16.isSurrogate2(s.charAt(i + 1))) throw new WrappedException(new CharConversionException("surrogate pair integrity failure")); char c2 = s.charAt(++i); if (cr.contains(c, c2)) { write(c); write(c2); } else charRef(Utf16.scalarValue(c, c2)); } else if (!cr.contains(c)) charRef(c); else write(c); break; } } } private void charRef(int n) { write("&#x"); write(Integer.toHexString(n)); write(';'); } private void indent() { for (int i = 0; i < level; i++) write(indentString); } private void newline() { write(lineSep); } private void maybeWriteTopLevelAttributes() { if (level != 1) return; for (int i = 0; i < topLevelAttributes.length; i += 2) attribute(topLevelAttributes[i], topLevelAttributes[i + 1]); } private void write(String s) { try { w.write(s); } catch (IOException e) { throw new WrappedException(e); } } private void write(char c) { try { w.write(c); } catch (IOException e) { throw new WrappedException(e); } } public void close() { try { w.close(); } catch (IOException e) { throw new WrappedException(e); } } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rnc/000077500000000000000000000000001225366607500310025ustar00rootroot00000000000000ComplexityCache.java000066400000000000000000000062701225366607500346540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rncpackage com.thaiopensource.relaxng.output.rnc; import com.thaiopensource.relaxng.edit.AbstractPatternVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClassedPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import java.util.HashMap; import java.util.Map; class ComplexityCache { private final ComplexityVisitor complexityVisitor = new ComplexityVisitor(); private final Map cache = new HashMap(); static private class Complexity { private int value; private Complexity(int value) { this.value = value; } static private final int MAX_BRACE = 0; static private final int MAX_PAREN = 2; static final Complexity SIMPLE = new Complexity(0); static final Complexity VERY_COMPLICATED = new Complexity(MAX_BRACE + 1); static Complexity max(Complexity c1, Complexity c2) { int n1 = c1.value; int n2 = c2.value; if (n1 > 0) return n1 > n2 ? c1 : c2; if (n2 > 0) return c2; return n1 < n2 ? c1 : c2; } static Complexity brace(Complexity c) { int n = c.value; return new Complexity(n <= 0 ? 1 : n + 1); } static Complexity paren(Complexity c) { int n = c.value; return n > 0 ? c : new Complexity(n - 1); } static boolean isComplex(Complexity c) { int n = c.value; return n > MAX_BRACE || n < -MAX_PAREN; } } private class ComplexityVisitor extends AbstractPatternVisitor { Complexity visit(Pattern p) { Complexity c = cache.get(p); if (c == null) { c = p.accept(this); cache.put(p, c); } return c; } public Complexity visitGrammar(GrammarPattern p) { return Complexity.VERY_COMPLICATED; } public Complexity visitNameClassed(NameClassedPattern p) { return brace(p); } public Complexity visitList(ListPattern p) { return brace(p); } public Complexity visitMixed(MixedPattern p) { return brace(p); } private Complexity brace(UnaryPattern p) { return Complexity.brace(visit(p.getChild())); } public Complexity visitUnary(UnaryPattern p) { return visit(p.getChild()); } public Complexity visitData(DataPattern p) { Complexity ret = Complexity.SIMPLE; if (p.getParams().size() > 0) ret = Complexity.brace(ret); if (p.getExcept() != null) ret = Complexity.max(ret, visit(p.getExcept())); return ret; } public Complexity visitComposite(CompositePattern p) { Complexity ret = Complexity.SIMPLE; for (Pattern child : p.getChildren()) ret = Complexity.max(ret, visit(child)); return Complexity.paren(ret); } public Complexity visitPattern(Pattern p) { return Complexity.SIMPLE; } } public boolean isComplex(Pattern p) { return Complexity.isComplex(complexityVisitor.visit(p)); } } NamespaceManager.java000066400000000000000000000152651225366607500347660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rncpackage com.thaiopensource.relaxng.output.rnc; import com.thaiopensource.xml.util.WellKnownNamespaces; import com.thaiopensource.relaxng.parse.SchemaBuilder; import java.util.List; import java.util.Collections; import java.util.Comparator; import java.util.Set; import java.util.Vector; import java.util.Iterator; import java.util.Map; import java.util.HashMap; class NamespaceManager { static class NamespaceBindings { /** * maps prefixes to namespaces */ private final Map prefixMap; /** * maps namespaces to preferred non-empty prefix */ private final Map nsMap; private NamespaceBindings(Map prefixMap, Map nsMap) { this.prefixMap = prefixMap; this.nsMap = nsMap; } /** * Must return non-empty prefix. * ns may be empty string */ String getNonEmptyPrefix(String ns) { return nsMap.get(ns); } /** * prefix of empty string refers to default namespace * if no binding, return null */ String getNamespaceUri(String prefix) { return prefixMap.get(prefix); } Set getPrefixes() { return prefixMap.keySet(); } } /** * maps a namespaceUri to Boolean; true means empty prefix is OK */ private final Map requiredNamespaces = new HashMap(); static private final String[] conventionalBindings = { // prefix, namespaceUri "", SchemaBuilder.INHERIT_NS, "inherit", SchemaBuilder.INHERIT_NS, "", "", "local", "", "rng", WellKnownNamespaces.RELAX_NG, "a", WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS }; static class Binding { private final String prefix; private final String namespaceUri; Binding(String prefix, String namespaceUri) { this.prefix = prefix; this.namespaceUri = namespaceUri; } String getPrefix() { return prefix; } String getNamespaceUri() { return namespaceUri; } public int hashCode() { return prefix.hashCode() ^ namespaceUri.hashCode(); } public boolean equals(Object obj) { if (!(obj instanceof Binding)) return false; Binding other = (Binding)obj; return (this.prefix.equals(other.prefix) && this.namespaceUri.equals(other.namespaceUri)); } } static class BindingUsage { boolean required; int usageCount; } /** * map Binding to BindingUsage */ private final Map bindingUsageMap = new HashMap(); void requireNamespace(String ns, boolean prefixMaybeEmpty) { Boolean b = requiredNamespaces.get(ns); if (b == null || (b && !prefixMaybeEmpty)) { b = prefixMaybeEmpty ? Boolean.TRUE : Boolean.FALSE; requiredNamespaces.put(ns, b); } } /** * prefix may be empty string */ void requireBinding(String prefix, String ns) { noteBinding(prefix, ns, true); } /** * prefix may be empty string */ void preferBinding(String prefix, String ns) { noteBinding(prefix, ns, false); } private void noteBinding(String prefix, String ns, boolean required) { if (ns.equals(WellKnownNamespaces.XML)) return; Binding b = new Binding(prefix, ns); BindingUsage bu = bindingUsageMap.get(b); if (bu == null) { bu = new BindingUsage(); bindingUsageMap.put(b, bu); } if (required) bu.required = true; bu.usageCount++; } private class BindingComparator implements Comparator { public int compare(Binding b1, Binding b2) { BindingUsage bu1 = bindingUsageMap.get(b1); BindingUsage bu2 = bindingUsageMap.get(b2); // required precedes not required if (bu1.required != bu2.required) return bu1.required ? -1 : 1; // more usage precedes less usage if (bu1.usageCount != bu2.usageCount) return bu2.usageCount - bu1.usageCount; // Make it a total order to avoid depending on order of // iteration over HashSet. // prefer shorter prefix if (b1.prefix.length() != b2.prefix.length()) return b1.prefix.length() - b2.prefix.length(); int ret = b1.prefix.compareTo(b2.prefix); if (ret != 0) return ret; return b1.namespaceUri.compareTo(b2.namespaceUri); } } NamespaceBindings createBindings() { // maps prefix representing a string to a namespaceUri Map prefixMap = new HashMap(); // maps namespace to preferred non-empty prefix Map nsMap = new HashMap(); prefixMap.put("xml", WellKnownNamespaces.XML); nsMap.put(WellKnownNamespaces.XML, "xml"); requiredNamespaces.remove(WellKnownNamespaces.XML); List bindingList = new Vector(); bindingList.addAll(bindingUsageMap.keySet()); Collections.sort(bindingList, new BindingComparator()); for (Iterator iter = bindingList.iterator(); iter.hasNext();) { Binding binding = iter.next(); if (prefixMap.get(binding.prefix) == null) { Boolean defaultOK = requiredNamespaces.get(binding.namespaceUri); boolean satisfiesRequirement = defaultOK != null && (binding.prefix.length() > 0 || defaultOK); if ((bindingUsageMap.get(binding)).required || satisfiesRequirement) { prefixMap.put(binding.prefix, binding.namespaceUri); iter.remove(); if (satisfiesRequirement) requiredNamespaces.remove(binding.namespaceUri); if (binding.prefix.length() > 0) nsMap.put(binding.namespaceUri, binding.prefix); } } } // use any of the bindings that we haven't yet used that don't conflict for (Binding binding : bindingList) { if (prefixMap.get(binding.prefix) == null) { prefixMap.put(binding.prefix, binding.namespaceUri); } } for (int i = 0; i < conventionalBindings.length; i += 2) { String prefix = conventionalBindings[i]; if (prefixMap.get(prefix) == null) { String ns = conventionalBindings[i + 1]; Boolean defaultOK = requiredNamespaces.get(ns); if (defaultOK != null && (prefix.length() > 0 || defaultOK)) { prefixMap.put(prefix, ns); requiredNamespaces.remove(ns); if (prefix.length() > 0) nsMap.put(ns, prefix); } } } Iterator iter = requiredNamespaces.keySet().iterator(); for (int i = 1; iter.hasNext(); i++) { String prefix = "ns" + Integer.toString(i); if (prefixMap.get(prefix) == null) { String ns = iter.next(); prefixMap.put(prefix, ns); nsMap.put(ns, prefix); } } return new NamespaceBindings(prefixMap, nsMap); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rnc/Output.java000066400000000000000000001104651225366607500331540ustar00rootroot00000000000000package com.thaiopensource.relaxng.output.rnc; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.AnnotationChildVisitor; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Combine; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassVisitor; import com.thaiopensource.relaxng.edit.NameClassedPattern; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.ParentRefPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.SourceLocation; import com.thaiopensource.relaxng.edit.TextAnnotation; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.VoidVisitor; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.edit.NamespaceContext; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.util.Utf16; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.out.CharRepertoire; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; class Output { private final Prettyprinter pp; private final CharRepertoire cr; private final String indent; private final String sourceUri; private final OutputDirectory od; private final ErrorReporter er; private final NamespaceManager.NamespaceBindings nsb; private final Map datatypeLibraryMap = new HashMap(); private final ComplexityCache complexityCache = new ComplexityCache(); private final NameClassVisitor nameClassOutput = new NameClassOutput(true); private final NameClassVisitor noParenNameClassOutput = new NameClassOutput(false); private final PatternVisitor noParenPatternOutput = new PatternOutput(false); private final PatternVisitor patternOutput = new PatternOutput(true); private final PatternVisitor repeatedPatternOutput = new RepeatedPatternOutput(); private final ComponentVisitor componentOutput = new ComponentOutput(); private final AnnotationChildVisitor annotationChildOutput = new AnnotationChildOutput(); private final AnnotationChildVisitor followingAnnotationChildOutput = new FollowingAnnotationChildOutput(); private boolean isAttributeNameClass; private final StringBuffer encodeBuf = new StringBuffer(); static private final String[] keywords = { "attribute", "default", "datatypes", "div", "element", "empty", "external", "grammar", "include", "inherit", "list", "mixed", "namespace", "notAllowed", "parent", "start", "string", "text", "token" }; static private final Set keywordSet = new HashSet(); static { for (int i = 0; i < keywords.length; i++) keywordSet.add(keywords[i]); } static void output(Pattern p, String encoding, String sourceUri, OutputDirectory od, ErrorReporter er) throws IOException { try { new Output(sourceUri, encoding, od, er, NamespaceVisitor.createBindings(p)).topLevel(p); } catch (Prettyprinter.WrappedException e) { throw e.getIOException(); } } private Output(String sourceUri, String encoding, OutputDirectory od, ErrorReporter er, NamespaceManager.NamespaceBindings nsb) throws IOException { this.sourceUri = sourceUri; this.od = od; this.er = er; // Only preserve the input encoding if it's one that can be auto-detected. if (encoding != null && !encoding.equalsIgnoreCase("UTF-8") && !encoding.equalsIgnoreCase("UTF-16") && !encoding.equalsIgnoreCase("US-ASCII")) encoding = null; OutputDirectory.Stream stream = od.open(sourceUri, encoding); this.cr = stream.getCharRepertoire(); this.pp = new StreamingPrettyprinter(od.getLineLength(), od.getLineSeparator(), stream.getWriter()); this.nsb = nsb; char[] tem = new char[od.getIndent()]; for (int i = 0; i < tem.length; i++) tem[i] = ' '; this.indent = new String(tem); } private void topLevel(Pattern p) { p.accept(new TextAnnotationMerger()); boolean implicitGrammar = p instanceof GrammarPattern && p.getAttributeAnnotations().isEmpty(); if (implicitGrammar && !p.getLeadingComments().isEmpty()) { leadingComments(p); pp.hardNewline(); } outputNamespaceDeclarations(); outputDatatypeLibraryDeclarations(p); if (implicitGrammar) { for (AnnotationChild annotationChild : p.getChildElementAnnotations()) { annotationChild.accept(annotationChildOutput); pp.hardNewline(); } innerBody(((GrammarPattern)p).getComponents()); // This deals with trailing comments for (AnnotationChild annotationChild : p.getFollowingElementAnnotations()) { pp.hardNewline(); annotationChild.accept(annotationChildOutput); } } else p.accept(patternOutput); // The pretty printer ensures that we have a terminating newline. pp.close(); } private void outputNamespaceDeclarations() { List prefixes = new Vector(); prefixes.addAll(nsb.getPrefixes()); Collections.sort(prefixes); boolean needNewline = false; String defaultPrefix = null; String defaultNamespace = nsb.getNamespaceUri(""); if (defaultNamespace != null && !defaultNamespace.equals(SchemaBuilder.INHERIT_NS)) defaultPrefix = nsb.getNonEmptyPrefix(defaultNamespace); for (String prefix : prefixes) { String ns = nsb.getNamespaceUri(prefix); if (prefix.length() == 0) { if (defaultPrefix == null && !ns.equals(SchemaBuilder.INHERIT_NS)) { pp.startGroup(); pp.text("default namespace ="); pp.startNest(indent); pp.softNewline(" "); literal(ns); pp.endNest(); pp.endGroup(); pp.hardNewline(); needNewline = true; } } else if (!prefix.equals("xml")) { pp.startGroup(); if (prefix.equals(defaultPrefix)) pp.text("default namespace "); else pp.text("namespace "); encodedText(prefix); pp.text(" ="); pp.startNest(indent); pp.softNewline(" "); if (ns.equals(SchemaBuilder.INHERIT_NS)) pp.text("inherit"); else literal(ns); pp.endNest(); pp.endGroup(); pp.hardNewline(); needNewline = true; } } if (needNewline) pp.hardNewline(); } private void outputDatatypeLibraryDeclarations(Pattern p) { datatypeLibraryMap.put(WellKnownNamespaces.XML_SCHEMA_DATATYPES, "xsd"); List datatypeLibraries = new Vector(); datatypeLibraries.addAll(DatatypeLibraryVisitor.findDatatypeLibraries(p)); if (datatypeLibraries.isEmpty()) return; Collections.sort(datatypeLibraries); for (int i = 0, len = datatypeLibraries.size(); i < len; i++) { String prefix = "d"; if (len > 1) prefix += Integer.toString(i + 1); String uri = datatypeLibraries.get(i); datatypeLibraryMap.put(uri, prefix); pp.startGroup(); pp.text("datatypes "); encodedText(prefix); pp.text(" ="); pp.startNest(indent); pp.softNewline(" "); literal(uri); pp.endNest(); pp.endGroup(); pp.hardNewline(); } pp.hardNewline(); } private static class TextAnnotationMerger extends VoidVisitor { public void voidVisitElement(ElementAnnotation ea) { TextAnnotation prevText = null; for (Iterator iter = ea.getChildren().iterator(); iter.hasNext();) { AnnotationChild child = iter.next(); if (child instanceof TextAnnotation) { if (prevText == null) prevText = (TextAnnotation)child; else { prevText.setValue(prevText.getValue() + ((TextAnnotation)child).getValue()); iter.remove(); } } else { prevText = null; child.accept(this); } } } } static class DatatypeLibraryVisitor extends VoidVisitor { private final Set datatypeLibraries = new HashSet(); public void voidVisitValue(ValuePattern p) { noteDatatypeLibrary(p.getDatatypeLibrary()); super.voidVisitValue(p); } public void voidVisitData(DataPattern p) { noteDatatypeLibrary(p.getDatatypeLibrary()); super.voidVisitData(p); } private void noteDatatypeLibrary(String uri) { if (!uri.equals("") && !uri.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES)) datatypeLibraries.add(uri); } static Set findDatatypeLibraries(Pattern p) { DatatypeLibraryVisitor dlv = new DatatypeLibraryVisitor(); p.accept(dlv); return dlv.datatypeLibraries; } } static class NamespaceVisitor extends VoidVisitor { private final NamespaceManager nsm = new NamespaceManager(); private boolean isAttribute; public void voidVisitInclude(IncludeComponent c) { super.voidVisitInclude(c); nsm.requireNamespace(c.getNs(), true); } public void voidVisitExternalRef(ExternalRefPattern p) { super.voidVisitExternalRef(p); nsm.requireNamespace(p.getNs(), true); } public void voidVisitElement(ElementPattern p) { isAttribute = false; super.voidVisitElement(p); } public void voidVisitAttribute(AttributePattern p) { isAttribute = true; super.voidVisitAttribute(p); } public void voidVisitName(NameNameClass nc) { super.voidVisitName(nc); if (!isAttribute || nc.getNamespaceUri().length() != 0) nsm.requireNamespace(nc.getNamespaceUri(), !isAttribute); if (nc.getPrefix() == null) { if (!isAttribute) nsm.preferBinding("", nc.getNamespaceUri()); } else nsm.preferBinding(nc.getPrefix(), nc.getNamespaceUri()); } public void voidVisitNsName(NsNameNameClass nc) { super.voidVisitNsName(nc); nsm.requireNamespace(nc.getNs(), false); } public void voidVisitValue(ValuePattern p) { super.voidVisitValue(p); for (Map.Entry entry : p.getPrefixMap().entrySet()) { nsm.requireBinding(entry.getKey(), entry.getValue()); } } public void voidVisitElement(ElementAnnotation ea) { super.voidVisitElement(ea); noteAnnotationBinding(ea.getPrefix(), ea.getNamespaceUri()); noteContext(ea.getContext(), true); } private void noteContext(NamespaceContext context, boolean required) { if (context == null) return; for (String prefix : context.getPrefixes()) { // Default namespace is not relevant to annotations if (!prefix.equals("")) { String ns = context.getNamespace(prefix); if (ns != null && !ns.equals(SchemaBuilder.INHERIT_NS)) { if (required) nsm.requireBinding(prefix, ns); else nsm.preferBinding(prefix, ns); } } } } public void voidVisitAttribute(AttributeAnnotation a) { super.voidVisitAttribute(a); noteAnnotationBinding(a.getPrefix(), a.getNamespaceUri()); } private void noteAnnotationBinding(String prefix, String ns) { if (ns.length() != 0) nsm.requireNamespace(ns, false); if (prefix != null) nsm.preferBinding(prefix, ns); } public void voidVisitAnnotated(Annotated p) { p.leadingCommentsAccept(this); noteContext(p.getContext(), !p.getAttributeAnnotations().isEmpty()); p.attributeAnnotationsAccept(this); List before = (p.mayContainText() ? p.getFollowingElementAnnotations() : p.getChildElementAnnotations()); // Avoid unnecessary prefix for documentation int state = 0; for (AnnotationChild child : before) { if (state < 2 && documentationString(child) != null) state = 1; else if (state != 1 || !(child instanceof Comment)) state = 2; if (state == 2) child.accept(this); } if (!p.mayContainText()) p.followingElementAnnotationsAccept(this); } static NamespaceManager.NamespaceBindings createBindings(Pattern p) { NamespaceVisitor nsv = new NamespaceVisitor(); p.accept(nsv); return nsv.nsm.createBindings(); } } private class ComponentOutput implements ComponentVisitor { public VoidValue visitDefine(DefineComponent c) { startAnnotations(c); pp.startGroup(); String name = c.getName(); if (name == DefineComponent.START) pp.text("start"); else identifier(name); Combine combine = c.getCombine(); String op; if (combine == null) op = " ="; else if (combine == Combine.CHOICE) op = " |="; else op = " &="; pp.text(op); pp.startNest(indent); pp.softNewline(" "); c.getBody().accept(noParenPatternOutput); pp.endNest(); pp.endGroup(); endAnnotations(c); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { startAnnotations(c); pp.text("div"); body(c); endAnnotations(c); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { startAnnotations(c); pp.startGroup(); pp.text("include "); pp.startNest("include "); literal(od.reference(sourceUri, c.getUri())); inherit(c.getNs()); pp.endNest(); pp.endGroup(); List components = c.getComponents(); if (!components.isEmpty()) body(components); endAnnotations(c); return VoidValue.VOID; } } class RepeatedPatternOutput extends PatternOutput { RepeatedPatternOutput() { super(true); } protected void postfix(UnaryPattern p, String op) { startAnnotations(p); pp.text("("); pp.startNest("("); p.getChild().accept(repeatedPatternOutput); pp.endNest(); pp.text(op); pp.text(")"); endAnnotations(p); } } class PatternOutput implements PatternVisitor { private final boolean alwaysUseParens; PatternOutput(boolean alwaysUseParens) { this.alwaysUseParens = alwaysUseParens; } public VoidValue visitGrammar(GrammarPattern p) { startAnnotations(p); pp.text("grammar"); body(p); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitElement(ElementPattern p) { isAttributeNameClass = false; nameClassed(p, "element "); return VoidValue.VOID; } public VoidValue visitAttribute(AttributePattern p) { isAttributeNameClass = true; nameClassed(p, "attribute "); return VoidValue.VOID; } private void nameClassed(NameClassedPattern p, String key) { startAnnotations(p); pp.text(key); pp.startNest(key); p.getNameClass().accept(noParenNameClassOutput); pp.endNest(); braceChild(p); endAnnotations(p); } private void braceChild(UnaryPattern p) { Pattern child = p.getChild(); boolean isSimple = !complexityCache.isComplex(child); if (isSimple) pp.startGroup(); pp.text(" {"); pp.startNest(indent); if (isSimple) pp.softNewline(" "); else pp.hardNewline(); child.accept(noParenPatternOutput); pp.endNest(); if (isSimple) pp.softNewline(" "); else pp.hardNewline(); pp.text("}"); if (isSimple) pp.endGroup(); } public VoidValue visitOneOrMore(OneOrMorePattern p) { postfix(p, "+"); return VoidValue.VOID; } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { postfix(p, "*"); return VoidValue.VOID; } public VoidValue visitOptional(OptionalPattern p) { postfix(p, "?"); return VoidValue.VOID; } protected void postfix(UnaryPattern p, String op) { if (!startAnnotations(p)) { p.getChild().accept(repeatedPatternOutput); pp.text(op); } else { pp.text("("); pp.startNest("("); p.getChild().accept(repeatedPatternOutput); pp.endNest(); pp.text(op); pp.text(")"); } endAnnotations(p); } public VoidValue visitRef(RefPattern p) { startAnnotations(p); identifier(p.getName()); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitParentRef(ParentRefPattern p) { startAnnotations(p); pp.text("parent "); identifier(p.getName()); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitExternalRef(ExternalRefPattern p) { startAnnotations(p); pp.startGroup(); pp.text("external "); pp.startNest("external "); literal(od.reference(sourceUri, p.getUri())); inherit(p.getNs()); pp.endNest(); pp.endGroup(); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitText(TextPattern p) { startAnnotations(p); pp.text("text"); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitEmpty(EmptyPattern p) { startAnnotations(p); pp.text("empty"); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitNotAllowed(NotAllowedPattern p) { startAnnotations(p); pp.text("notAllowed"); endAnnotations(p); return VoidValue.VOID; } public VoidValue visitList(ListPattern p) { prefix(p, "list"); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { prefix(p, "mixed"); return VoidValue.VOID; } private void prefix(UnaryPattern p, String key) { startAnnotations(p); pp.text(key); braceChild(p); endAnnotations(p); } public VoidValue visitChoice(ChoicePattern p) { composite(p, "| ", false); return VoidValue.VOID; } public VoidValue visitInterleave(InterleavePattern p) { composite(p, "& ", false); return VoidValue.VOID; } public VoidValue visitGroup(GroupPattern p) { composite(p, ",", true); return VoidValue.VOID; } void composite(CompositePattern p, String sep, boolean sepBeforeNewline) { boolean useParens = alwaysUseParens; if (startAnnotations(p)) useParens = true; boolean isSimple = !complexityCache.isComplex(p); if (isSimple) pp.startGroup(); if (useParens) { pp.text("("); pp.startNest("("); } boolean first = true; for (Pattern child : p.getChildren()) { if (!first) { if (sepBeforeNewline) pp.text(sep); if (isSimple) pp.softNewline(" "); else pp.hardNewline(); if (!sepBeforeNewline) { pp.text(sep); pp.startNest(sep); } } child.accept(patternOutput); if (first) first = false; else if (!sepBeforeNewline) pp.endNest(); } if (useParens) { pp.endNest(); pp.text(")"); } if (isSimple) pp.endGroup(); endAnnotations(p); } public VoidValue visitData(DataPattern p) { startAnnotations(p); String lib = p.getDatatypeLibrary(); String qn; if (!lib.equals("")) qn = datatypeLibraryMap.get(lib) + ":" + p.getType(); else qn = p.getType(); qn = encode(qn); Pattern e = p.getExcept(); // open a parentheses on data except if (e != null) pp.text("("); pp.text(qn); List params = p.getParams(); if (params.size() > 0) { pp.startGroup(); pp.text(" {"); pp.startNest(indent); for (Param param : params) { pp.softNewline(" "); startAnnotations(param); pp.startGroup(); encodedText(param.getName()); pp.text(" ="); pp.startNest(indent); pp.softNewline(" "); literal(param.getValue()); pp.endNest(); pp.endGroup(); endAnnotations(param); } pp.endNest(); pp.softNewline(" "); pp.text("}"); pp.endGroup(); } if (e != null) { boolean useParen = (!e.mayContainText() && !e.getFollowingElementAnnotations().isEmpty()); String s; if (params.isEmpty()) s = " - "; else { pp.startGroup(); pp.softNewline(" "); s = "- "; } if (useParen) s += "("; pp.text(s); pp.startNest(params.isEmpty() ? qn + s : s); e.accept(useParen ? noParenPatternOutput : patternOutput); pp.endNest(); if (useParen) pp.text(")"); if (!params.isEmpty()) pp.endGroup(); // close the parentheses on data except pp.text(")"); } endAnnotations(p); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { for (Map.Entry entry : p.getPrefixMap().entrySet()) { String prefix = entry.getKey(); String uri = entry.getValue(); if (!uri.equals(nsb.getNamespaceUri(prefix))) { if (prefix.equals("")) er.error("value_inconsistent_default_binding", uri, p.getSourceLocation()); else er.error("value_inconsistent_binding", prefix, uri, p.getSourceLocation()); } } startAnnotations(p); String lib = p.getDatatypeLibrary(); pp.startGroup(); String str = null; if (lib.equals("")) { if (!p.getType().equals("token")) str = p.getType() + " "; } else str = datatypeLibraryMap.get(lib) + ":" + p.getType() + " "; if (str != null) { String encoded = encode(str); pp.text(encoded); pp.startNest(encoded); } literal(p.getValue()); if (str != null) pp.endNest(); pp.endGroup(); endAnnotations(p); return VoidValue.VOID; } } class NameClassOutput implements NameClassVisitor { private final boolean alwaysUseParens; NameClassOutput(boolean alwaysUseParens) { this.alwaysUseParens = alwaysUseParens; } public VoidValue visitAnyName(AnyNameNameClass nc) { NameClass e = nc.getExcept(); if (e == null) { startAnnotations(nc); pp.text("*"); } else { boolean useParens = startAnnotations(nc) || alwaysUseParens; String s = useParens ? "(* - " : "* - "; pp.text(s); pp.startNest(s); e.accept(nameClassOutput); if (useParens) pp.text(")"); pp.endNest(); } endAnnotations(nc); return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { NameClass e = nc.getExcept(); String prefix = nsb.getNonEmptyPrefix(nc.getNs()); if (e == null) { startAnnotations(nc); encodedText(prefix); pp.text(":*"); } else { boolean useParens = startAnnotations(nc) || alwaysUseParens; String s = useParens ? "(" : ""; s += encode(prefix); s += ":* - "; pp.text(s); pp.startNest(s); e.accept(nameClassOutput); pp.endNest(); if (useParens) pp.text(")"); } endAnnotations(nc); return VoidValue.VOID; } public VoidValue visitName(NameNameClass nc) { startAnnotations(nc); qualifiedName(nc.getNamespaceUri(), nc.getPrefix(), nc.getLocalName(), isAttributeNameClass); endAnnotations(nc); return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { boolean useParens = alwaysUseParens; if (startAnnotations(nc)) useParens = true; else if (nc.getChildren().size() == 1) useParens = false; if (useParens) { pp.text("("); pp.startNest("("); } pp.startGroup(); boolean first = true; for (NameClass child : nc.getChildren()) { if (first) first = false; else { pp.softNewline(" "); pp.text("| "); } child.accept(nameClassOutput); } pp.endGroup(); if (useParens) { pp.endNest(); pp.text(")"); } endAnnotations(nc); return VoidValue.VOID; } } class AnnotationChildOutput implements AnnotationChildVisitor { public VoidValue visitText(TextAnnotation ta) { literal(ta.getValue()); return VoidValue.VOID; } public VoidValue visitComment(Comment c) { comment("#", c.getValue()); return VoidValue.VOID; } public VoidValue visitElement(ElementAnnotation elem) { checkContext(elem.getContext(), elem.getSourceLocation()); qualifiedName(elem.getNamespaceUri(), elem.getPrefix(), elem.getLocalName(), // unqualified annotation element names have "" namespace true); pp.text(" "); annotationBody(elem.getAttributes(), elem.getChildren()); return VoidValue.VOID; } } class FollowingAnnotationChildOutput extends AnnotationChildOutput { public VoidValue visitElement(ElementAnnotation elem) { pp.text(">> "); pp.startNest(">> "); super.visitElement(elem); pp.endNest(); return VoidValue.VOID; } } private static boolean hasAnnotations(Annotated annotated) { return (!annotated.getChildElementAnnotations().isEmpty() || !annotated.getAttributeAnnotations().isEmpty() || !annotated.getFollowingElementAnnotations().isEmpty()); } private boolean startAnnotations(Annotated annotated) { if (!annotated.getLeadingComments().isEmpty()) { leadingComments(annotated); if (!hasAnnotations(annotated)) return false; } else if (!hasAnnotations(annotated)) return false; List before = (annotated.mayContainText() ? annotated.getFollowingElementAnnotations() : annotated.getChildElementAnnotations()); int i = 0; int len = before.size(); for (; i < len; i++) { int j = i; if (i != 0) { do { if (!(before.get(j) instanceof Comment)) break; } while (++j < len); if (j >= len) break; } String doc = documentationString(before.get(j)); if (doc == null) break; if (j == i) pp.hardNewline(); else { for (;;) { before.get(i).accept(annotationChildOutput); if (++i == j) break; pp.hardNewline(); } } comment("##", doc); } if (i > 0) before = before.subList(i, len); pp.startGroup(); if (!annotated.getAttributeAnnotations().isEmpty() || !before.isEmpty()) { if (!annotated.getAttributeAnnotations().isEmpty()) checkContext(annotated.getContext(), annotated.getSourceLocation()); annotationBody(annotated.getAttributeAnnotations(), before); pp.softNewline(" "); } return true; } private static String documentationString(AnnotationChild child) { if (!(child instanceof ElementAnnotation)) return null; ElementAnnotation elem = (ElementAnnotation)child; if (!elem.getLocalName().equals("documentation")) return null; if (!elem.getNamespaceUri().equals(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS)) return null; if (!elem.getAttributes().isEmpty()) return null; StringBuffer buf = new StringBuffer(); for (AnnotationChild a : elem.getChildren()) { if (!(a instanceof TextAnnotation)) return null; buf.append(((TextAnnotation)a).getValue()); } return buf.toString(); } private void endAnnotations(Annotated annotated) { if (!annotated.mayContainText()) { for (AnnotationChild child : annotated.getFollowingElementAnnotations()) { if (annotated instanceof Component) pp.hardNewline(); else pp.softNewline(" "); AnnotationChildVisitor output = (annotated instanceof Component ? annotationChildOutput : followingAnnotationChildOutput); child.accept(output); } } if (hasAnnotations(annotated)) pp.endGroup(); } private void leadingComments(Annotated annotated) { boolean first = true; for (Comment comment : annotated.getLeadingComments()) { if (!first) pp.hardNewline(); else first = false; comment.accept(annotationChildOutput); } } private void annotationBody(List attributes, List children) { pp.startGroup(); pp.text("["); pp.startNest(indent); for (AttributeAnnotation att : attributes) { pp.softNewline(" "); pp.startGroup(); qualifiedName(att.getNamespaceUri(), att.getPrefix(), att.getLocalName(), true); pp.text(" ="); pp.startNest(indent); pp.softNewline(" "); literal(att.getValue()); pp.endNest(); pp.endGroup(); } for (AnnotationChild child : children) { pp.softNewline(" "); child.accept(annotationChildOutput); } pp.endNest(); pp.softNewline(" "); pp.text("]"); pp.endGroup(); } private void body(Container container) { body(container.getComponents()); } private void body(List components) { if (components.size() == 0) pp.text(" { }"); else { pp.text(" {"); pp.startNest(indent); pp.hardNewline(); innerBody(components); pp.endNest(); pp.hardNewline(); pp.text("}"); } } private void innerBody(List components) { boolean first = true; for (Component c : components) { if (first) first = false; else pp.hardNewline(); c.accept(componentOutput); } } private void inherit(String ns) { if (ns.equals(nsb.getNamespaceUri(""))) return; pp.softNewline(" "); pp.text("inherit = "); encodedText(nsb.getNonEmptyPrefix(ns)); } private void identifier(String name) { if (keywordSet.contains(name)) pp.text("\\"); encodedText(name); } private static final String[] delims = { "\"", "'", "\"\"\"", "'''" }; private void literal(String str) { for (int i = 0, len = str.length();;) { // Find the delimiter that gives the longest segment String bestDelim = null; int bestEnd = -1; int lim = str.indexOf('\n', i); if (lim < 0) lim = len; else ++lim; for (int j = 0; j < delims.length; j++) { int end = (str + delims[j]).indexOf(delims[j], i); if (end > bestEnd) { bestDelim = delims[j]; bestEnd = end; if (end >= lim) { bestEnd = lim; break; } } } if (i != 0) { pp.text(" ~"); pp.softNewline(" "); } pp.text(bestDelim); encodedText(str.substring(i, bestEnd)); pp.text(bestDelim); i = bestEnd; if (i == len) break; } } private void encodedText(String str) { pp.text(encode(str)); } private String encode(String str) { int start = 0; int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); switch (c) { case '\\': if (!startsWithEscapeOpen(str, i)) break; // fall through case '\r': case '\n': if (start < i) encodeBuf.append(str.substring(start, i)); escape(c); start = i + 1; break; default: if (Utf16.isSurrogate(c)) { if (!cr.contains(c, str.charAt(i + 1))) { if (start < i) encodeBuf.append(str.substring(start, i)); escape(Utf16.scalarValue(c, str.charAt(i + 1))); start = i + 2; } ++i; } else if (!cr.contains(c)) { if (start < i) encodeBuf.append(str.substring(start, i)); escape(c); start = i + 1; } break; } } if (start == 0) return str; if (start != len) encodeBuf.append(str.substring(start, len)); str = encodeBuf.toString(); encodeBuf.setLength(0); return str; } private void escape(int n) { encodeBuf.append("\\x{"); encodeBuf.append(Integer.toHexString(n)); encodeBuf.append("}"); } static private boolean startsWithEscapeOpen(String str, int off) { if (!str.startsWith("\\x", off)) return false; for (off += 2; str.startsWith("x", off); off++) ; return str.startsWith("{", off); } /** * null means no prefix */ private void qualifiedName(String ns, String prefix, String localName, boolean isAttribute) { prefix = choosePrefix(ns, prefix, isAttribute); if (prefix == null) encodedText(localName); else { encodedText(prefix); pp.text(":"); encodedText(localName); } } /** * null means no prefix */ private String choosePrefix(String ns, String prefix, boolean isAttribute) { if (prefix != null && ns.equals(nsb.getNamespaceUri(prefix))) return prefix; if (isAttribute) { if (ns.length() == 0) return null; } else { if (ns.equals(nsb.getNamespaceUri(""))) return null; } return nsb.getNonEmptyPrefix(ns); } private void comment(String delim, String value) { int i = 0; for (;;) { pp.text(delim); if (i < value.length() && value.charAt(i) != '\t') pp.text(" "); int j = value.indexOf('\n', i); String tem = j < 0 ? value.substring(i) : value.substring(i, j); encodedText(tem); pp.hardNewline(); if (j < 0) break; i = j + 1; } } private void checkContext(NamespaceContext context, SourceLocation loc) { if (context == null) return; for (String prefix : context.getPrefixes()) { // Default namespace is not relevant to annotations if (!prefix.equals("")) { String ns = context.getNamespace(prefix); if (ns != null && !ns.equals(SchemaBuilder.INHERIT_NS) && !nsb.getNamespaceUri(prefix).equals(ns)) er.warning("annotation_inconsistent_binding", prefix, ns, loc); } } } } Prettyprinter.java000066400000000000000000000011461225366607500344630ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rncpackage com.thaiopensource.relaxng.output.rnc; import java.io.IOException; interface Prettyprinter { public static class WrappedException extends RuntimeException { private final IOException cause; public Throwable getCause() { return cause; } public IOException getIOException() { return cause; } public WrappedException(IOException cause) { this.cause = cause; } } void hardNewline(); void softNewline(String noBreak); void text(String str); void startNest(String indent); void endNest(); void startGroup(); void endGroup(); void close(); } RncOutputFormat.java000066400000000000000000000031211225366607500346770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rncpackage com.thaiopensource.relaxng.output.rnc; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.OutputDirectoryParamProcessor; import com.thaiopensource.relaxng.output.OutputFailedException; import com.thaiopensource.relaxng.output.OutputFormat; import com.thaiopensource.relaxng.output.common.ErrorReporter; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; import java.util.Map; public class RncOutputFormat implements OutputFormat { public void output(SchemaCollection sc, OutputDirectory od, String[] params, String inputFormat, ErrorHandler eh) throws SAXException, IOException, OutputFailedException, InvalidParamsException { new OutputDirectoryParamProcessor(od).process(params, eh); try { ErrorReporter er = new ErrorReporter(eh, RncOutputFormat.class); for (Map.Entry entry : sc.getSchemaDocumentMap().entrySet()) { outputPattern(entry.getValue(), entry.getKey(), od, er); } } catch (ErrorReporter.WrappedSAXException e) { throw e.getException(); } } private static void outputPattern(SchemaDocument sd, String sourceUri, OutputDirectory od, ErrorReporter er) throws IOException { Output.output(sd.getPattern(), sd.getEncoding(), sourceUri, od, er); } } StreamingPrettyprinter.java000066400000000000000000000156151225366607500363430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rncpackage com.thaiopensource.relaxng.output.rnc; import java.io.Writer; import java.io.IOException; public class StreamingPrettyprinter implements Prettyprinter { private final String lineSep; private final Writer w; static private class Group { /** * Serial number of the segment containing the close of the group * or -1 if the segment is not yet closed. */ int closeSegmentSerial = -1; boolean broken; final Group parent; Group(Group parent) { this.parent = parent; broken = (parent == null); } void setBroken() { if (!broken) { broken = true; parent.setBroken(); } } } static private class Segment { /** * Reference to the next segment. */ Segment next; /** * Number of characters to discard at the end of the segment if we break immediately after * the segment */ int preBreakDiscardCount = -1; /** * The current group at the end of the segment. */ Group group = null; /** * The indent to be written after the newline at the end of this segment */ int indent; final int serial; private static final int ALLOC_SPARE = 5; private static final int ALLOC_INIT = 10; /** * The characters in the segment including the characters from the terminating soft newline */ char[] chars = new char[ALLOC_INIT]; /** * The number of characters in chars */ int length = 0; Segment(int serial) { this.serial = serial; } void append(String str) { if (str.length() > chars.length - length) { int newSize = chars.length * 2; if (newSize - length < str.length()) newSize = chars.length + str.length() + ALLOC_SPARE; char[] newChars = new char[newSize]; System.arraycopy(chars, 0, newChars, 0, length); chars = newChars; } str.getChars(0, str.length(), chars, length); length += str.length(); } } private Segment head; private Segment tail; private int nextSegmentSerial = 0; private Group currentGroup = new Group(null); private int currentIndent = 0; private int[] indentStack = new int[10]; private int indentLevel = 0; /** * The total width of the segments between head and tail inclusive. */ private int totalWidth = 0; /** * Available width on this line. */ private int availWidth; /** * The last possible breakpoint discovered on the line is immediately after this * segment. */ private Segment lastPossibleBreak = null; /** * Maximum allowable line width (not including newline char). */ private final int maxWidth; private Group noBreakGroup = null; public StreamingPrettyprinter(int maxWidth, String lineSep, Writer w) { this.lineSep = lineSep; this.w = w; this.maxWidth = maxWidth; this.availWidth = maxWidth; head = makeSegment(); tail = head; } private Segment makeSegment() { return new Segment(nextSegmentSerial++); } public void startGroup() { currentGroup = new Group(currentGroup); } public void endGroup() { if (noBreakGroup == currentGroup) noBreakGroup = null; currentGroup.closeSegmentSerial = tail.serial; currentGroup = currentGroup.parent; } public void startNest(String indent) { if (indentLevel >= indentStack.length) { int[] newStack = new int[indentStack.length * 2]; System.arraycopy(indentStack, 0, newStack, 0, indentStack.length); indentStack = newStack; } indentStack[indentLevel++] = currentIndent; currentIndent += indent.length(); } public void endNest() { currentIndent = indentStack[--indentLevel]; } public void text(String str) { tail.append(str); totalWidth += str.length(); tryFlush(false); } public void softNewline(String noBreak) { if (head == tail || noBreakGroup == null) lastPossibleBreak = tail; tail.append(noBreak); tail.preBreakDiscardCount = noBreak.length(); tail.group = currentGroup; if (noBreakGroup == null) noBreakGroup = currentGroup; tail.indent = currentIndent; totalWidth += tail.preBreakDiscardCount; Segment tem = makeSegment(); tail.next = tem; tail = tem; tryFlush(false); } public void hardNewline() { if (head == tail || noBreakGroup == null) lastPossibleBreak = tail; tail.preBreakDiscardCount = 0; tail.group = currentGroup; if (noBreakGroup == null) noBreakGroup = currentGroup; tail.indent = currentIndent; Segment tem = makeSegment(); tail.next = tem; tail = tem; tryFlush(true); } private boolean shouldKeepLooking(boolean hard) { if (lastPossibleBreak == null) return true; if (hard) return false; if (totalWidth > availWidth) return false; if (lastPossibleBreak.group.broken) return false; return true; } private void tryFlush(boolean hard) { for (;;) { if (shouldKeepLooking(hard)) return; Segment s = head; head = lastPossibleBreak.next; lastPossibleBreak.next = null; lastPossibleBreak.length -= lastPossibleBreak.preBreakDiscardCount; for (; s != null; s = s.next) write(s.chars, 0, s.length); writeNewline(lastPossibleBreak.indent); availWidth = maxWidth - lastPossibleBreak.indent; lastPossibleBreak.group.setBroken(); update(); } } private void update() { lastPossibleBreak = null; totalWidth = 0; Group nbg = null; for (Segment s = head; s != tail; s = s.next) { if (nbg != null && nbg.closeSegmentSerial != -1 && s.serial >= nbg.closeSegmentSerial) nbg = null; totalWidth += s.length; if (lastPossibleBreak == null || (!lastPossibleBreak.group.broken && nbg == null)) lastPossibleBreak = s; if (nbg == null) nbg = s.group; } totalWidth += tail.length; if (nbg != null && nbg.closeSegmentSerial == -1) noBreakGroup = nbg; else noBreakGroup = null; } public void close() { if (tail.length != 0) { // Don't want spaces after final newline currentIndent = 0; hardNewline(); } else if (head != tail) { // Avoid spaces after final newline for (Segment s = head;; s = s.next) { if (s.next == tail) { s.indent = 0; break; } } tryFlush(true); } try { w.close(); } catch (IOException e) { throw new Prettyprinter.WrappedException(e); } } private void write(char[] chars, int off, int len) { try { w.write(chars, off, len); } catch (IOException e) { throw new Prettyprinter.WrappedException(e); } } private void writeNewline(int indent) { try { w.write(lineSep); for (int i = 0; i < indent; i++) w.write(' '); } catch (IOException e) { throw new Prettyprinter.WrappedException(e); } } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rnc/resources/000077500000000000000000000000001225366607500330145ustar00rootroot00000000000000Messages.properties000066400000000000000000000007601225366607500366250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rnc/resourcesvalue_inconsistent_default_binding=in translated output default namespace not correctly bound to URI \"{0}\" as needed for value because used inconsistently elsewhere value_inconsistent_binding=in translated output prefix \"{0}\" not correctly bound to URI \"{1}\" as needed for value because used inconsistently elsewhere annotation_inconsistent_binding=in translated output prefix \"{0}\" not correctly bound to URI \"{1}\" as perhaps needed for annotation because used inconsistently elsewherejing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rng/000077500000000000000000000000001225366607500310065ustar00rootroot00000000000000Analyzer.java000066400000000000000000000165431225366607500333700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rngpackage com.thaiopensource.relaxng.output.rng; import com.thaiopensource.relaxng.edit.AbstractVisitor; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassedPattern; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.relaxng.edit.NamespaceContext; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.HashMap; import java.util.List; import java.util.Map; class Analyzer extends AbstractVisitor { private VoidValue visitAnnotated(Annotated anno) { if (anno.getAttributeAnnotations().size() > 0 || anno.getChildElementAnnotations().size() > 0 || anno.getFollowingElementAnnotations().size() > 0) noteContext(anno.getContext()); visitAnnotationAttributes(anno.getAttributeAnnotations()); visitAnnotationChildren(anno.getChildElementAnnotations()); visitAnnotationChildren(anno.getFollowingElementAnnotations()); return VoidValue.VOID; } private void visitAnnotationAttributes(List list) { for (int i = 0, len = list.size(); i < len; i++) { AttributeAnnotation att = list.get(i); if (att.getNamespaceUri().length() != 0) noteNs(att.getPrefix(), att.getNamespaceUri()); } } private void visitAnnotationChildren(List list) { for (int i = 0, len = list.size(); i < len; i++) { AnnotationChild ac = list.get(i); if (ac instanceof ElementAnnotation) { ElementAnnotation elem = (ElementAnnotation)ac; if (elem.getPrefix() != null) noteNs(elem.getPrefix(), elem.getNamespaceUri()); visitAnnotationAttributes(elem.getAttributes()); visitAnnotationChildren(elem.getChildren()); } } } public VoidValue visitPattern(Pattern p) { return visitAnnotated(p); } public VoidValue visitDefine(DefineComponent c) { visitAnnotated(c); return c.getBody().accept(this); } public VoidValue visitDiv(DivComponent c) { visitAnnotated(c); return visitContainer(c); } public VoidValue visitInclude(IncludeComponent c) { visitAnnotated(c); noteInheritNs(c.getNs()); return visitContainer(c); } public VoidValue visitGrammar(GrammarPattern p) { visitAnnotated(p); return visitContainer(p); } private VoidValue visitContainer(Container c) { List list = c.getComponents(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); return VoidValue.VOID; } public VoidValue visitUnary(UnaryPattern p) { visitAnnotated(p); return p.getChild().accept(this); } public VoidValue visitComposite(CompositePattern p) { visitAnnotated(p); List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); return VoidValue.VOID; } public VoidValue visitNameClassed(NameClassedPattern p) { p.getNameClass().accept(this); return visitUnary(p); } public VoidValue visitAttribute(AttributePattern p) { NameClass nc = p.getNameClass(); if (nc instanceof NameNameClass && ((NameNameClass)nc).getNamespaceUri().equals("")) return visitUnary(p); return visitNameClassed(p); } public VoidValue visitChoice(ChoiceNameClass nc) { visitAnnotated(nc); List list = nc.getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { visitAnnotated(p); if (!p.getType().equals("token") || !p.getDatatypeLibrary().equals("")) noteDatatypeLibrary(p.getDatatypeLibrary()); for (Map.Entry entry : p.getPrefixMap().entrySet()) { noteNs(entry.getKey(), entry.getValue()); } return VoidValue.VOID; } public VoidValue visitData(DataPattern p) { visitAnnotated(p); noteDatatypeLibrary(p.getDatatypeLibrary()); Pattern except = p.getExcept(); if (except != null) except.accept(this); for (Param param : p.getParams()) visitAnnotated(param); return VoidValue.VOID; } public VoidValue visitExternalRef(ExternalRefPattern p) { visitAnnotated(p); noteInheritNs(p.getNs()); return VoidValue.VOID; } public VoidValue visitName(NameNameClass nc) { visitAnnotated(nc); noteNs(nc.getPrefix(), nc.getNamespaceUri()); return VoidValue.VOID; } public VoidValue visitAnyName(AnyNameNameClass nc) { visitAnnotated(nc); NameClass except = nc.getExcept(); if (except != null) except.accept(this); return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { visitAnnotated(nc); noteInheritNs(nc.getNs()); NameClass except = nc.getExcept(); if (except != null) except.accept(this); return VoidValue.VOID; } private String datatypeLibrary = null; private final Map prefixMap = new HashMap(); private boolean haveInherit = false; private NamespaceContext lastContext = null; private String noPrefixNs = null; private void noteDatatypeLibrary(String uri) { if (datatypeLibrary == null || datatypeLibrary.length() == 0) datatypeLibrary = uri; } private void noteInheritNs(String ns) { if (ns == NameClass.INHERIT_NS) haveInherit = true; else noPrefixNs = ns; } private void noteNs(String prefix, String ns) { if (ns == NameClass.INHERIT_NS) { haveInherit = true; return; } if (prefix == null) prefix = ""; if (ns == null || (ns.length() == 0 && prefix.length() != 0) || prefixMap.containsKey(prefix)) return; prefixMap.put(prefix, ns); } private void noteContext(NamespaceContext context) { if (context == null || context == lastContext) return; lastContext = context; for (String prefix : context.getPrefixes()) noteNs(prefix, context.getNamespace(prefix)); } Map getPrefixMap() { if (haveInherit) prefixMap.remove(""); else if (noPrefixNs != null && !prefixMap.containsKey("")) prefixMap.put("", noPrefixNs); prefixMap.put("xml", WellKnownNamespaces.XML); return prefixMap; } String getDatatypeLibrary() { return datatypeLibrary; } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rng/Output.java000066400000000000000000000426741225366607500331660ustar00rootroot00000000000000package com.thaiopensource.relaxng.output.rng; import com.thaiopensource.relaxng.edit.AbstractRefPattern; import com.thaiopensource.relaxng.edit.Annotated; import com.thaiopensource.relaxng.edit.AnnotationChild; import com.thaiopensource.relaxng.edit.AnyNameNameClass; import com.thaiopensource.relaxng.edit.AttributeAnnotation; import com.thaiopensource.relaxng.edit.AttributePattern; import com.thaiopensource.relaxng.edit.ChoiceNameClass; import com.thaiopensource.relaxng.edit.ChoicePattern; import com.thaiopensource.relaxng.edit.Comment; import com.thaiopensource.relaxng.edit.Component; import com.thaiopensource.relaxng.edit.ComponentVisitor; import com.thaiopensource.relaxng.edit.CompositePattern; import com.thaiopensource.relaxng.edit.Container; import com.thaiopensource.relaxng.edit.DataPattern; import com.thaiopensource.relaxng.edit.DefineComponent; import com.thaiopensource.relaxng.edit.DivComponent; import com.thaiopensource.relaxng.edit.ElementAnnotation; import com.thaiopensource.relaxng.edit.ElementPattern; import com.thaiopensource.relaxng.edit.EmptyPattern; import com.thaiopensource.relaxng.edit.ExternalRefPattern; import com.thaiopensource.relaxng.edit.GrammarPattern; import com.thaiopensource.relaxng.edit.GroupPattern; import com.thaiopensource.relaxng.edit.IncludeComponent; import com.thaiopensource.relaxng.edit.InterleavePattern; import com.thaiopensource.relaxng.edit.ListPattern; import com.thaiopensource.relaxng.edit.MixedPattern; import com.thaiopensource.relaxng.edit.NameClass; import com.thaiopensource.relaxng.edit.NameClassVisitor; import com.thaiopensource.relaxng.edit.NameNameClass; import com.thaiopensource.relaxng.edit.NotAllowedPattern; import com.thaiopensource.relaxng.edit.NsNameNameClass; import com.thaiopensource.relaxng.edit.OneOrMorePattern; import com.thaiopensource.relaxng.edit.OpenNameClass; import com.thaiopensource.relaxng.edit.OptionalPattern; import com.thaiopensource.relaxng.edit.Param; import com.thaiopensource.relaxng.edit.ParentRefPattern; import com.thaiopensource.relaxng.edit.Pattern; import com.thaiopensource.relaxng.edit.PatternVisitor; import com.thaiopensource.relaxng.edit.RefPattern; import com.thaiopensource.relaxng.edit.TextAnnotation; import com.thaiopensource.relaxng.edit.TextPattern; import com.thaiopensource.relaxng.edit.UnaryPattern; import com.thaiopensource.relaxng.edit.ValuePattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.relaxng.edit.ZeroOrMorePattern; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.common.XmlWriter; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.io.IOException; import java.util.List; import java.util.Map; class Output implements PatternVisitor, NameClassVisitor, ComponentVisitor { private final String sourceUri; private final OutputDirectory od; private final XmlWriter xw; private final String datatypeLibrary; private final Map prefixMap; private String localNs = null; static public void output(Pattern p, String encoding, String sourceUri, OutputDirectory od, String datatypeLibrary, Map prefixMap) throws IOException { try { Output out = new Output(sourceUri, encoding, od, datatypeLibrary, prefixMap); p.accept(out); out.xw.close(); } catch (XmlWriter.WrappedException e) { throw e.getIOException(); } } private Output(String sourceUri, String encoding, OutputDirectory od, String datatypeLibrary, Map prefixMap) throws IOException { this.sourceUri = sourceUri; this.od = od; this.datatypeLibrary = datatypeLibrary; this.prefixMap = prefixMap; OutputDirectory.Stream stream = od.open(sourceUri, encoding); this.xw = new XmlWriter(stream.getWriter(), stream.getEncoding(), stream.getCharRepertoire(), od.getLineSeparator(), od.getIndent(), getTopLevelAttributes()); } private String[] getTopLevelAttributes() { int nAtts = prefixMap.size(); if (datatypeLibrary != null) nAtts += 1; String[] atts = new String[nAtts * 2]; int i = 0; for (Map.Entry entry : prefixMap.entrySet()) { String prefix = entry.getKey(); if (!prefix.equals("xml")) { if (prefix.equals("")) atts[i++] = "ns"; else atts[i++] = "xmlns:" + prefix; atts[i++] = entry.getValue(); } } atts[i++] = "xmlns"; atts[i++] = WellKnownNamespaces.RELAX_NG; if (datatypeLibrary != null) { atts[i++] = "datatypeLibrary"; atts[i++] = datatypeLibrary; } return atts; } public VoidValue visitElement(ElementPattern p) { leadingAnnotations(p); xw.startElement("element"); boolean usedNameAtt = tryNameAttribute(p.getNameClass(), false); innerAnnotations(p); if (!usedNameAtt) p.getNameClass().accept(this); implicitGroup(p.getChild()); end(p); return VoidValue.VOID; } public VoidValue visitAttribute(AttributePattern p) { leadingAnnotations(p); xw.startElement("attribute"); boolean usedNameAtt = tryNameAttribute(p.getNameClass(), true); innerAnnotations(p); if (!usedNameAtt) p.getNameClass().accept(this); Pattern child = p.getChild(); if (!(child instanceof TextPattern) || hasAnnotations(child)) child.accept(this); end(p); return VoidValue.VOID; } private boolean tryNameAttribute(NameClass nc, boolean isAttribute) { if (hasAnnotations(nc)) return false; if (!(nc instanceof NameNameClass)) return false; NameNameClass nnc = (NameNameClass)nc; String ns = nnc.getNamespaceUri(); if (ns == NameClass.INHERIT_NS) { if (isAttribute || lookupPrefix("") != null) return false; xw.attribute("name", nnc.getLocalName()); return true; } if (ns.length() == 0) { if (!isAttribute && !"".equals(lookupPrefix(""))) return false; xw.attribute("name", nnc.getLocalName()); return true; } String prefix = nnc.getPrefix(); if (prefix == null) { if (isAttribute || !ns.equals(lookupPrefix(""))) return false; xw.attribute("name", nnc.getLocalName()); } else { if (!ns.equals(prefixMap.get(prefix))) xw.attribute("xmlns:" + prefix, ns); xw.attribute("name", prefix + ":" + nnc.getLocalName()); } return true; } public VoidValue visitOneOrMore(OneOrMorePattern p) { return visitUnary("oneOrMore", p); } public VoidValue visitZeroOrMore(ZeroOrMorePattern p) { return visitUnary("zeroOrMore", p); } public VoidValue visitOptional(OptionalPattern p) { return visitUnary("optional", p); } public VoidValue visitInterleave(InterleavePattern p) { return visitComposite("interleave", p); } public VoidValue visitGroup(GroupPattern p) { return visitComposite("group", p); } public VoidValue visitChoice(ChoicePattern p) { return visitComposite("choice", p); } public VoidValue visitGrammar(GrammarPattern p) { leadingAnnotations(p); xw.startElement("grammar"); finishContainer(p, p); return VoidValue.VOID; } public VoidValue visitExternalRef(ExternalRefPattern p) { leadingAnnotations(p); xw.startElement("externalRef"); xw.attribute("href", od.reference(sourceUri, p.getUri())); nsAttribute(p.getNs()); innerAnnotations(p); end(p); return VoidValue.VOID; } public VoidValue visitRef(RefPattern p) { return visitAbstractRef("ref", p); } public VoidValue visitParentRef(ParentRefPattern p) { return visitAbstractRef("parentRef", p); } private VoidValue visitAbstractRef(String name, AbstractRefPattern p) { leadingAnnotations(p); xw.startElement(name); xw.attribute("name", p.getName()); innerAnnotations(p); end(p); return VoidValue.VOID; } public VoidValue visitValue(ValuePattern p) { leadingAnnotations(p); xw.startElement("value"); if (!p.getType().equals("token") || !p.getDatatypeLibrary().equals("")) { xw.attribute("type", p.getType()); if (!p.getDatatypeLibrary().equals(datatypeLibrary)) xw.attribute("datatypeLibrary", p.getDatatypeLibrary()); for (Map.Entry entry : p.getPrefixMap().entrySet()) { String prefix = entry.getKey(); String ns = entry.getValue(); if (prefix.length() == 0) nsAttribute(ns); else if (ns != NameClass.INHERIT_NS && !ns.equals(lookupPrefix(prefix))) xw.attribute("xmlns:" + prefix, ns); } } innerAnnotations(p); xw.text(p.getValue()); end(p); return VoidValue.VOID; } public VoidValue visitData(DataPattern p) { leadingAnnotations(p); xw.startElement("data"); xw.attribute("type", p.getType()); if (!p.getDatatypeLibrary().equals(datatypeLibrary)) xw.attribute("datatypeLibrary", p.getDatatypeLibrary()); innerAnnotations(p); List list = p.getParams(); for (int i = 0, len = list.size(); i < len; i++) { Param param = list.get(i); leadingAnnotations(param); xw.startElement("param"); xw.attribute("name", param.getName()); innerAnnotations(param); xw.text(param.getValue()); end(param); } Pattern except = p.getExcept(); if (except != null) { xw.startElement("except"); implicitChoice(except); xw.endElement(); } end(p); return VoidValue.VOID; } public VoidValue visitMixed(MixedPattern p) { return visitUnary("mixed", p); } public VoidValue visitList(ListPattern p) { return visitUnary("list", p); } public VoidValue visitText(TextPattern p) { return visitNullary("text", p); } public VoidValue visitEmpty(EmptyPattern p) { return visitNullary("empty", p); } public VoidValue visitNotAllowed(NotAllowedPattern p) { return visitNullary("notAllowed", p); } private VoidValue visitNullary(String name, Pattern p) { leadingAnnotations(p); xw.startElement(name); innerAnnotations(p); end(p); return VoidValue.VOID; } private VoidValue visitUnary(String name, UnaryPattern p) { leadingAnnotations(p); xw.startElement(name); innerAnnotations(p); implicitGroup(p.getChild()); end(p); return VoidValue.VOID; } private VoidValue visitComposite(String name, CompositePattern p) { leadingAnnotations(p); xw.startElement(name); innerAnnotations(p); List list = p.getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); end(p); return VoidValue.VOID; } public VoidValue visitChoice(ChoiceNameClass nc) { leadingAnnotations(nc); xw.startElement("choice"); innerAnnotations(nc); List list = nc.getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); end(nc); return VoidValue.VOID; } public VoidValue visitAnyName(AnyNameNameClass nc) { leadingAnnotations(nc); xw.startElement("anyName"); innerAnnotations(nc); visitExcept(nc); end(nc); return VoidValue.VOID; } public VoidValue visitNsName(NsNameNameClass nc) { leadingAnnotations(nc); xw.startElement("nsName"); String saveNs = localNs; localNs = nsAttribute(nc.getNs()); innerAnnotations(nc); visitExcept(nc); localNs = saveNs; end(nc); return VoidValue.VOID; } private void visitExcept(OpenNameClass onc) { NameClass except = onc.getExcept(); if (except == null) return; xw.startElement("except"); implicitChoice(except); xw.endElement(); } public VoidValue visitName(NameNameClass nc) { leadingAnnotations(nc); xw.startElement("name"); String ns = nc.getNamespaceUri(); if (ns == NameClass.INHERIT_NS) { nsAttribute(ns); innerAnnotations(nc); xw.text(nc.getLocalName()); } else { String prefix = nc.getPrefix(); if (prefix == null || ns.length() == 0) { nsAttribute(ns); innerAnnotations(nc); xw.text(nc.getLocalName()); } else { if (!ns.equals(prefixMap.get(prefix))) xw.attribute("xmlns:" + prefix, ns); innerAnnotations(nc); xw.text(prefix + ":" + nc.getLocalName()); } } end(nc); return VoidValue.VOID; } public VoidValue visitDefine(DefineComponent c) { leadingAnnotations(c); String name = c.getName(); if (name == DefineComponent.START) xw.startElement("start"); else { xw.startElement("define"); xw.attribute("name", name); } if (c.getCombine() != null) xw.attribute("combine", c.getCombine().toString()); innerAnnotations(c); if (name == DefineComponent.START) c.getBody().accept(this); else implicitGroup(c.getBody()); end(c); return VoidValue.VOID; } public VoidValue visitDiv(DivComponent c) { leadingAnnotations(c); xw.startElement("div"); finishContainer(c, c); return VoidValue.VOID; } public VoidValue visitInclude(IncludeComponent c) { leadingAnnotations(c); xw.startElement("include"); xw.attribute("href", od.reference(sourceUri, c.getUri())); String saveNs = localNs; localNs = nsAttribute(c.getNs()); finishContainer(c, c); localNs = saveNs; return VoidValue.VOID; } private void finishContainer(Annotated subject, Container container) { innerAnnotations(subject); List list = container.getComponents(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); end(subject); } private void leadingAnnotations(Annotated subject) { annotationChildren(subject.getLeadingComments(), true); } private void innerAnnotations(Annotated subject) { annotationAttributes(subject.getAttributeAnnotations()); annotationChildren(subject.getChildElementAnnotations(), true); } private void outerAnnotations(Annotated subject) { annotationChildren(subject.getFollowingElementAnnotations(), true); } private void annotationAttributes(List list) { for (int i = 0, len = list.size(); i < len; i++) { AttributeAnnotation att = list.get(i); String name = att.getLocalName(); String prefix = att.getPrefix(); xw.attribute(prefix == null ? name : prefix + ":" + name, att.getValue()); } } private void annotationChildren(List list, boolean haveDefaultNamespace) { for (int i = 0, len = list.size(); i < len; i++) { AnnotationChild child = list.get(i); if (child instanceof ElementAnnotation) { ElementAnnotation elem = (ElementAnnotation)child; String name = elem.getLocalName(); String prefix = elem.getPrefix(); if (prefix == null) { xw.startElement(name); if (haveDefaultNamespace) { xw.attribute("xmlns", ""); haveDefaultNamespace = false; } } else xw.startElement(prefix + ":" + name); annotationAttributes(elem.getAttributes()); annotationChildren(elem.getChildren(), haveDefaultNamespace); xw.endElement(); } else if (child instanceof TextAnnotation) xw.text(((TextAnnotation)child).getValue()); else if (child instanceof Comment) xw.comment(fixupComment(((Comment)child).getValue())); } } static private String fixupComment(String comment) { int i = 0; for (;;) { int j = comment.indexOf('-', i); if (j < 0) break; if (j == comment.length() - 1) return comment + " "; if (comment.charAt(j + 1) == '-') return comment.substring(0, j) + "- " + fixupComment(comment.substring(j + 1)); i = j + 1; } return comment; } private void end(Annotated subject) { xw.endElement(); outerAnnotations(subject); } private void implicitGroup(Pattern p) { if (!hasAnnotations(p) && p instanceof GroupPattern) { List list = ((GroupPattern)p).getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); } else p.accept(this); } private void implicitChoice(Pattern p) { if (!hasAnnotations(p) && p instanceof ChoicePattern) { List list = ((ChoicePattern)p).getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); } else p.accept(this); } private void implicitChoice(NameClass nc) { if (!hasAnnotations(nc) && nc instanceof ChoiceNameClass) { List list = ((ChoiceNameClass)nc).getChildren(); for (int i = 0, len = list.size(); i < len; i++) (list.get(i)).accept(this); } else nc.accept(this); } private static boolean hasAnnotations(Annotated subject) { return (!subject.getLeadingComments().isEmpty() || !subject.getAttributeAnnotations().isEmpty() || !subject.getChildElementAnnotations().isEmpty() || !subject.getFollowingElementAnnotations().isEmpty()); } private String nsAttribute(String ns) { if (ns == NameClass.INHERIT_NS) { if (lookupPrefix("") != null) { // cannot do it exactly; this is the best approximation xw.attribute("ns", ""); return ""; } } else if (!ns.equals(lookupPrefix(""))) { xw.attribute("ns", ns); return ns; } return localNs; } private String lookupPrefix(String prefix) { if (prefix.equals("") && localNs != null) return localNs; return prefixMap.get(prefix); } } RngOutputFormat.java000066400000000000000000000026051225366607500347150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rngpackage com.thaiopensource.relaxng.output.rng; import com.thaiopensource.relaxng.edit.SchemaCollection; import com.thaiopensource.relaxng.edit.SchemaDocument; import com.thaiopensource.relaxng.output.OutputDirectory; import com.thaiopensource.relaxng.output.OutputDirectoryParamProcessor; import com.thaiopensource.relaxng.output.OutputFormat; import com.thaiopensource.relaxng.translate.util.InvalidParamsException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.io.IOException; import java.util.Map; public class RngOutputFormat implements OutputFormat { public void output(SchemaCollection sc, OutputDirectory od, String[] params, String inputFormat, ErrorHandler eh) throws IOException, InvalidParamsException, SAXException { new OutputDirectoryParamProcessor(od).process(params, eh); for (Map.Entry entry : sc.getSchemaDocumentMap().entrySet()) { outputPattern(entry.getValue(), entry.getKey(), od); } } private static void outputPattern(SchemaDocument sd, String sourceUri, OutputDirectory od) throws IOException { Analyzer analyzer = new Analyzer(); sd.getPattern().accept(analyzer); Output.output(sd.getPattern(), sd.getEncoding(), sourceUri, od, analyzer.getDatatypeLibrary(), analyzer.getPrefixMap()); } } jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/000077500000000000000000000000001225366607500306555ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/util/000077500000000000000000000000001225366607500316325ustar00rootroot00000000000000AbsoluteUriParam.java000066400000000000000000000010621225366607500356340ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; import com.thaiopensource.util.Uri; public abstract class AbsoluteUriParam extends AbstractParam { public void set(String value) throws InvalidParamValueException { if (!Uri.isValid(value)) throw new ParamProcessor.LocalizedInvalidValueException("invalid_uri"); if (!Uri.isAbsolute(value)) throw new ParamProcessor.LocalizedInvalidValueException("relative_uri"); setAbsoluteUri(value); } protected abstract void setAbsoluteUri(String value) throws InvalidParamValueException; } AbstractParam.java000066400000000000000000000007031225366607500351420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public class AbstractParam implements Param { public boolean allowRepeat() { return false; } public void set(String value) throws InvalidParamValueException, ParamValuePresenceException { throw new ParamValuePresenceException(); } public void set(boolean value) throws InvalidParamValueException, ParamValuePresenceException { throw new ParamValuePresenceException(); } } EncodingParam.java000066400000000000000000000011321225366607500351220ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; import com.thaiopensource.xml.util.EncodingMap; import java.io.UnsupportedEncodingException; public abstract class EncodingParam extends AbstractParam { public void set(String value) throws InvalidParamValueException { try { "x".getBytes(EncodingMap.getJavaName(value)); } catch (UnsupportedEncodingException e) { throw new ParamProcessor.LocalizedInvalidValueException("unsupported_encoding"); } setEncoding(value); } protected abstract void setEncoding(String encoding) throws InvalidParamValueException; } EnumParam.java000066400000000000000000000012301225366607500342770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public abstract class EnumParam extends AbstractParam { private final String[] values; public EnumParam(String[] values) { this.values = values; } public String[] getValues() { return values; } public void set(String value) throws InvalidParamValueException { for (int i = 0; i < values.length; i++) { if (values[i].equals(value)) { setEnum(i); return; } } // XXX more helpful message throw new ParamProcessor.LocalizedInvalidValueException("invalid_enum"); } abstract protected void setEnum(int value) throws InvalidParamValueException; } IntegerParam.java000066400000000000000000000015271225366607500350010ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public abstract class IntegerParam extends AbstractParam { private final int minValue; private final int maxValue; public IntegerParam(int minValue, int maxValue) { this.minValue = minValue; this.maxValue = maxValue; } public IntegerParam() { this(Integer.MIN_VALUE, Integer.MAX_VALUE); } public void set(String value) throws InvalidParamValueException { try { int n = Integer.parseInt(value); if (n < minValue || n > maxValue) throw new ParamProcessor.LocalizedInvalidValueException("out_of_range_integer"); setInteger(n); } catch (NumberFormatException e) { throw new ParamProcessor.LocalizedInvalidValueException("not_an_integer"); } } protected abstract void setInteger(int value) throws InvalidParamValueException; } InvalidParamValueException.java000066400000000000000000000003521225366607500376410ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public class InvalidParamValueException extends Exception { public InvalidParamValueException() { } public InvalidParamValueException(String message) { super(message); } } InvalidParamsException.java000066400000000000000000000001561225366607500370310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public class InvalidParamsException extends Exception { } NCNameParam.java000066400000000000000000000007021225366607500344770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; import com.thaiopensource.xml.util.Naming; public abstract class NCNameParam extends AbstractParam { public void set(String value) throws InvalidParamValueException { if (!Naming.isNcname(value)) throw new ParamProcessor.LocalizedInvalidValueException("invalid_ncname"); setNCName(value); } protected abstract void setNCName(String value) throws InvalidParamValueException; } NmtokenParam.java000066400000000000000000000007071225366607500350160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; import com.thaiopensource.xml.util.Naming; public abstract class NmtokenParam extends AbstractParam { public void set(String value) throws InvalidParamValueException { if (!Naming.isNmtoken(value)) throw new ParamProcessor.LocalizedInvalidValueException("invalid_nmtoken"); setNmtoken(value); } protected abstract void setNmtoken(String value) throws InvalidParamValueException; } Param.java000066400000000000000000000004331225366607500334560ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public interface Param { boolean allowRepeat(); void set(String value) throws InvalidParamValueException, ParamValuePresenceException; void set(boolean value) throws InvalidParamValueException, ParamValuePresenceException; } ParamFactory.java000066400000000000000000000001701225366607500350040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public interface ParamFactory { Param createParam(String name); } ParamProcessor.java000066400000000000000000000063261225366607500353650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; import com.thaiopensource.relaxng.output.common.ErrorReporter; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; public class ParamProcessor { private ErrorReporter er; private ParamFactory paramFactory; private final Map paramMap = new HashMap(); private final Set processedParamNames = new HashSet(); private static class BadParamException extends Exception { } static class LocalizedInvalidValueException extends InvalidParamValueException { private final String key; LocalizedInvalidValueException(String key) { this.key = key; } } public void declare(String name, Param param) { paramMap.put(name, param); } public void setParamFactory(ParamFactory factory) { this.paramFactory = factory; } public void process(String[] params, ErrorHandler eh) throws InvalidParamsException, SAXException { er = new ErrorReporter(eh, ParamProcessor.class); try { for (int i = 0; i < params.length; i++) processParam(params[i]); if (er.getHadError()) throw new InvalidParamsException(); } catch (ErrorReporter.WrappedSAXException e) { throw e.getException(); } finally { processedParamNames.clear(); er = null; } } private void processParam(String param) { int off = param.indexOf('='); String name = null; try { if (off < 0) { if (param.startsWith("no-")) { name = param.substring(3); lookupParam(name).set(false); } else { name = param; lookupParam(name).set(true); } } else { name = param.substring(0, off); lookupParam(name).set(param.substring(off + 1)); } } catch (BadParamException e) { } catch (LocalizedInvalidValueException e) { er.error("invalid_param_value_detail", name, er.getLocalizer().message(e.key), null); } catch (InvalidParamValueException e) { String detail = e.getMessage(); if (detail != null) er.error("invalid_param_value_detail", name, detail, null); else if (off < 0) er.error(param.startsWith("no-") ? "param_only_positive" : "param_only_negative", name, null); else er.error("invalid_param_value", name, null); } catch (ParamValuePresenceException e) { if (off < 0) er.error("param_value_required", name, null); else er.error("param_value_not_allowed", name, null); } } private Param lookupParam(String name) throws BadParamException { Param p = paramMap.get(name); if (p == null && paramFactory != null) p = paramFactory.createParam(name); if (p == null) { er.error("unrecognized_param", name, null); throw new BadParamException(); } if (processedParamNames.contains(name)) { if (!p.allowRepeat()) { er.error("duplicate_param", name, null); throw new BadParamException(); } } else processedParamNames.add(name); return p; } } ParamValuePresenceException.java000066400000000000000000000001631225366607500400170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilpackage com.thaiopensource.relaxng.translate.util; public class ParamValuePresenceException extends Exception { } resources/000077500000000000000000000000001225366607500335655ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/utilMessages.properties000066400000000000000000000015011225366607500374470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/src/main/com/thaiopensource/relaxng/translate/util/resourcesinvalid_param_value_detail=invalid value for parameter \"{0}\": {1} invalid_param_value=invalid value for parameter \"{0}\" param_value_required=parameter \"{0}\" requires a value param_value_not_allowed=parameter \"{0}\" cannot have a value duplicate_param=parameter \"{0}\" must not be specified more than once unrecognized_param=unknown parameter \"{0}\" param_only_positive=only \"{0}\" is allowed; \"no-{0}\" is not allowed param_only_negative=only \"no-{0}\" is allowed; \"{0}\" is not allowed unsupported_encoding=unsupported encoding invalid_uri=not a valid URI relative_uri=must be an absolute URI not a relative URI invalid_ncname=not a valid NCName invalid_nmtoken=contains characters not allowed in an XML name invalid_integer=not a valid integer out_of_range_integer=value out of range invalid_integer=value not allowed jing-trang-20131210+dfsg+1/mod/rng-schema/test/000077500000000000000000000000001225366607500206565ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-schema/test/compacttest.xml000066400000000000000000001541641225366607500237410ustar00rootroot00000000000000 element foo { empty } element foo { text } group interleave choice optional zeroOrMore oneOrMore list mixed ref parentRef empty notAllowed text choice interleave rdf:Description rdf:RDF rdf:ID rdf:about rdf:aboutEach rdf:bagID rdf:parseType rdf:resource rdf:Description rdf:RDF rdf:ID rdf:about rdf:aboutEach rdf:bagID rdf:parseType rdf:resource rdf:type rdf:li rdf:Description rdf:RDF rdf:ID rdf:about rdf:aboutEach rdf:bagID rdf:parseType rdf:resource Literal Resource Literal Resource , except that # John Cowan retains the moral right to be known as the author. # This is draft 6.2 # Diff from 6.1: rel|rel now rel|rev, th|td@headers now IDREFS, # table width no longer an integer, non-basic table attrs gone, # rowspan and colspan must be non-negative # Diff from 6.0: added attributes to ul, comment about img, new meta # This is a RELAX NG schema which describes a subset of XHTML Basic for # use within other schemas. It is by intention equivalent # (within its scope) to -//W3C//DTD XHTML 1.1//EN, but is # not a derived work in the copyright sense. # It is often convenient for XML documents to have a bit of # documentation somewhere in them. In the absence of a schema like # this one, that documentation winds up being only, which is # a pity, because rich text adds measurably to the readability of # documents. By incorporating this schema by reference (as an # external parameter entity) into another schema, that schema inherits # the capabilities of this one. Using HTML-compatible elements # and attributes allows the documentation to be passed straight # through to HTML renderers. # Current HTML renderers can cope with most XML tags, but empty # tags require special treatment. Inserting a space before the # terminating "/>" usually makes the "/" (which is not HTML) # invisible. Using "" is not as effective, as the # latter is often misinterpreted as a second "". # Note that since the elements of this schema are intended to be # used within domain-specific elements of the surrounding DTD, # it is not necessary that every fragment begin with an "html" # element, as in HTML. Recommended s for elements # containing documentation are "horiz.model" for simple # text fragments and "struct.model" for documents in extenso. # Common attributes # All elements (except full-document elements) can have these attributes all = attribute id {xsd:ID}?, attribute class {token}?, attribute title {text}? # All non-empty elements can have these attributes i18n = attribute xml:lang {text}?, attribute dir {"ltr" | "rtl"}? basic = all, i18n # Models t = text horiz.model = basic & t & horiz* vert.model = vert* & horiz.model struct.model = basic & vert* # Horizontal formatting elements horiz = a | br | horiz.other a = element a { attribute href {xsd:anyURI}?, attribute name {text}?, attribute rel | rev {xsd:anyURI}?, horiz.model } br = element br {all, empty} horiz.other = element abbr | acronym | cite | code | dfn | em | img | kbd | q | samp | span | strong | var {horiz.model} # Vertical formatting elements vert = header | List | table | vert.other header = element h1 | h2 | h3 {horiz.model} List = element dl {basic, element dt | dd {horiz.model}+ } | element ol|ul {basic, element li {horiz.model}+ } aligns = attribute align {"left" | "center" | "right" | "justified"}?, attribute valign {"top" | "middle" | "bottom" | "baseline"}? table = element table { basic, attribute summary {text}?, element caption {horiz.model}?, element tr { basic, aligns, tabledata+}+ } tabledata = element th | td { aligns, attribute abbr {text}?, attribute axis {text}?, attribute colspan {xsd:nonNegativeInteger}?, attribute headers {xsd:IDREFS}?, attribute rowspan {xsd:nonNegativeInteger}?, attribute scope {"row" | "col" | "rowgroup" | "colgroup"}?, vert.model } vert.other = element address {horiz.model} | element blockquote {attribute cite {xsd:anyURI}?, struct.model} | element div {struct.model} | element p {horiz.model} | element pre {horiz.model} # Support for complete HTML documents start = element html { i18n, attribute xml:base {xsd:anyURI}?, attribute xml:space {"preserve" | "default"}?, head, element body {basic, vert*} } head = element head { i18n, element title {i18n, text}, element meta { attribute name|http-equiv {token}?, attribute content {text}, empty }* } # END OF ibtwsh.rnc ]]> ltr rtl rel rev abbr acronym cite code dfn em img kbd q samp span strong var h1 h2 h3 dt dd ol ul left center right justified top middle bottom baseline th td row col rowgroup colgroup preserve default name http-equiv foo \x{65}l\xxxxx{00065}ment\x{20}foo { empty \x{7d} element foo { "\x{10300}" } 𐌀 element foo { "฀" } element foo { """z """ } z element foo { "z\x{A}" } z element foo { "z\x{D}" } z element foo { "z\x{D}\x{A}" } z '" xyzzy foo|bar This is a comment about a foo. This is a comment about a foo. This is a formal comment about a foo. This is a formal comment about a foo. This is a formal comment foo start = element foo { empty }

    xyzzy xyzzy "'x''""y val
    foo = empty
    > x[]) >> y[] } ]]> > x[]) >> y[] } ]]> x > x[] ]]> 13 2 foo default preserve start = element foo { grammar { start = element bar { text }, element doh {text} } } jing-trang-20131210+dfsg+1/mod/rng-validate/000077500000000000000000000000001225366607500202305ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/mod.xml000066400000000000000000000011121225366607500215240ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/rng-validate/src/000077500000000000000000000000001225366607500210175ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/000077500000000000000000000000001225366607500217435ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/000077500000000000000000000000001225366607500225215ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/000077500000000000000000000000001225366607500255515ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500272115ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/SchemaFactory.java000066400000000000000000000222261225366607500326100ustar00rootroot00000000000000package com.thaiopensource.relaxng; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.Flag; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.xml.sax.XMLReaderCreator; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; /** * A factory for RELAX NG schemas. The factory creates Schema objects from their * XML representation. * * A single SchemaFactory is not safe for concurrent * access by multiple threads; it must be accessed by at most one thread at a time. * Schemas can be created concurrently by using a distinct SchemaFactory for each * thread. However, the Schema objects created are safe for concurrent * access by multiple threads. * * @author James Clark */ public class SchemaFactory { private PropertyMapBuilder properties = new PropertyMapBuilder(); private boolean compactSyntax = false; private SchemaReader autoSchemaLanguage = new AutoSchemaReader(); /** * Constructs a schema factory. */ public SchemaFactory() { } /** * Creates a schema by parsing an XML document. A non-null XMLReaderCreator must be specified * with setXMLReaderCreator before calling createSchema. The ErrorHandler * is allowed to be null. The DatatypeLibraryFactory is allowed to be null. * *

    Normally, if a schema cannot be created, createSchema will throw * a IncorrectSchemaException; however, * before doing so, one or more errors will be reported using the ErrorHandler if it is non-null. If the * ErrorHandler throws a SAXException, then createSchema will pass this * through rather than throwing a IncorrectSchemaException. Similarly, if XMLReader.parse * throws a SAXException or IOException, then createSchema will pass * this through rather than throwing a IncorrectSchemaException. Thus, if an error handler * is specified that reports errors to the user, there is no need to report any additional message to the * user if createSchema throws IncorrectSchemaException. * * @param in the InputSource containing the XML document to be parsed; * must not be null * @return the Schema constructed from the XML document; * never null. * * @throws IOException if an I/O error occurs * @throws SAXException if there is an XML parsing error and the XMLReader or ErrorHandler * throws a SAXException * @throws com.thaiopensource.validate.IncorrectSchemaException if the XML document was not a correct RELAX NG schema * @throws NullPointerException if the current XMLReaderCreator is null */ public Schema createSchema(InputSource in) throws IOException, SAXException, IncorrectSchemaException { SchemaReader r = compactSyntax ? CompactSchemaReader.getInstance() : autoSchemaLanguage; return r.createSchema(in, properties.toPropertyMap()); } /** * Specifies the XMLReaderCreator to be used for creating XMLReaders for parsing * the XML document. Because of include and externalRef elements, * parsing a single RELAX NG may require the creation of multiple more than one XMLReader. * A non-null XMLReaderCreator must be specified before calling createSchema. * * @param xrc the XMLReaderCreator to be used for parsing the XML document containing * the schema; may be null * @see #getXMLReaderCreator */ public void setXMLReaderCreator(XMLReaderCreator xrc) { properties.put(ValidateProperty.XML_READER_CREATOR, xrc); } /** * Returns the current XMLReaderCreator as specified by setXMLReaderCreator. * If XMLReaderCreator has never been called, then getXMLReaderCreator * returns null. * * @return the XMLReaderCreator that will be used for parsing the XML document containing * the schema; may be null * * @see #setXMLReaderCreator */ public XMLReaderCreator getXMLReaderCreator() { return (XMLReaderCreator)properties.get(ValidateProperty.XML_READER_CREATOR); } /** * Specifies the ErrorHandler to be used for reporting errors while creating the schema. * This does not affect the error handler used for validation. * * @param eh the ErrorHandler to be used for reporting errors while creating the schema; * may be null. * @see #getErrorHandler */ public void setErrorHandler(ErrorHandler eh) { properties.put(ValidateProperty.ERROR_HANDLER, eh); } /** * Returns the ErrorHandler that will be used for reporting errors while creating the * schema. If setErrorHandler has not been called for this SchemaFactory, * then getErrorHandler returns null. * * @return the ErrorHandler to be used for reporting errors while creating the schema; * may be null. * @see #setErrorHandler */ public ErrorHandler getErrorHandler() { return (ErrorHandler)properties.get(ValidateProperty.ERROR_HANDLER); } /** * Specifies the DatatypeLibraryFactory to be used for handling datatypes in the schema. * This also determines how datatypes are handled during validation. If null is * specified then only the builtin datatypes will be supported. * * @param dlf the DatatypeLibraryFactory to be used for handling datatypes in the schema * @see #getDatatypeLibraryFactory */ public void setDatatypeLibraryFactory(DatatypeLibraryFactory dlf) { properties.put(RngProperty.DATATYPE_LIBRARY_FACTORY, dlf); } /** * Returns the DatatypeLibraryFactory that will be used for handling datatypes in the * schema. If setDatatypeLibraryFactory has not been called for this SchemaFactory, * then getDatatypeLibraryFactory returns null. * * @return the DatatypeLibraryFactory to be used for handling datatypes in the schema; * may be null. * @see #setDatatypeLibraryFactory */ public DatatypeLibraryFactory getDatatypeLibraryFactory() { return (DatatypeLibraryFactory)properties.get(RngProperty.DATATYPE_LIBRARY_FACTORY); } /** * Specifies whether to perform checking of ID/IDREF/IDREFS attributes in accordance with * RELAX NG DTD Compatibility. * * @param checkIdIdref true if ID/IDREF/IDREFS checking should be performed; * false otherwise * * @see #getCheckIdIdref * @see RELAX NG DTD Compatibility */ public void setCheckIdIdref(boolean checkIdIdref) { properties.put(RngProperty.CHECK_ID_IDREF, checkIdIdref ? Flag.PRESENT : null); } /** * Indicates whether ID/IDREF/IDREFS attributes will be checked in accordance RELAX NG DTD * Compatibility. If setCheckIdIdref has not been called for this SchemaFactory, * then getCheckIdref will return false. * * @return true if ID/IDREF/IDREFS attributes will be checked; * false otherwise. * * @see #setCheckIdIdref * @see RELAX NG DTD Compatibility */ public boolean getCheckIdIdref() { return properties.contains(RngProperty.CHECK_ID_IDREF); } /** * Specifies whether to use the compact syntax to parse the RELAX NG schema rather than the normal XML syntax. * * @param compactSyntax true if the compact syntax should be used; false * if the XML syntax should be used * @see #getCompactSyntax */ public void setCompactSyntax(boolean compactSyntax) { this.compactSyntax = compactSyntax; } /** * Indicates whether the compact syntax will be used to parse the RELAX NG schema rather than * the normal XML syntax. * * @return true if the compact syntax will be used; false if the XML * syntax will be used */ public boolean getCompactSyntax() { return compactSyntax; } public void setFeasible(boolean feasible) { properties.put(RngProperty.FEASIBLE, feasible ? Flag.PRESENT : null); } public boolean getFeasible() { return properties.contains(RngProperty.FEASIBLE); } } jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/package.html000066400000000000000000000006701225366607500314750ustar00rootroot00000000000000 Provides a SAX-based API for validating XML documents using RELAX NG. @see RELAX NG Specification @see RELAX NG Tutorial @see RELAX NG DTD Compatibility @see SAX jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/000077500000000000000000000000001225366607500301665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/Driver.java000066400000000000000000000136771225366607500323020ustar00rootroot00000000000000package com.thaiopensource.relaxng.util; import com.thaiopensource.resolver.catalog.CatalogResolver; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.OptionParser; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.util.UriOrFile; import com.thaiopensource.util.Version; import com.thaiopensource.validate.Flag; import com.thaiopensource.validate.FlagOption; import com.thaiopensource.validate.OptionArgumentException; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.StringOption; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.ValidationDriver; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.xml.sax.ErrorHandlerImpl; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; import java.util.ArrayList; import java.util.List; class Driver { static private String usageKey = "usage"; static public void setUsageKey(String key) { usageKey = key; } static public void main(String[] args) { System.exit(new Driver().doMain(args)); } private boolean timing = false; private String encoding = null; private Localizer localizer = new Localizer(Driver.class); public int doMain(String[] args) { ErrorHandlerImpl eh = new ErrorHandlerImpl(System.out); OptionParser op = new OptionParser("itcdfe:p:sC:", args); PropertyMapBuilder properties = new PropertyMapBuilder(); properties.put(ValidateProperty.ERROR_HANDLER, eh); RngProperty.CHECK_ID_IDREF.add(properties); SchemaReader sr = null; boolean compact = false; boolean outputSimplifiedSchema = false; List catalogUris = new ArrayList(); try { while (op.moveToNextOption()) { switch (op.getOptionChar()) { case 'i': properties.put(RngProperty.CHECK_ID_IDREF, null); break; case 'C': catalogUris.add(UriOrFile.toUri(op.getOptionArg())); break; case 'c': compact = true; break; case 'd': { if (sr == null) sr = new AutoSchemaReader(); FlagOption option = (FlagOption)sr.getOption(SchemaReader.BASE_URI + "diagnose"); if (option == null) { eh.print(localizer.message("no_schematron", op.getOptionCharString())); return 2; } properties.put(option.getPropertyId(), Flag.PRESENT); } break; case 't': timing = true; break; case 'e': encoding = op.getOptionArg(); break; case 'f': RngProperty.FEASIBLE.add(properties); break; case 's': outputSimplifiedSchema = true; break; case 'p': { if (sr == null) sr = new AutoSchemaReader(); StringOption option = (StringOption)sr.getOption(SchemaReader.BASE_URI + "phase"); if (option == null) { eh.print(localizer.message("no_schematron", op.getOptionCharString())); return 2; } try { properties.put(option.getPropertyId(), option.valueOf(op.getOptionArg())); } catch (OptionArgumentException e) { eh.print(localizer.message("invalid_phase", op.getOptionArg())); return 2; } } break; } } } catch (OptionParser.InvalidOptionException e) { eh.print(localizer.message("invalid_option", op.getOptionCharString())); return 2; } catch (OptionParser.MissingArgumentException e) { eh.print(localizer.message("option_missing_argument", op.getOptionCharString())); return 2; } if (!catalogUris.isEmpty()) { try { properties.put(ValidateProperty.RESOLVER, new CatalogResolver(catalogUris)); } catch (LinkageError e) { eh.print(localizer.message("resolver_not_found")); return 2; } } if (compact) sr = CompactSchemaReader.getInstance(); args = op.getRemainingArgs(); if (args.length < 1) { eh.print(localizer.message(usageKey, Version.getVersion(Driver.class))); return 2; } long startTime = System.currentTimeMillis(); long loadedPatternTime = -1; boolean hadError = false; try { ValidationDriver driver = new ValidationDriver(properties.toPropertyMap(), sr); InputSource in = ValidationDriver.uriOrFileInputSource(args[0]); if (encoding != null) in.setEncoding(encoding); if (driver.loadSchema(in)) { loadedPatternTime = System.currentTimeMillis(); if (outputSimplifiedSchema) { String simplifiedSchema = driver.getSchemaProperties().get(RngProperty.SIMPLIFIED_SCHEMA); if (simplifiedSchema == null) { eh.print(localizer.message("no_simplified_schema")); hadError = true; } else System.out.print(simplifiedSchema); } for (int i = 1; i < args.length; i++) { if (!driver.validate(ValidationDriver.uriOrFileInputSource(args[i]))) hadError = true; } } else hadError = true; } catch (SAXException e) { hadError = true; eh.printException(e); } catch (IOException e) { hadError = true; eh.printException(e); } if (timing) { long endTime = System.currentTimeMillis(); if (loadedPatternTime < 0) loadedPatternTime = endTime; eh.print(localizer.message("elapsed_time", new Object[] { loadedPatternTime - startTime, endTime - loadedPatternTime, endTime - startTime })); } if (hadError) return 1; return 0; } } jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/JingTask.java000066400000000000000000000120001225366607500325340ustar00rootroot00000000000000package com.thaiopensource.relaxng.util; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.Flag; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.ValidationDriver; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.prop.schematron.SchematronProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.xml.sax.ErrorHandlerImpl; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Ant task to validate XML files using RELAX NG or other schema languages. */ public class JingTask extends Task { private File schemaFile; private File src; private final List filesets = new ArrayList(); private PropertyMapBuilder properties = new PropertyMapBuilder(); private boolean failOnError = true; private SchemaReader schemaReader = null; private class LogErrorHandler extends ErrorHandlerImpl { int logLevel = Project.MSG_ERR; public void warning(SAXParseException e) throws SAXParseException { logLevel = Project.MSG_WARN; super.warning(e); } public void error(SAXParseException e) { logLevel = Project.MSG_ERR; super.error(e); } public void printException(Throwable e) { logLevel = Project.MSG_ERR; super.printException(e); } public void print(String message) { log(message, logLevel); } } public JingTask() { RngProperty.CHECK_ID_IDREF.add(properties); } public void execute() throws BuildException { if (schemaFile == null) throw new BuildException("There must be an rngFile or schemaFile attribute", getLocation()); if (src == null && filesets.size() == 0) throw new BuildException("There must be a file attribute or a fileset child element", getLocation()); ErrorHandlerImpl eh = new LogErrorHandler(); boolean hadError = false; try { ValidationDriver driver = new ValidationDriver(properties.toPropertyMap(), schemaReader); if (!driver.loadSchema(ValidationDriver.fileInputSource(schemaFile))) hadError = true; else { if (src != null) { if (!driver.validate(ValidationDriver.fileInputSource(src))) hadError = true; } for (int i = 0; i < filesets.size(); i++) { FileSet fs = (FileSet)filesets.get(i); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); File dir = fs.getDir(getProject()); String[] srcs = ds.getIncludedFiles(); for (int j = 0; j < srcs.length; j++) { if (!driver.validate(ValidationDriver.fileInputSource(new File(dir, srcs[j])))) hadError = true; } } } } catch (SAXException e) { hadError = true; eh.printException(e); } catch (IOException e) { hadError = true; eh.printException(e); } if (hadError && failOnError) throw new BuildException("Validation failed, messages should have been provided.", getLocation()); } /** * Handles the rngfile attribute. * * @param rngFilename the attribute value */ public void setRngfile(String rngFilename) { schemaFile = getProject().resolveFile(rngFilename); } /** * Handles the schemafile attribute. * * @param schemaFilename the attribute value */ public void setSchemafile(String schemaFilename) { schemaFile = getProject().resolveFile(schemaFilename); } public void setFile(File file) { this.src = file; } /** * Handles the checkid attribute. * * @param checkid the attribute value converted to a boolean */ public void setCheckid(boolean checkid) { properties.put(RngProperty.CHECK_ID_IDREF, checkid ? Flag.PRESENT : null); } /** * Handles the compactsyntax attribute. * * @param compactsyntax the attribute value converted to a boolean */ public void setCompactsyntax(boolean compactsyntax) { schemaReader = compactsyntax ? CompactSchemaReader.getInstance() : null; } /** * Handles the feasible attribute. * * @param feasible the attribute value converted to a boolean */ public void setFeasible(boolean feasible) { properties.put(RngProperty.FEASIBLE, feasible ? Flag.PRESENT : null); } /** * Handles the phase attribute. * * @param phase the attribute value */ public void setPhase(String phase) { properties.put(SchematronProperty.PHASE, phase); } /** * Handles the failonerror attribute. * * @param failOnError the attribute value converted to a boolean */ public void setFailonerror(boolean failOnError) { this.failOnError = failOnError; } public void addFileset(FileSet set) { filesets.add(set); } } jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/TestDriver.java000066400000000000000000000106471225366607500331340ustar00rootroot00000000000000package com.thaiopensource.relaxng.util; import com.thaiopensource.util.OptionParser; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.util.Localizer; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.ValidationDriver; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.xml.sax.ErrorHandlerImpl; import com.thaiopensource.datatype.DatatypeLibraryLoader; import org.xml.sax.SAXException; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; class TestDriver { static public void main(String[] args) throws IOException { System.exit(new TestDriver().doMain(args)); } private ValidationDriver driver; private ErrorHandlerImpl eh; private Localizer localizer = new Localizer(TestDriver.class); private int nTests = 0; public int doMain(String[] args) throws IOException { long startTime = System.currentTimeMillis(); eh = new ErrorHandlerImpl(System.out); OptionParser op = new OptionParser("i", args); PropertyMapBuilder properties = new PropertyMapBuilder(); // This is an optimization. It ensures that all SchemaReaders share a // single DatatypeLibraryLoader. properties.put(RngProperty.DATATYPE_LIBRARY_FACTORY, new DatatypeLibraryLoader()); try { while (op.moveToNextOption()) { switch (op.getOptionChar()) { case 'i': RngProperty.CHECK_ID_IDREF.add(properties); break; } } } catch (OptionParser.InvalidOptionException e) { eh.print(localizer.message("invalid_option", op.getOptionCharString())); return 2; } catch (OptionParser.MissingArgumentException e) { eh.print(localizer.message("option_missing_argument", op.getOptionCharString())); return 2; } args = op.getRemainingArgs(); eh = new ErrorHandlerImpl(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(args[0])))); properties.put(ValidateProperty.ERROR_HANDLER, eh); driver = new ValidationDriver(properties.toPropertyMap()); int result = 0; for (int i = 1; i < args.length; i++) { int n = runTestSuite(new File(args[i])); if (n > result) result = n; } System.err.println("Number of tests: " + nTests); System.err.println("Elapsed time: " + (System.currentTimeMillis() - startTime)); eh.close(); return result; } private static final String CORRECT_SCHEMA_NAME = "c.rng"; private static final String INCORRECT_SCHEMA_NAME = "i.rng"; private static final String VALID_INSTANCE_SUFFIX = ".v.xml"; private static final String INVALID_INSTANCE_SUFFIX = ".i.xml"; public int runTestSuite(File dir) throws IOException { int result = 0; String[] subdirs = dir.list(); for (int i = 0; i < subdirs.length; i++) { File subdir = new File(dir, subdirs[i]); if (subdir.isDirectory()) { int n = runTestCase(subdir); if (n > result) result = n; } } return result; } private int runTestCase(File dir) throws IOException { File f = new File(dir, INCORRECT_SCHEMA_NAME); if (f.exists()) { if (loadSchema(f)) { failed(f); return 1; } return 0; } f = new File(dir, CORRECT_SCHEMA_NAME); if (!f.exists()) return 0; if (!loadSchema(f)) { failed(f); return 1; } String[] files = dir.list(); int result = 0; for (int i = 0; i < files.length; i++) { if (files[i].endsWith(VALID_INSTANCE_SUFFIX)) { f = new File(dir, files[i]); if (!validateInstance(f)) { failed(f); result = 1; } } else if (files[i].endsWith(INVALID_INSTANCE_SUFFIX)) { f = new File(dir, files[i]); if (validateInstance(f)) { failed(f); result = 1; } } } return result; } private static void failed(File f) { System.err.println("Failed: " + f.toString()); } private boolean loadSchema(File schema) throws IOException { nTests++; try { if (driver.loadSchema(ValidationDriver.fileInputSource(schema))) return true; } catch (SAXException e) { eh.printException(e); } return false; } private boolean validateInstance(File instance) throws IOException { nTests++; try { if (driver.validate(ValidationDriver.fileInputSource(instance))) return true; } catch (SAXException e) { eh.printException(e); } return false; } } ValidationEngine.java000066400000000000000000000117311225366607500341750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/utilpackage com.thaiopensource.relaxng.util; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.ValidationDriver; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.xml.sax.XMLReaderCreator; import com.thaiopensource.xml.sax.Sax2XMLReaderCreator; import org.xml.sax.ErrorHandler; /** * Provides a compatibility wrapper around ValidationDriver. New applications * should use ValidationDriver directly. * * @author James Clark * @see ValidationDriver * @deprecated */ public class ValidationEngine extends ValidationDriver { /** * Flag indicating that ID/IDREF/IDREFS should be checked. * @see RngProperty#CHECK_ID_IDREF */ public static final int CHECK_ID_IDREF = 01; /** * Flag indicating that the schema is in the RELAX NG compact syntax rather than the XML syntax. * @see CompactSchemaReader */ public static final int COMPACT_SYNTAX = 02; /** * @see RngProperty#FEASIBLE */ public static final int FEASIBLE = 04; /** * Default constructor. Equivalent to ValidationEngine(null, null, CHECK_ID_IDREF). */ public ValidationEngine() { this(null, null, CHECK_ID_IDREF); } /** * Constructs a ValidationEngine. * * @param xrc the XMLReaderCreator to be used for constructing XMLReaders; * if null uses Sax2XMLReaderCreator * @param eh the ErrorHandler to be used for reporting errors; if null * uses DraconianErrorHandler * @param flags bitwise OR of flags selected from CHECK_ID_IDREF, COMPACT_SYNTAX, * FEASIBLE, MNS * @see com.thaiopensource.xml.sax.DraconianErrorHandler * @see com.thaiopensource.xml.sax.Sax2XMLReaderCreator * @see #CHECK_ID_IDREF * @see #COMPACT_SYNTAX * @see #FEASIBLE */ public ValidationEngine(XMLReaderCreator xrc, ErrorHandler eh, int flags) { super(makePropertyMap(xrc, eh, flags), (flags & COMPACT_SYNTAX) == 0 ? null : CompactSchemaReader.getInstance()); } private static PropertyMap makePropertyMap(XMLReaderCreator xrc, ErrorHandler eh, int flags) { PropertyMapBuilder builder = new PropertyMapBuilder(); if (xrc == null) xrc = new Sax2XMLReaderCreator(); builder.put(ValidateProperty.XML_READER_CREATOR, xrc); if (eh != null) builder.put(ValidateProperty.ERROR_HANDLER, eh); if ((flags & CHECK_ID_IDREF) != 0) RngProperty.CHECK_ID_IDREF.add(builder); if ((flags & FEASIBLE) != 0) RngProperty.FEASIBLE.add(builder); return builder.toPropertyMap(); } /** * Constructs a ValidationEngine. * * @param xrc the XMLReaderCreator to be used for constructing XMLReaders; * if null uses Sax2XMLReaderCreator * @param eh the ErrorHandler to be used for reporting errors; if null * uses DraconianErrorHandler * @param checkIdIdref true if ID/IDREF/IDREFS should be checked; false otherwise * @see com.thaiopensource.xml.sax.DraconianErrorHandler * @see com.thaiopensource.xml.sax.Sax2XMLReaderCreator */ public ValidationEngine(XMLReaderCreator xrc, ErrorHandler eh, boolean checkIdIdref) { this(xrc, eh, checkIdIdref ? CHECK_ID_IDREF : 0); } /** * Constructs a ValidationEngine. * * @param xrc the XMLReaderCreator to be used for constructing XMLReaders; * if null uses Sax2XMLReaderCreator * @param eh the ErrorHandler to be used for reporting errors; if null * uses DraconianErrorHandler * @param checkIdIdref true if ID/IDREF/IDREFS should be checked; false otherwise * @param compactSyntax true if the RELAX NG compact syntax should be used to parse the schema; * false if the XML syntax should be used * @see com.thaiopensource.xml.sax.DraconianErrorHandler * @see com.thaiopensource.xml.sax.Sax2XMLReaderCreator */ public ValidationEngine(XMLReaderCreator xrc, ErrorHandler eh, boolean checkIdIdref, boolean compactSyntax) { this(xrc, eh, (checkIdIdref ? CHECK_ID_IDREF : 0) | (compactSyntax ? COMPACT_SYNTAX : 0)); } public ValidationEngine(XMLReaderCreator xrc, ErrorHandler eh, boolean checkIdIdref, boolean compactSyntax, boolean feasible) { this(xrc, eh, (checkIdIdref ? CHECK_ID_IDREF : 0) | (compactSyntax ? COMPACT_SYNTAX : 0) | (feasible ? FEASIBLE : 0)); } } jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/package.html000066400000000000000000000001611225366607500324450ustar00rootroot00000000000000 Provides convenience classes for working with the API in com.thaiopensource.relaxng. jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/resources/000077500000000000000000000000001225366607500322005ustar00rootroot00000000000000Messages.properties000066400000000000000000000015461225366607500360140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/relaxng/util/resourcesno_schematron=option \"-{0}\" is only applicable to Schematron, but this version of Jing does not support Schematron invalid_phase=\"{0}\" is not a valid Schematron phase name elapsed_time=Elapsed time {0,number,#}+{1,number,#}={2,number,#} milliseconds option_missing_argument=option \"-{0}\" requires an argument invalid_option=invalid option \"-{0}\" no_simplified_schema=simplified schemas are only available for RELAX NG schemas resolver_not_found=Use of catalogs requires Apache XML Commons Resolver v1.2.\n\ Download from .\n\ Then put resolver.jar in the same directory as jing.jar. usage=Jing version {0}\n\ usage: java com.thaiopensource.relaxng.util.Driver [-i] [-c] [-s] [-t] [-C catalogFile] [-e encoding] RNGFile XMLFile...\n\ RELAX NG is a schema language for XML\n\ See http://relaxng.org/ for more information. jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/000077500000000000000000000000001225366607500273425ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/000077500000000000000000000000001225366607500301305ustar00rootroot00000000000000CompactSchemaReader.java000066400000000000000000000026161225366607500345530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rngpackage com.thaiopensource.validate.rng; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.compact.CompactParseable; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.VoidValue; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.rng.impl.SchemaReaderImpl; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; public class CompactSchemaReader extends SchemaReaderImpl { private static final SchemaReader theInstance = new CompactSchemaReader(); private CompactSchemaReader() { } public static SchemaReader getInstance() { return theInstance; } protected Parseable createParseable(SAXSource source, SAXResolver saxResolver, ErrorHandler eh, PropertyMap properties) { return new CompactParseable(SAX.createInput(source.getInputSource()), saxResolver.getResolver(), eh); } } SAXSchemaReader.java000066400000000000000000000027031225366607500336150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rngpackage com.thaiopensource.validate.rng; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.sax.SAXParseable; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.rng.impl.SchemaReaderImpl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.VoidValue; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; public class SAXSchemaReader extends SchemaReaderImpl { private static final SchemaReader theInstance = new SAXSchemaReader(); private SAXSchemaReader() { } public static SchemaReader getInstance() { return theInstance; } protected Parseable createParseable(SAXSource source, SAXResolver resolver, ErrorHandler eh, PropertyMap properties) throws SAXException { if (source.getXMLReader() == null) source = new SAXSource(resolver.createXMLReader(), source.getInputSource()); return new SAXParseable(source, resolver, eh); } } SAXSchemaReceiverFactory.java000066400000000000000000000024701225366607500355100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rngpackage com.thaiopensource.validate.rng; import com.thaiopensource.relaxng.parse.sax.SAXParseReceiver; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.ResolverFactory; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.rng.impl.SchemaReceiverImpl; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.xml.sax.ErrorHandler; public class SAXSchemaReceiverFactory implements SchemaReceiverFactory { public SchemaReceiver createSchemaReceiver(String namespaceUri, PropertyMap properties) { // XXX allow namespaces with incorrect version if (!WellKnownNamespaces.RELAX_NG.equals(namespaceUri)) return null; SAXResolver resolver = ResolverFactory.createResolver(properties); ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); return new SchemaReceiverImpl(new SAXParseReceiver(resolver, eh), properties); } public Option getOption(String uri) { return RngProperty.getOption(uri); } } jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/impl/000077500000000000000000000000001225366607500310715ustar00rootroot00000000000000FeasibleIdTypeMapSchema.java000066400000000000000000000014661225366607500362740ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.relaxng.pattern.IdTypeMap; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import org.xml.sax.ErrorHandler; public class FeasibleIdTypeMapSchema extends AbstractSchema { private final IdTypeMap idTypeMap; public FeasibleIdTypeMapSchema(IdTypeMap idTypeMap, PropertyMap properties) { super(properties); this.idTypeMap = idTypeMap; } public Validator createValidator(PropertyMap properties) { ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); return new IdValidator(idTypeMap, eh) { public void endDocument() { setComplete(); } }; } } IdTypeMapSchema.java000066400000000000000000000013341225366607500346330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.relaxng.pattern.IdTypeMap; import org.xml.sax.ErrorHandler; public class IdTypeMapSchema extends AbstractSchema { private final IdTypeMap idTypeMap; public IdTypeMapSchema(IdTypeMap idTypeMap, PropertyMap properties) { super(properties); this.idTypeMap = idTypeMap; } public Validator createValidator(PropertyMap properties) { ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); return new IdValidator(idTypeMap, eh); } } IdValidator.java000066400000000000000000000012041225366607500340540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.relaxng.pattern.IdTypeMap; import com.thaiopensource.relaxng.sax.IdContentHandler; import com.thaiopensource.validate.Validator; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.ErrorHandler; public class IdValidator extends IdContentHandler implements Validator { public IdValidator(IdTypeMap idTypeMap, ErrorHandler eh) { super(idTypeMap, eh); } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return null; } public void reset() { super.reset(); } } PatternSchema.java000066400000000000000000000016741225366607500344230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import org.xml.sax.ErrorHandler; public class PatternSchema extends AbstractSchema { private final SchemaPatternBuilder spb; private final Pattern start; public PatternSchema(SchemaPatternBuilder spb, Pattern start, PropertyMap properties) { super(properties); this.spb = spb; this.start = start; } public Validator createValidator(PropertyMap properties) { ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); return new RngValidator(start, new ValidatorPatternBuilder(spb), eh); } } RngValidator.java000066400000000000000000000013531225366607500342530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.relaxng.sax.PatternValidator; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.validate.Validator; import org.xml.sax.ErrorHandler; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; public class RngValidator extends PatternValidator implements Validator { public RngValidator(Pattern pattern, ValidatorPatternBuilder builder, ErrorHandler eh) { super(pattern, builder, eh); } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return this; } public void reset() { super.reset(); } } SchemaReaderImpl.java000066400000000000000000000123161225366607500350250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.FeasibleTransform; import com.thaiopensource.relaxng.pattern.IdTypeMap; import com.thaiopensource.relaxng.pattern.IdTypeMapBuilder; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.PatternDumper; import com.thaiopensource.relaxng.pattern.SchemaBuilderImpl; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.util.PropertyId; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.VoidValue; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.AbstractSchemaReader; import com.thaiopensource.validate.CombineSchema; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Option; import com.thaiopensource.validate.ResolverFactory; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.prop.wrap.WrapProperty; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import javax.xml.transform.sax.SAXSource; import java.io.IOException; public abstract class SchemaReaderImpl extends AbstractSchemaReader { private static final PropertyId[] supportedPropertyIds = { ValidateProperty.XML_READER_CREATOR, ValidateProperty.ERROR_HANDLER, ValidateProperty.ENTITY_RESOLVER, ValidateProperty.URI_RESOLVER, ValidateProperty.RESOLVER, RngProperty.DATATYPE_LIBRARY_FACTORY, RngProperty.CHECK_ID_IDREF, RngProperty.FEASIBLE, WrapProperty.ATTRIBUTE_OWNER, }; public Schema createSchema(SAXSource source, PropertyMap properties) throws IOException, SAXException, IncorrectSchemaException { SchemaPatternBuilder spb = new SchemaPatternBuilder(); SAXResolver resolver = ResolverFactory.createResolver(properties); ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); DatatypeLibraryFactory dlf = properties.get(RngProperty.DATATYPE_LIBRARY_FACTORY); if (dlf == null) dlf = new DatatypeLibraryLoader(); try { Pattern start = SchemaBuilderImpl.parse(createParseable(source, resolver, eh, properties), eh, dlf, spb, properties.contains(WrapProperty.ATTRIBUTE_OWNER)); return wrapPattern(start, spb, properties); } catch (IllegalSchemaException e) { throw new IncorrectSchemaException(); } } public Option getOption(String uri) { return RngProperty.getOption(uri); } static private class SimplifiedSchemaPropertyMap implements PropertyMap { private final PropertyMap base; private final Pattern start; SimplifiedSchemaPropertyMap(PropertyMap base, Pattern start) { this.base = base; this.start = start; } public T get(PropertyId pid) { if (pid == RngProperty.SIMPLIFIED_SCHEMA) { String simplifiedSchema = PatternDumper.toString(start); return pid.getValueClass().cast(simplifiedSchema); } else return base.get(pid); } public PropertyId getKey(int i) { return i == base.size() ? RngProperty.SIMPLIFIED_SCHEMA : base.getKey(i); } public int size() { return base.size() + 1; } public boolean contains(PropertyId pid) { return base.contains(pid) || pid == RngProperty.SIMPLIFIED_SCHEMA; } } static Schema wrapPattern(Pattern start, SchemaPatternBuilder spb, PropertyMap properties) throws SAXException, IncorrectSchemaException { if (properties.contains(RngProperty.FEASIBLE)) start = FeasibleTransform.transform(spb, start); properties = new SimplifiedSchemaPropertyMap(AbstractSchema.filterProperties(properties, supportedPropertyIds), start); Schema schema = new PatternSchema(spb, start, properties); if (spb.hasIdTypes() && properties.contains(RngProperty.CHECK_ID_IDREF)) { ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); IdTypeMap idTypeMap = new IdTypeMapBuilder(eh, start).getIdTypeMap(); if (idTypeMap == null) throw new IncorrectSchemaException(); Schema idSchema; if (properties.contains(RngProperty.FEASIBLE)) idSchema = new FeasibleIdTypeMapSchema(idTypeMap, properties); else idSchema = new IdTypeMapSchema(idTypeMap, properties); schema = new CombineSchema(schema, idSchema, properties); } return schema; } protected abstract Parseable createParseable(SAXSource source, SAXResolver resolver, ErrorHandler eh, PropertyMap properties) throws SAXException; } SchemaReceiverImpl.java000066400000000000000000000051441225366607500353700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/src/main/com/thaiopensource/validate/rng/implpackage com.thaiopensource.validate.rng.impl; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.prop.rng.RngProperty; import com.thaiopensource.validate.prop.wrap.WrapProperty; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.relaxng.parse.ParseReceiver; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.PatternFuture; import com.thaiopensource.relaxng.pattern.SchemaBuilderImpl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.datatype.DatatypeLibraryLoader; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import java.io.IOException; public class SchemaReceiverImpl implements SchemaReceiver { private final ParseReceiver parser; private final PropertyMap properties; public SchemaReceiverImpl(ParseReceiver parser, PropertyMap properties) { this.parser = parser; this.properties = properties; } public SchemaFuture installHandlers(XMLReader xr) throws SAXException { final SchemaPatternBuilder pb = new SchemaPatternBuilder(); ErrorHandler eh = properties.get(ValidateProperty.ERROR_HANDLER); DatatypeLibraryFactory dlf = properties.get(RngProperty.DATATYPE_LIBRARY_FACTORY); if (dlf == null) dlf = new DatatypeLibraryLoader(); final PatternFuture pf = SchemaBuilderImpl.installHandlers(parser, xr, eh, dlf, pb); return new SchemaFuture() { public Schema getSchema() throws IncorrectSchemaException, SAXException, IOException { try { return SchemaReaderImpl.wrapPattern(pf.getPattern(properties.contains(WrapProperty.ATTRIBUTE_OWNER)), pb, properties); } catch (IllegalSchemaException e) { throw new IncorrectSchemaException(); } } public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException { if (e instanceof BuildException) { try { return SchemaBuilderImpl.unwrapBuildException((BuildException)e); } catch (IllegalSchemaException ise) { throw new IncorrectSchemaException(); } } return e; } }; } } jing-trang-20131210+dfsg+1/mod/rng-validate/test/000077500000000000000000000000001225366607500212075ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-validate/test/spectest.xml000066400000000000000000004104521225366607500235710ustar00rootroot00000000000000"> ]> James Clark jjc@jclark.com For October 26 version of the spec.

    3
    Various possible syntax errors.
    3
    3
    3
    3
    foo
    3
    bar
    3
    foo bar
    3
    foo bar
    3
    foo bar
    3
    3
    3
    3
    3
    3
    3
    Tests for obsolete syntax
    3
    3
    3
    foo
    3
    foo
    3
    3
    3
    3
    Tests for missing attributes and child elements
    3
    3
    foo
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    Checking of ns attribute
    3
    3
    No checking of ns attribute is performed
    3
    No checking of ns attribute is performed
    3
    No checking of ns attribute is performed
    Checking of datatypeLibrary attribute
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must conform to RFC 2396
    3
    Value of datatypeLibrary attribute must not be relative
    3
    Value of datatypeLibrary attribute must not be relative
    3
    Value of datatypeLibrary attribute must not be relative
    3
    Value of datatypeLibrary attribute must not be relative
    3
    3
    3
    x
    3
    Value of datatypeLibrary attribute must not contain fragment identifier
    3
    Value of datatypeLibrary attribute must not contain fragment identifier
    Tests for QName and NCNames in schemas
    3
    &dii;
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    Tests for elements that allow only a single pattern child.
    3
    3
    3
    bar
    Tests for foreign element and attribute handling.
    3
    3
    foo
    3
    foo
    3
    X
    3
    3
    foo X
    3
    foo X
    3
    foo X
    3
    foo X
    4
    4.2
    4.2
    4.2
    bar bar bar
    4.2
    X
    4.2
    foo bar
    4.2
    4.4
    bar bar bar bar baz ba r
    4.5
    4.5
    4.5
    4.5
    4.6
    4.6
    4.6
    4.6
    4.6
    4.6
    4.6
    Same value of href before resolution, but not a loop.
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.7
    4.8
    4.8
    4.8
    4.9
    4.9
    bar
    4.6
    4.9
    foo foo bar
    4.10
    4.10
    4.10
    4.10
    4.10
    4.11
    4.11
    4.12
    X X
    4.12
    X X
    4.12
    4.15
    X X
    4.12
    4.14
    X X
    4.12
    x y z x y z x
    4.12
    4.13
    X X
    4.12
    foo X X
    4.12
    foo bar baz
    4.12
    x y z xyz x y y
    4.12
    4.12
    bar
    4.12
    X X
    4.12
    4.12
    4.12
    4.12
    4.12
    4.13
    4.13
    x x xy
    4.14
    4.14
    x
    4.15
    4.15
    x
    4.16
    4.16
    4.16
    foo
    4.16
    4.16
    foo
    4.16
    4.16
    foo
    4.16
    Tests that 4.16 is before 4.20.
    4.16
    Tests that 4.16 is before removal of unreachable definitions.
    4.16
    4.16
    4.16
    4.16
    4.16
    4.16
    4.16
    xmlns foo
    4.16
    xmlns
    4.16
    xmlns
    4.16
    xmlns
    4.16
    foo xmlns
    4.16
    xmlns
    4.16
    xmlns
    4.16
    4.16
    4.16
    2
    4.16
    4.16
    4.16
    2
    4.16
    4.16
    4.16
    2
    4.16
    4.16
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.17
    4.18
    4.18
    grammar must have a start
    4.18
    4.17 is before 4.18
    4.18
    4.17 is before 4.19
    4.18
    every ref must have a def
    4.18
    4.17 is before 4.18
    4.18
    4.17 is before 4.19
    4.18
    every parentRef must have a def
    4.18
    4.17 is before 4.18
    4.18
    4.17 is before 4.19
    4.18
    4.18
    4.18
    4.18
    4.19
    4.19
    4.19
    4.19
    4.19
    4.20
    Tests that recursion detection happens before normalization of notAllowed.
    6
    6.1
    6.1
    6.1
    foo
    6.1
    6.1
    6.1
    6.1
    foo
    6.1
    foo
    6.1
    foo
    6.1
    foo
    6.1
    foo bar
    6.2
    6.2.1
    6.2.1
    6.2.1
    6.2.1
    6.2.1
    6.2.2
    6.2.2
    6.2.2
    6.2.2
    6.2.2
    6.2.2
    6.2.2
    6.2.3
    6.2.3
    x
    6.2.3
    6.2.3
    x
    6.2.3
    6.2.3
    6.2.4
    6.2.4
    x x y
    6.2.4
    x x y x
    6.2.4
    x x y x
    6.2.4
    x x y x xx xx
    6.2.4
    x
    6.2.5
    6.2.5
    6.2.5
    6.2.5
    6.2.5
    6.2.6
    6.2.6
    6.2.6
    6.2.6
    6.2.6
    6.2.7
    6.2.7
    bar baz baz
    6.2.7
    bar baz baz
    6.2.7
    bar
    6.2.7
    foo bar baz
    6.2.7
    6.2.8
    x
    6.2.7
    6.2.8
    x
    6.2.7
    6.2.8
    6.2.10
    x x x y
    6.2.7
    6.2.8
    2 xx xxx x
    6.2.7
    6.2.8
    x x x y x x
    6.2.7
    6.2.8
    x x x y x x
    6.2.8
    6.2.8
    x y xyzzy x y x
    6.2.8
    6.2.8
    6.2.8
    x
    6.2.9
    6.2.9
    xyzzy x y z
    6.2.9
    xyzzy x y z
    6.2.9
    x x xy x
    6.2.9
    x x xy x
    6.2.9
    x x x x x xy
    6.2.9
    x y x y x y x y xy
    6.2.9
    x x x x x xy
    6.2.9
    x y x y x y x y x y x y xy
    6.2.9
    6.2.9
    6.2.9
    2
    6.2.9
    2
    6.2.10
    6.2.10
    x x x x x
    6.2.10
    x x x x x x x y
    6.2.10
    x y x y x y x y x
    6.2.10
    x y x y z
    6.2.10
    x y x y
    7
    7.1
    7.1.1
    7.1.1
    7.1.1
    7.1.1
    7.1.2
    7.1.2
    7.1.2
    7.1.2
    7.1.2
    7.1.2
    7.1.3
    7.1.3
    7.1.3
    7.1.3
    7.1.3
    7.1.3
    7.1.3
    7.1.3
    x y
    7.1.3
    x y z
    7.1.4
    7.1.4
    7.1.4
    7.1.4
    7.1.4
    7.1.4
    7.1.4
    7.1.4
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    foo
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7.1.5
    7
    4.18
    Tests that constraints are post-normalization text
    7.1.5
    7
    4.18
    7.1.1
    7
    4.20
    7.1.1
    7
    4.20
    The nested attribute element is normalized out because of the not allowed.
    7.1.2
    7
    4.12
    The group element is normalized out.
    7.1.2
    7
    4.21
    The group element is normalized out.
    7.1.2
    7
    4.20
    The attribute elements are all normalized out.
    7.2
    7.2
    Checks that normalization of notAllowed happens before string sequence checking.
    7.2
    4.20
    4.20
    7.2
    notAllowed in an element is not normalized
    7.3
    7.3
    7.3
    7.3
    7.3
    7.3
    7.3
    7.3
    baz
    7.3
    bar
    7.3
    7.3
    baz
    7.3
    7.3
    7.3
    bar
    7.3
    foo
    7.3
    foo
    7.3
    bar
    7.3
    7.3
    7.3
    7.3
    7.3
    7.3
    foo
    7.4
    7.4
    7.4
    7.4
    7.4
    7.4
    7.4
    7.4
    7.4
    7.4
    bar
    7.4
    7.4
    7.4
    Regressions Validation error reporting text xyzzy xyzzy xyzzy x Datatype problems xyzzy xyzzy xyzzy x xyzzy xyzzy e2:xyzzy xyzzy xyzzy xyzzy x e3:xyzzy e2:xyzzy xyzzy xyzzy xyzzy x Datatype error reporting x y x z x y #none rgb 0 1 0.5 0.5 0.5 0.4 rgb 0.9 0.8 0.8 0.5 0.4 rgb 0.9 1.1 0.8 0.5 0.4 rgb -0.9 0.8 0.8 0.5 0.4 rb 0.9 0.8 0.8 0.5 0.4 rgb 0.9 0.8 x y x z jing-trang-20131210+dfsg+1/mod/schematron/000077500000000000000000000000001225366607500200165ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/schematron/lib/000077500000000000000000000000001225366607500205645ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/schematron/lib/xsltc-fixup.xsl000066400000000000000000000005551225366607500236070ustar00rootroot00000000000000

    The copy() and equals() methods allow * applications to perform incremental revalidation. */ public interface Matcher { /** * Return a copy of the current Matcher. * Future changes to the state of the copy will not affect this and vice-versa. * * @return a Matcher that is a copy of this */ Matcher copy(); /** * Return a copy of this Matcher reset to its starting state. * @return a new Matcher */ Matcher start(); /** * Test whether obj is an equivalent Matcher. * @return true if they are obj is known to be equivalent, false otherwise */ boolean equals(Object obj); /** * Return a hashCode for the Matcher. This is consistent with equals. * @return a hash code */ int hashCode(); /** * Match a StartDocument event. This can only generate an error if the schema was * equivalent to notAllowed. * * @return false if there was an error, true otherwise */ boolean matchStartDocument(); /** * Match an EndDocument event. * * @return false if there was an error, true otherwise */ boolean matchEndDocument(); /** * Match a StartTagOpen event. * @param name the element name * @param qName the element qName (may be empty or null if unknown) * @param context the MatchContext * @return false if there was an error, true otherwise */ boolean matchStartTagOpen(Name name, String qName, MatchContext context); /** * Match an AttributeName event. * * @param name the attribute name * @param qName the attribute qName (may be empty or null if unknown) * @param context the MatchContext * @return false if there was an error, true otherwise */ boolean matchAttributeName(Name name, String qName, MatchContext context); /** * Match an AttributeValue event. * The MatchContext must include all the namespace declarations in the start-tag * including those that lexically follow the attribute. * * @param value the attribute value, normalized in accordance with XML 1.0 * @param name the attribute name (included for use in error messages) * @param qName the attribute qName (included for use in error messages) * @param context the MatchContext * @return false if there was an error, true otherwise */ boolean matchAttributeValue(String value, Name name, String qName, MatchContext context); /** * Match a StartTagClose event. This corresponds to the > character * that ends the start-tag). * It may cause an error if there are required attributes that have not been matched. * The parameters are used to generate error messages. * * @param name the element name * @param qName the element qName (may be null or empty) * @param context the MatchContext * @return false if there was an error, true otherwise */ boolean matchStartTagClose(Name name, String qName, MatchContext context); /** * Match a Text event that occurs immediately before an EndTag event. * All text between two tags must be collected together: consecutive * calls to matchTextBeforeEndTag/matchTextBeforeStartTag are not * allowed unless separated by a call to matchStartTagOpen or matchEndTag. * Calls to matchTextBeforeEndTag can sometimes be optimized into * calls to matchUntypedText. * * @param string the text to be matched * @param name the name of the parent element (i.e. the name of the element of the following * EndTag event) * @param qName the qName of the parent element * @param context a match context * @return false if there was an error, true otherwise */ boolean matchTextBeforeEndTag(String string, Name name, String qName, MatchContext context); /** * Match a Text event that occurs immediately before a StartTagOpen event. * All text between two tags must be collected together: consecutive * calls to matchTextBeforeEndTag/matchTextBeforeStartTag are not * allowed unless separated by a call to matchStartTagOpen or matchEndTag. * Calls to matchTextBeforeStartTag can sometimes be optimized into * calls to matchUntypedText. * * @param string the text to be matched * @param context a match context * @return false if there was an error, true otherwise */ boolean matchTextBeforeStartTag(String string, MatchContext context); /** * An optimization of matchTextBeforeStartTag/matchTextBeforeEndTag. * Unlike these functions, matchUntypedText does not * need to examine the text. * If isTextTyped returns false, then in this state * text that consists of whitespace (' ', '\r', '\n', '\t') may be ignored and text that contains * non-whitespace characters may be processed using matchUntypedText. * Furthermore it is not necessary to collect up all the text between tags; * consecutive calls to matchUntypedText are allowed. * matchUntypedText must not be used unless isTextTyped * returns false. * @param context a match context * @return false if there was an error, true otherwise */ boolean matchUntypedText(MatchContext context); /** * Return true if text may be typed in the current state, false otherwise. * If text may be typed, then a call to matchText must not be optimized * to matchUntypedText. * * @return true if text may be typed, false otherwise */ boolean isTextTyped(); /** * Match an EndTag event. * * @param name the element name * @param qName the elememt qname (may be empty or null if unknown) * @param context a match context * @return false if there was an error, true otherwise */ boolean matchEndTag(Name name, String qName, MatchContext context); /** * Return the current error message. * The current error message is changed by any matchE method * that returns false. Initially, the current error message is null. * * @return a string with the current error message, or null if there has not yet * been an error. */ String getErrorMessage(); /** * Return true if the document is valid so far. * A document is valid so far if and only if no errors have yet been * encountered. * * @return true if the document is valid so far, false otherwise */ boolean isValidSoFar(); /** * Return a NameClass containing the names of elements whose start-tags are valid * in the current state. This must be called only in a state in * which a call to matchStartTagOpen would be allowed. * * @return a NameClass contains the names of elements whose start-tags are possible */ NameClass possibleStartTagNames(); /** * Return a NameClass containing the names of attributes that are valid * in the current state. This must be called only in a state in * which a call to matchAttributeName would be allowed. * * @return a NameClass containing the names of attributes that are possible */ NameClass possibleAttributeNames(); /** * Return a Set containing the names of attributes that are required in the * current state. This must be called only in a state in * which a call to matchAttributeName would be allowed. Note * that in a schema such as attribute foo|bar { text } neither foo nor * bar are considered required attributes; an attribute name x is required * only if every matching pattern contains an attribute named x. Similarly, * this function provides no information about wildcard attribute names. * @return a non-null Set each member of which is a non-null Name corresponding * to the name of a required attribute * @see Name */ Set requiredAttributeNames(); Set requiredElementNames(); } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/match/NameClass.java000066400000000000000000000062501225366607500321210ustar00rootroot00000000000000package com.thaiopensource.relaxng.match; import com.thaiopensource.xml.util.Name; import java.util.Set; /** * A RELAX NG name class. Equivalent name classes are normalized so that they have the * same representation. */ public interface NameClass { /** * Tests whether this name class is empty. A name class is empty if there is no name in the * name class. * @return true if the name class is empty, false otherwise */ boolean isEmpty(); /** * Tests whether this name class contains a name. * @param name the name to test; must not be null * @return true if the name class contains the name, false otherwise */ boolean contains(Name name); /** * Tests whethers this name class contains a wildcard matching any name. If true, then the * name class contains all names except for those in getExcludedNames() or whose namespace * is in getExcludedNamespaces(); it also contains those names in getIncludedNames(). * @return true if this name class contains a wildcard matching any name, false otherwise. */ boolean isAnyNameIncluded(); /** * Returns the set of namespaces excluded from a wildcard matching any name. * @return a non-null immutable, possibly empty Set each member of which is a non-null String, * if isAnyNameIncluded() is true, null otherwise * @see #isAnyNameIncluded */ Set getExcludedNamespaces(); /** * Returns the set of names excluded from a wildcard matching any name. None of the names * will have namespaces in getExcludedNamespaces(). * @return a non-null immutable, possibly empty Set each member of which is a non-null Name, * if isAnyNameIncluded() is true, null otherwise * @see #isAnyNameIncluded * @see Name */ Set getExcludedNames(); /** * Returns the set of names that this name class contains. This doesn't include any wildcards * included in the name class. If isAnyNameIncluded() is true, then all the names in the * returned set will have a namespace that is in getExcludedNamespaces(). None of the names * will have a namespace that is in getIncludedNamespaces(). * @return a non-null, possibly empty Set, each member of which is a non-null Name * @see Name */ Set getIncludedNames(); /** * Returns the set of namespace wildcards that this name class contains. If a string s is in the * returned set, then the name class contains all names whose namespace is s, with * the exception of any names contained in getExcludedNames(s). The * default namespace is represented by a zero-length String. The returned set will be empty * if isAnyNameIncluded() is true. * @return a non-null, possibly empty, immutable Set each member of which is a non-null String * @see #isAnyNameIncluded */ Set getIncludedNamespaces(); /** * Returns the set of local names excluded from a namespace wildcard. * @param ns the namespace from which the local names are excluded * @return a non-null possibly empty Set each member of which is a non-null String, * if ns is in getIncludedNamespaces(), null otherwise * @see #getIncludedNamespaces */ Set getExcludedLocalNames(String ns); } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/000077500000000000000000000000001225366607500277665ustar00rootroot00000000000000AbstractNameClassNormalizer.java000066400000000000000000000053121225366607500361500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Base class for normalizing name classes. */ public abstract class AbstractNameClassNormalizer { private static final String IMPOSSIBLE = "\u0000"; protected abstract boolean contains(Name name); protected abstract void accept(NameClassVisitor visitor); public NormalizedNameClass normalize() { final List mentionedNames = new ArrayList(); final List mentionedNamespaces = new ArrayList(); accept(new NameClassVisitor() { public void visitChoice(NameClass nc1, NameClass nc2) { nc1.accept(this); nc2.accept(this); } public void visitNsName(String ns) { mentionedNamespaces.add(ns); } public void visitNsNameExcept(String ns, NameClass nc) { mentionedNamespaces.add(ns); nc.accept(this); } public void visitAnyName() { } public void visitAnyNameExcept(NameClass nc) { nc.accept(this); } public void visitName(Name name) { mentionedNames.add(name); } public void visitNull() { } public void visitError() { } }); if (contains(new Name(IMPOSSIBLE, IMPOSSIBLE))) { Set includedNames = new HashSet(); Set excludedNamespaces = new HashSet(); Set excludedNames = new HashSet(); for (String ns : mentionedNamespaces) { if (!contains(new Name(ns, IMPOSSIBLE))) excludedNamespaces.add(ns); } for (Name name : mentionedNames) { boolean in = contains(name); if (excludedNamespaces.contains(name.getNamespaceUri())) { if (in) includedNames.add(name); } else if (!in) excludedNames.add(name); } return new NormalizedAnyNameClass(includedNames, excludedNamespaces, excludedNames); } Map> nsMap = new HashMap>(); for (String ns : mentionedNamespaces) { if (contains(new Name(ns, IMPOSSIBLE)) && nsMap.get(ns) == null) nsMap.put(ns, new HashSet()); } Set includedNames = new HashSet(); for (Name name : mentionedNames) { boolean in = contains(name); Set excluded = nsMap.get(name.getNamespaceUri()); if (excluded == null) { if (in) includedNames.add(name); } else if (!in) excluded.add(name.getLocalName()); } return new NormalizedNsNameClass(includedNames, nsMap); } } AbstractPatternFunction.java000066400000000000000000000024351225366607500353650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; abstract class AbstractPatternFunction implements PatternFunction { public T caseEmpty(EmptyPattern p) { return caseOther(p); } public T caseNotAllowed(NotAllowedPattern p) { return caseOther(p); } public T caseError(ErrorPattern p) { return caseOther(p); } public T caseGroup(GroupPattern p) { return caseOther(p); } public T caseInterleave(InterleavePattern p) { return caseOther(p); } public T caseChoice(ChoicePattern p) { return caseOther(p); } public T caseOneOrMore(OneOrMorePattern p) { return caseOther(p); } public T caseElement(ElementPattern p) { return caseOther(p); } public T caseAttribute(AttributePattern p) { return caseOther(p); } public T caseData(DataPattern p) { return caseOther(p); } public T caseDataExcept(DataExceptPattern p) { return caseOther(p); } public T caseValue(ValuePattern p) { return caseOther(p); } public T caseText(TextPattern p) { return caseOther(p); } public T caseList(ListPattern p) { return caseOther(p); } public T caseAfter(AfterPattern p) { return caseOther(p); } public T caseRef(RefPattern p) { return caseOther(p); } public abstract T caseOther(Pattern p); } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/AfterPattern.java000066400000000000000000000005621225366607500332330ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class AfterPattern extends BinaryPattern { AfterPattern(Pattern p1, Pattern p2) { super(false, combineHashCode(AFTER_HASH_CODE, p1.hashCode(), p2.hashCode()), p1, p2); } boolean isNotAllowed() { return p1.isNotAllowed(); } T apply(PatternFunction f) { return f.caseAfter(this); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/Alphabet.java000066400000000000000000000014071225366607500323530ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class Alphabet { private NameClass nameClass; boolean isEmpty() { return nameClass == null; } void addElement(NameClass nc) { if (nameClass == null) nameClass = nc; else if (nc != null) nameClass = new ChoiceNameClass(nameClass, nc); } void addAlphabet(Alphabet a) { addElement(a.nameClass); } void checkOverlap(Alphabet a) throws RestrictionViolationException { if (nameClass != null && a.nameClass != null) OverlapDetector.checkOverlap(nameClass, a.nameClass, "interleave_element_overlap_name", "interleave_element_overlap_ns", "interleave_element_overlap"); } } AnnotationsImpl.java000066400000000000000000000013411225366607500336700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.relaxng.parse.Annotations; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.util.VoidValue; import org.xml.sax.Locator; public abstract class AnnotationsImpl extends CommentListImpl implements Annotations { public void addAttribute(String ns, String localName, String prefix, String value, Locator loc) throws BuildException { } public void addElement(VoidValue voidValue) throws BuildException { } public void addComment(CommentListImpl comments) throws BuildException { } public void addLeadingComment(CommentListImpl comments) throws BuildException { } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/AnyNameClass.java000066400000000000000000000011031225366607500331420ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class AnyNameClass implements NameClass { public boolean contains(Name name) { return true; } public int containsSpecificity(Name name) { return SPECIFICITY_ANY_NAME; } public boolean equals(Object obj) { return obj != null && obj instanceof AnyNameClass; } public int hashCode() { return AnyNameClass.class.hashCode(); } public void accept(NameClassVisitor visitor) { visitor.visitAnyName(); } public boolean isOpen() { return true; } } AnyNameExceptNameClass.java000066400000000000000000000015541225366607500350470ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class AnyNameExceptNameClass implements NameClass { private final NameClass nameClass; AnyNameExceptNameClass(NameClass nameClass) { this.nameClass = nameClass; } public boolean contains(Name name) { return !nameClass.contains(name); } public int containsSpecificity(Name name) { return contains(name) ? SPECIFICITY_ANY_NAME : SPECIFICITY_NONE; } public boolean equals(Object obj) { if (obj == null || !(obj instanceof AnyNameExceptNameClass)) return false; return nameClass.equals(((AnyNameExceptNameClass)obj).nameClass); } public int hashCode() { return ~nameClass.hashCode(); } public void accept(NameClassVisitor visitor) { visitor.visitAnyNameExcept(nameClass); } public boolean isOpen() { return true; } } ApplyAfterFunction.java000066400000000000000000000014401225366607500343260ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; abstract class ApplyAfterFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; ApplyAfterFunction(ValidatorPatternBuilder builder) { this.builder = builder; } public Pattern caseAfter(AfterPattern p) { return builder.makeAfter(p.getOperand1(), apply(p.getOperand2())); } public Pattern caseChoice(ChoicePattern p) { return builder.makeChoice(p.getOperand1().apply(this), p.getOperand2().apply(this)); } public Pattern caseNotAllowed(NotAllowedPattern p) { return p; } public Pattern caseOther(Pattern p) { throw new AssertionError("ApplyAfterFunction applied to " + p.getClass().getName()); } abstract Pattern apply(Pattern p); } AttributeNameClassChecker.java000066400000000000000000000020431225366607500355700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.WellKnownNamespaces; import com.thaiopensource.xml.util.Name; class AttributeNameClassChecker implements NameClassVisitor { private String errorMessageId = null; public void visitChoice(NameClass nc1, NameClass nc2) { nc1.accept(this); nc2.accept(this); } public void visitNsName(String ns) { if (ns.equals(WellKnownNamespaces.XMLNS)) errorMessageId = "xmlns_uri_attribute"; } public void visitNsNameExcept(String ns, NameClass nc) { visitNsName(ns); nc.accept(this); } public void visitAnyName() { } public void visitAnyNameExcept(NameClass nc) { nc.accept(this); } public void visitName(Name name) { visitNsName(name.getNamespaceUri()); if (name.equals(new Name("", "xmlns"))) errorMessageId = "xmlns_attribute"; } public void visitNull() { } public void visitError() { } String checkNameClass(NameClass nc) { errorMessageId = null; nc.accept(this); return errorMessageId; } } AttributePattern.java000066400000000000000000000045731225366607500340640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.Locator; import org.xml.sax.SAXException; class AttributePattern extends Pattern { private final NameClass nameClass; private final Pattern p; private final Locator loc; AttributePattern(NameClass nameClass, Pattern value, Locator loc) { super(false, EMPTY_CONTENT_TYPE, combineHashCode(ATTRIBUTE_HASH_CODE, nameClass.hashCode(), value.hashCode())); this.nameClass = nameClass; this.p = value; this.loc = loc; } Pattern expand(SchemaPatternBuilder b) { Pattern ep = p.expand(b); if (ep != p) return b.makeAttribute(nameClass, ep, loc); else return this; } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_attribute"); case ELEMENT_CONTEXT: if (nameClass.isOpen()) throw new RestrictionViolationException("open_name_class_not_repeated"); break; case ELEMENT_REPEAT_GROUP_CONTEXT: throw new RestrictionViolationException("one_or_more_contains_group_contains_attribute"); case ELEMENT_REPEAT_INTERLEAVE_CONTEXT: throw new RestrictionViolationException("one_or_more_contains_interleave_contains_attribute"); case LIST_CONTEXT: throw new RestrictionViolationException("list_contains_attribute"); case ATTRIBUTE_CONTEXT: throw new RestrictionViolationException("attribute_contains_attribute"); case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_attribute"); } dad.addAttribute(nameClass); try { p.checkRestrictions(ATTRIBUTE_CONTEXT, null, null); } catch (RestrictionViolationException e) { e.maybeSetLocator(loc); throw e; } } boolean samePattern(Pattern other) { if (!(other instanceof AttributePattern)) return false; AttributePattern ap = (AttributePattern)other; return nameClass.equals(ap.nameClass)&& p == ap.p; } void checkRecursion(int depth) throws SAXException { p.checkRecursion(depth); } T apply(PatternFunction f) { return f.caseAttribute(this); } Pattern getContent() { return p; } NameClass getNameClass() { return nameClass; } Locator getLocator() { return loc; } } BinaryPattern.java000066400000000000000000000017231225366607500333370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.SAXException; abstract class BinaryPattern extends Pattern { final Pattern p1; final Pattern p2; BinaryPattern(boolean nullable, int hc, Pattern p1, Pattern p2) { super(nullable, Math.max(p1.getContentType(), p2.getContentType()), hc); this.p1 = p1; this.p2 = p2; } void checkRecursion(int depth) throws SAXException { p1.checkRecursion(depth); p2.checkRecursion(depth); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { p1.checkRestrictions(context, dad, alpha); p2.checkRestrictions(context, dad, alpha); } boolean samePattern(Pattern other) { if (getClass() != other.getClass()) return false; BinaryPattern b = (BinaryPattern)other; return p1 == b.p1 && p2 == b.p2; } Pattern getOperand1() { return p1; } Pattern getOperand2() { return p2; } } BlankDataDerivType.java000066400000000000000000000021121225366607500342230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.ValidationContext; import java.util.List; class BlankDataDerivType extends DataDerivType { private PatternMemo blankMemo; private PatternMemo nonBlankMemo; BlankDataDerivType() { } PatternMemo dataDeriv(ValidatorPatternBuilder builder, Pattern p, String str, ValidationContext vc, List fail) { if (DataDerivFunction.isBlank(str)) { if (blankMemo == null || (fail != null && blankMemo.isNotAllowed())) blankMemo = super.dataDeriv(builder, p, str, vc, fail); return blankMemo; } else { if (nonBlankMemo == null || (fail != null && nonBlankMemo.isNotAllowed())) nonBlankMemo = super.dataDeriv(builder, p, str, vc, fail); return nonBlankMemo; } } DataDerivType copy() { return new BlankDataDerivType(); } DataDerivType combine(DataDerivType ddt) { if (ddt instanceof BlankDataDerivType || ddt instanceof SingleDataDerivType) return this; return InconsistentDataDerivType.getInstance(); } }BuiltinDatatypeBuilder.java000066400000000000000000000012041225366607500351600ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeBuilder; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.ValidationContext; class BuiltinDatatypeBuilder implements DatatypeBuilder { private final Datatype dt; BuiltinDatatypeBuilder(Datatype dt) { this.dt = dt; } public void addParameter(String name, String value, ValidationContext context) throws DatatypeException { throw new DatatypeException(SchemaBuilderImpl.localizer.message("builtin_param")); } public Datatype createDatatype() { return dt; } } BuiltinDatatypeLibrary.java000066400000000000000000000016131225366607500352020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeBuilder; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeLibrary; public class BuiltinDatatypeLibrary implements DatatypeLibrary { private final DatatypeBuilder tokenDatatypeBuilder = new BuiltinDatatypeBuilder(new TokenDatatype()); private final DatatypeBuilder stringDatatypeBuilder = new BuiltinDatatypeBuilder(new StringDatatype()); public DatatypeBuilder createDatatypeBuilder(String type) throws DatatypeException { if (type.equals("token")) return tokenDatatypeBuilder; else if (type.equals("string")) return stringDatatypeBuilder; throw new DatatypeException(); } public Datatype createDatatype(String type) throws DatatypeException { return createDatatypeBuilder(type).createDatatype(); } } BuiltinDatatypeLibraryFactory.java000066400000000000000000000025731225366607500365400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.DatatypeLibraryFactory; import java.util.HashMap; import java.util.Map; class BuiltinDatatypeLibraryFactory implements DatatypeLibraryFactory { private final Map cache = new HashMap(); private final DatatypeLibraryFactory factory; private final DatatypeLibrary builtinDatatypeLibrary = new BuiltinDatatypeLibrary(); private DatatypeLibrary lastDatatypeLibrary = null; private String lastDatatypeLibraryUri = null; BuiltinDatatypeLibraryFactory(DatatypeLibraryFactory factory) { this.factory = factory; cache.put(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES, new CompatibilityDatatypeLibrary(this)); } public DatatypeLibrary createDatatypeLibrary(String uri) { if (uri.equals("")) return builtinDatatypeLibrary; if (uri.equals(lastDatatypeLibraryUri)) return lastDatatypeLibrary; DatatypeLibrary library = cache.get(uri); if (library == null) { if (factory == null) return null; library = factory.createDatatypeLibrary(uri); if (library == null) return null; cache.put(uri, library); } lastDatatypeLibraryUri = uri; return lastDatatypeLibrary = library; } } ChoiceNameClass.java000066400000000000000000000022331225366607500335330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class ChoiceNameClass implements NameClass { private final NameClass nameClass1; private final NameClass nameClass2; ChoiceNameClass(NameClass nameClass1, NameClass nameClass2) { this.nameClass1 = nameClass1; this.nameClass2 = nameClass2; } public boolean contains(Name name) { return (nameClass1.contains(name) || nameClass2.contains(name)); } public int containsSpecificity(Name name) { return Math.max(nameClass1.containsSpecificity(name), nameClass2.containsSpecificity(name)); } public int hashCode() { return nameClass1.hashCode() ^ nameClass2.hashCode(); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof ChoiceNameClass)) return false; ChoiceNameClass other = (ChoiceNameClass)obj; return (nameClass1.equals(other.nameClass1) && nameClass2.equals(other.nameClass2)); } public void accept(NameClassVisitor visitor) { visitor.visitChoice(nameClass1, nameClass2); } public boolean isOpen() { return nameClass1.isOpen() || nameClass2.isOpen(); } } ChoicePattern.java000066400000000000000000000017661225366607500333140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class ChoicePattern extends BinaryPattern { ChoicePattern(Pattern p1, Pattern p2) { super(p1.isNullable() || p2.isNullable(), combineHashCode(CHOICE_HASH_CODE, p1.hashCode(), p2.hashCode()), p1, p2); } Pattern expand(SchemaPatternBuilder b) { Pattern ep1 = p1.expand(b); Pattern ep2 = p2.expand(b); if (ep1 != p1 || ep2 != p2) return b.makeChoice(ep1, ep2); else return this; } boolean containsChoice(Pattern p) { return p1.containsChoice(p) || p2.containsChoice(p); } T apply(PatternFunction f) { return f.caseChoice(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { if (dad != null) dad.startChoice(); p1.checkRestrictions(context, dad, alpha); if (dad != null) dad.alternative(); p2.checkRestrictions(context, dad, alpha); if (dad != null) dad.endChoice(); } } CommentListImpl.java000066400000000000000000000005101225366607500336260ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.CommentList; import org.xml.sax.Locator; public class CommentListImpl implements CommentList { public void addComment(String value, Locator loc) throws BuildException { } } CompatibilityDatatypeLibrary.java000066400000000000000000000023321225366607500364040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeBuilder; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.DatatypeLibraryFactory; import com.thaiopensource.xml.util.WellKnownNamespaces; class CompatibilityDatatypeLibrary implements DatatypeLibrary { private final DatatypeLibraryFactory factory; private DatatypeLibrary xsdDatatypeLibrary = null; CompatibilityDatatypeLibrary(DatatypeLibraryFactory factory) { this.factory = factory; } public DatatypeBuilder createDatatypeBuilder(String type) throws DatatypeException { if (type.equals("ID") || type.equals("IDREF") || type.equals("IDREFS")) { if (xsdDatatypeLibrary == null) { xsdDatatypeLibrary = factory.createDatatypeLibrary(WellKnownNamespaces.XML_SCHEMA_DATATYPES); if (xsdDatatypeLibrary == null) throw new DatatypeException(); } return xsdDatatypeLibrary.createDatatypeBuilder(type); } throw new DatatypeException(); } public Datatype createDatatype(String type) throws DatatypeException { return createDatatypeBuilder(type).createDatatype(); } } DataDataDerivType.java000066400000000000000000000035351225366607500340570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.ValidationContext; import java.util.List; class DataDataDerivType extends DataDerivType { private final DataPattern dp; private PatternMemo validMemo; private PatternMemo invalidMemo; DataDataDerivType(DataPattern dp) { this.dp = dp; } PatternMemo dataDeriv(ValidatorPatternBuilder builder, Pattern p, String str, ValidationContext vc, List fail) { boolean isValid; final Datatype dt = dp.getDatatype(); DataDerivFailure ddf = null; if (fail != null) { try { dt.checkValid(str, vc); isValid = true; } catch (DatatypeException e) { isValid = false; ddf = new DataDerivFailure(dp, e); } } else isValid = dt.isValid(str, vc); if (isValid) { if (validMemo == null || (fail != null && validMemo.isNotAllowed())) validMemo = super.dataDeriv(builder, p, str, vc, fail); return validMemo; } else { if (invalidMemo == null) invalidMemo = super.dataDeriv(builder, p, str, vc, fail); else if (invalidMemo.isNotAllowed() && ddf != null) fail.add(ddf); return invalidMemo; } } DataDerivType copy() { return new DataDataDerivType(dp); } DataDerivType combine(DataDerivType ddt) { if (ddt instanceof DataDataDerivType) { if (((DataDataDerivType)ddt).dp.getDatatype() == dp.getDatatype()) return this; return InconsistentDataDerivType.getInstance(); } if (ddt instanceof ValueDataDerivType) { if (((ValueDataDerivType)ddt).getDatatype() == dp.getDatatype()) return ddt; return InconsistentDataDerivType.getInstance(); } return ddt.combine(this); } }DataDerivFailure.java000066400000000000000000000101031225366607500337200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeException; import java.util.List; /** * Provides information about why a DataDerivFunction returned notAllowed. */ final class DataDerivFailure { private final Datatype datatype; private final Name datatypeName; private final List datatypeParams; private final String message; private final String stringValue; private final Object value; // except non-null means it matched the except private Pattern except; // index where error occurred if known private int index; private int tokenIndex = -1; private int tokenStart = -1; private int tokenEnd = -1; // not a valid instance of the datatype DataDerivFailure(DataPattern p, DatatypeException e) { this(p.getDatatype(), p.getDatatypeName(), p.getParams(), e.getMessage(), e.getIndex()); } // not a valid instance of the datatype DataDerivFailure(Datatype dt, Name dtName, DatatypeException e) { this(dt, dtName, null, e.getMessage(), e.getIndex()); } // failed because it matched the except in a dataExcept DataDerivFailure(DataExceptPattern p) { this(p.getDatatype(), p.getDatatypeName(), p.getParams(), p.getExcept()); } // not equal to the value in a value pattern DataDerivFailure(ValuePattern p) { this(p.getDatatype(), p.getDatatypeName(), p.getValue(), p.getStringValue()); } private DataDerivFailure(Datatype datatype, Name datatypeName, List datatypeParams, String message, int index) { this.datatype = datatype; this.datatypeName = datatypeName; this.datatypeParams = datatypeParams; this.message = message; this.except = null; this.index = index == DatatypeException.UNKNOWN ? -1 : index; this.stringValue = null; this.value = null; } private DataDerivFailure(Datatype datatype, Name datatypeName, List datatypeParams, Pattern except) { this.datatype = datatype; this.datatypeName = datatypeName; this.datatypeParams = datatypeParams; this.message = null; this.except = except; this.index = -1; this.stringValue = null; this.value = null; } private DataDerivFailure(Datatype datatype, Name datatypeName, Object value, String stringValue) { this.datatype = datatype; this.datatypeName = datatypeName; this.datatypeParams = null; this.message = null; this.except = null; this.index = -1; this.stringValue = stringValue; this.value = value; } public boolean equals(Object obj) { if (!(obj instanceof DataDerivFailure)) return false; DataDerivFailure other = (DataDerivFailure)obj; return (datatype == other.datatype && equal(message, other.message) && equal(stringValue, other.stringValue) && except == other.except && tokenIndex == other.tokenIndex && index == other.index); } public int hashCode() { int hc = datatype.hashCode(); if (message != null) hc ^= message.hashCode(); if (stringValue != null) hc ^= stringValue.hashCode(); if (except != null) hc ^= except.hashCode(); return hc; } private static boolean equal(Object o1, Object o2) { if (o1 == null) return o2 == null; return o1.equals(o2); } Datatype getDatatype() { return datatype; } Name getDatatypeName() { return datatypeName; } List getDatatypeParams() { return datatypeParams; } String getMessage() { return message; } String getStringValue() { return stringValue; } Object getValue() { return value; } Pattern getExcept() { return except; } int getIndex() { return index; } int getTokenIndex() { return tokenIndex; } int getTokenStart() { return tokenStart; } int getTokenEnd() { return tokenEnd; } void setToken(int tokenIndex, int tokenStart, int tokenEnd) { this.tokenIndex = tokenIndex; this.tokenStart = tokenStart; this.tokenEnd = tokenEnd; if (index < 0) index += tokenStart; } } DataDerivFunction.java000066400000000000000000000134721225366607500341320ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.ValidationContext; import org.relaxng.datatype.DatatypeException; import java.util.List; // invariant: if return is not notAllowed, then no failures are added to fail class DataDerivFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; private final ValidationContext vc; private final String str; private final List fail; DataDerivFunction(String str, ValidationContext vc, ValidatorPatternBuilder builder, List fail) { this.str = str; this.vc = vc; this.builder = builder; this.fail = fail; } static boolean isBlank(String str) { int len = str.length(); for (int i = 0; i < len; i++) { switch (str.charAt(i)) { case '\r': case '\n': case ' ': case '\t': break; default: return false; } } return true; } public Pattern caseText(TextPattern p) { return p; } public Pattern caseRef(RefPattern p) { return memoApply(p.getPattern()); } public Pattern caseList(ListPattern p) { int len = str.length(); int tokenIndex = 0; int tokenStart = -1; PatternMemo memo = builder.getPatternMemo(p.getOperand()); for (int i = 0; i < len; i++) { switch (str.charAt(i)) { case '\r': case '\n': case ' ': case '\t': if (tokenStart >= 0) { memo = tokenDeriv(memo, tokenIndex++, tokenStart, i); tokenStart = -1; } break; default: if (tokenStart < 0) tokenStart = i; break; } } if (tokenStart >= 0) memo = tokenDeriv(memo, tokenIndex++, tokenStart, len); if (memo.getPattern().isNullable()) return builder.makeEmpty(); if (memo.isNotAllowed()) return memo.getPattern(); // pseudo-token to try and force some failures tokenDeriv(memo, tokenIndex, len, len); // XXX handle the case where this didn't produce any failures return builder.makeNotAllowed(); } private PatternMemo tokenDeriv(PatternMemo p, int tokenIndex, int start, int end) { int failStartSize = failSize(); PatternMemo deriv = p.dataDeriv(str.substring(start, end), vc, fail); if (fail != null && deriv.isNotAllowed()) { for (int i = fail.size() - 1; i >= failStartSize; --i) fail.get(i).setToken(tokenIndex, start, end); } return deriv; } public Pattern caseValue(ValuePattern p) { Datatype dt = p.getDatatype(); Object value = dt.createValue(str, vc); if (value != null && dt.sameValue(p.getValue(), value)) return builder.makeEmpty(); if (fail != null) { if (value == null) { try { dt.checkValid(str, vc); } catch (DatatypeException e) { fail.add(new DataDerivFailure(dt, p.getDatatypeName(), e)); } } else fail.add(new DataDerivFailure(p)); } return builder.makeNotAllowed(); } public Pattern caseData(DataPattern p) { if (p.allowsAnyString()) return builder.makeEmpty(); if (fail != null) { try { p.getDatatype().checkValid(str, vc); return builder.makeEmpty(); } catch (DatatypeException e) { fail.add(new DataDerivFailure(p, e)); return builder.makeNotAllowed(); } } if (p.getDatatype().isValid(str, vc)) return builder.makeEmpty(); else return builder.makeNotAllowed(); } public Pattern caseDataExcept(DataExceptPattern p) { Pattern tem = caseData(p); if (tem.isNullable() && memoApply(p.getExcept()).isNullable()) { if (fail != null) fail.add(new DataDerivFailure(p)); return builder.makeNotAllowed(); } return tem; } public Pattern caseAfter(AfterPattern p) { Pattern p1 = p.getOperand1(); final int failStartSize = failSize(); if (memoApplyWithFailure(p1).isNullable()) return p.getOperand2(); if (p1.isNullable() && isBlank(str)) { clearFailures(failStartSize); return p.getOperand2(); } return builder.makeNotAllowed(); } public Pattern caseChoice(ChoicePattern p) { final int failStartSize = failSize(); Pattern tem = builder.makeChoice(memoApplyWithFailure(p.getOperand1()), memoApplyWithFailure(p.getOperand2())); if (!tem.isNotAllowed()) clearFailures(failStartSize); return tem; } public Pattern caseGroup(GroupPattern p) { final int failStartSize = failSize(); final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); Pattern tem = builder.makeGroup(memoApplyWithFailure(p1), p2); if (p1.isNullable()) tem = builder.makeChoice(tem, memoApplyWithFailure(p2)); if (!tem.isNotAllowed()) clearFailures(failStartSize); return tem; } // list//interleave is prohibited, so I don't think this can happen public Pattern caseInterleave(InterleavePattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); return builder.makeChoice(builder.makeInterleave(memoApply(p1), p2), builder.makeInterleave(p1, memoApply(p2))); } public Pattern caseOneOrMore(OneOrMorePattern p) { return builder.makeGroup(memoApplyWithFailure(p.getOperand()), builder.makeOptional(p)); } public Pattern caseOther(Pattern p) { return builder.makeNotAllowed(); } private Pattern memoApply(Pattern p) { return builder.getPatternMemo(p).dataDeriv(str, vc).getPattern(); } private Pattern memoApplyWithFailure(Pattern p) { return builder.getPatternMemo(p).dataDeriv(str, vc, fail).getPattern(); } private int failSize() { return fail == null ? 0 : fail.size(); } private void clearFailures(int failStartSize) { if (fail != null) { for (int i = fail.size() - 1; i >= failStartSize; --i) fail.remove(i); } } } DataDerivType.java000066400000000000000000000007501225366607500332610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.ValidationContext; import java.util.List; abstract class DataDerivType { abstract DataDerivType copy(); abstract DataDerivType combine(DataDerivType ddt); PatternMemo dataDeriv(ValidatorPatternBuilder builder, Pattern p, String str, ValidationContext vc, List fail) { return builder.getPatternMemo(p.apply(new DataDerivFunction(str, vc, builder, fail))); } } DataDerivTypeFunction.java000066400000000000000000000037241225366607500347730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class DataDerivTypeFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; DataDerivTypeFunction(ValidatorPatternBuilder builder) { this.builder = builder; } static DataDerivType dataDerivType(ValidatorPatternBuilder builder, Pattern pattern) { return pattern.apply(builder.getDataDerivTypeFunction()); } public DataDerivType caseOther(Pattern p) { return new SingleDataDerivType(); } public DataDerivType caseRef(RefPattern p) { return apply(p.getPattern()); } public DataDerivType caseAfter(AfterPattern p) { Pattern p1 = p.getOperand1(); DataDerivType ddt = apply(p.getOperand1()); if (!p1.isNullable()) return ddt; return ddt.combine(new BlankDataDerivType()); } private DataDerivType caseBinary(BinaryPattern p) { return apply(p.getOperand1()).combine(apply(p.getOperand2())); } public DataDerivType caseChoice(ChoicePattern p) { return caseBinary(p); } public DataDerivType caseGroup(GroupPattern p) { return caseBinary(p); } public DataDerivType caseInterleave(InterleavePattern p) { return caseBinary(p); } public DataDerivType caseOneOrMore(OneOrMorePattern p) { return apply(p.getOperand()); } public DataDerivType caseList(ListPattern p) { return InconsistentDataDerivType.getInstance(); } public DataDerivType caseValue(ValuePattern p) { return new ValueDataDerivType(p.getDatatype(), p.getDatatypeName()); } public DataDerivType caseData(DataPattern p) { if (p.allowsAnyString()) return new SingleDataDerivType(); return new DataDataDerivType(p); } public DataDerivType caseDataExcept(DataExceptPattern p) { if (p.allowsAnyString()) return apply(p.getExcept()); return new DataDataDerivType(p).combine(apply(p.getExcept())); } private DataDerivType apply(Pattern p) { return builder.getPatternMemo(p).dataDerivType(); } } DataExceptPattern.java000066400000000000000000000021371225366607500341350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.xml.sax.Locator; import java.util.List; class DataExceptPattern extends DataPattern { private final Pattern except; private final Locator loc; DataExceptPattern(Datatype dt, Name dtName, List params, Pattern except, Locator loc) { super(dt, dtName, params); this.except = except; this.loc = loc; } boolean samePattern(Pattern other) { if (!super.samePattern(other)) return false; return except.samePattern(((DataExceptPattern)other).except); } T apply(PatternFunction f) { return f.caseDataExcept(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { super.checkRestrictions(context, dad, alpha); try { except.checkRestrictions(DATA_EXCEPT_CONTEXT, null, null); } catch (RestrictionViolationException e) { e.maybeSetLocator(loc); throw e; } } Pattern getExcept() { return except; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/DataPattern.java000066400000000000000000000024631225366607500330450ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.datatype.Datatype2; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import java.util.Collections; import java.util.List; class DataPattern extends StringPattern { private final Datatype dt; private final Name dtName; private final List params; DataPattern(Datatype dt, Name dtName, List params) { super(combineHashCode(DATA_HASH_CODE, dt.hashCode())); this.dt = dt; this.dtName = dtName; this.params = params; } boolean samePattern(Pattern other) { if (other.getClass() != this.getClass()) return false; return dt.equals(((DataPattern)other).dt); } T apply(PatternFunction f) { return f.caseData(this); } Datatype getDatatype() { return dt; } Name getDatatypeName() { return dtName; } List getParams() { return Collections.unmodifiableList(params); } boolean allowsAnyString() { return dt instanceof Datatype2 && ((Datatype2)dt).alwaysValid(); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_data"); } } } DatatypeValue.java000066400000000000000000000011051225366607500333170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.Datatype; class DatatypeValue { private final Object value; private final Datatype dt; DatatypeValue(Object value, Datatype dt) { this.value = value; this.dt = dt; } public int hashCode() { return dt.hashCode() ^ dt.valueHashCode(value); } public boolean equals(Object obj) { if (!(obj instanceof DatatypeValue)) return false; DatatypeValue other = (DatatypeValue)obj; if (other.dt != dt) return false; return dt.sameValue(value, other.value); } } DuplicateAttributeDetector.java000066400000000000000000000030221225366607500360370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import java.util.ArrayList; import java.util.List; class DuplicateAttributeDetector { private final List nameClasses = new ArrayList(); private Alternative alternatives = null; private static class Alternative { private final int startIndex; private int endIndex; private final Alternative parent; private Alternative(int startIndex, Alternative parent) { this.startIndex = startIndex; this.endIndex = startIndex; this.parent = parent; } } void addAttribute(NameClass nc) throws RestrictionViolationException { int lim = nameClasses.size(); for (Alternative a = alternatives; a != null; a = a.parent) { for (int i = a.endIndex; i < lim; i++) checkAttributeOverlap(nc, nameClasses.get(i)); lim = a.startIndex; } for (int i = 0; i < lim; i++) checkAttributeOverlap(nc, nameClasses.get(i)); nameClasses.add(nc); } static private void checkAttributeOverlap(NameClass nc1, NameClass nc2) throws RestrictionViolationException { OverlapDetector.checkOverlap(nc1, nc2, "duplicate_attribute_name", "duplicate_attribute_ns", "duplicate_attribute"); } void startChoice() { alternatives = new Alternative(nameClasses.size(), alternatives); } void alternative() { alternatives.endIndex = nameClasses.size(); } void endChoice() { alternatives = alternatives.parent; } } ElementPattern.java000066400000000000000000000043401225366607500335020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.Locator; import org.xml.sax.SAXException; class ElementPattern extends Pattern { private Pattern p; private final NameClass origNameClass; private NameClass nameClass; private boolean expanded = false; private boolean checkedRestrictions = false; private final Locator loc; ElementPattern(NameClass nameClass, Pattern p, Locator loc) { super(false, ELEMENT_CONTENT_TYPE, combineHashCode(ELEMENT_HASH_CODE, nameClass.hashCode(), p.hashCode())); this.nameClass = nameClass; this.origNameClass = nameClass; this.p = p; this.loc = loc; } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { if (alpha != null) alpha.addElement(origNameClass); if (checkedRestrictions) return; switch (context) { case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_element"); case LIST_CONTEXT: throw new RestrictionViolationException("list_contains_element"); case ATTRIBUTE_CONTEXT: throw new RestrictionViolationException("attribute_contains_element"); } checkedRestrictions = true; try { p.checkRestrictions(ELEMENT_CONTEXT, new DuplicateAttributeDetector(), null); } catch (RestrictionViolationException e) { checkedRestrictions = false; e.maybeSetLocator(loc); throw e; } } Pattern expand(SchemaPatternBuilder b) { if (!expanded) { expanded = true; p = p.expand(b); if (p.isNotAllowed()) nameClass = new NullNameClass(); } return this; } boolean samePattern(Pattern other) { if (!(other instanceof ElementPattern)) return false; ElementPattern ep = (ElementPattern)other; return nameClass.equals(ep.nameClass) && p == ep.p; } void checkRecursion(int depth) throws SAXException { p.checkRecursion(depth + 1); } T apply(PatternFunction f) { return f.caseElement(this); } void setContent(Pattern p) { this.p = p; } Pattern getContent() { return p; } NameClass getNameClass() { return nameClass; } Locator getLocator() { return loc; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/EmptyPattern.java000066400000000000000000000012531225366607500332660ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class EmptyPattern extends Pattern { EmptyPattern() { super(true, EMPTY_CONTENT_TYPE, EMPTY_HASH_CODE); } boolean samePattern(Pattern other) { return other instanceof EmptyPattern; } T apply(PatternFunction f) { return f.caseEmpty(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_empty"); case START_CONTEXT: throw new RestrictionViolationException("start_contains_empty"); } } } EndAttributesFunction.java000066400000000000000000000035321225366607500350400ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class EndAttributesFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; EndAttributesFunction(ValidatorPatternBuilder builder) { this.builder = builder; } public Pattern caseOther(Pattern p) { return p; } public Pattern caseGroup(GroupPattern p) { Pattern p1 = p.getOperand1(); Pattern p2 = p.getOperand2(); Pattern q1 = memoApply(p1); Pattern q2 = memoApply(p2); if (p1 == q1 && p2 == q2) return p; return builder.makeGroup(q1, q2); } public Pattern caseInterleave(InterleavePattern p) { Pattern p1 = p.getOperand1(); Pattern p2 = p.getOperand2(); Pattern q1 = memoApply(p1); Pattern q2 = memoApply(p2); if (p1 == q1 && p2 == q2) return p; return builder.makeInterleave(q1, q2); } public Pattern caseChoice(ChoicePattern p) { Pattern p1 = p.getOperand1(); Pattern p2 = p.getOperand2(); Pattern q1 = memoApply(p1); Pattern q2 = memoApply(p2); if (p1 == q1 && p2 == q2) return p; return builder.makeChoice(q1, q2); } public Pattern caseOneOrMore(OneOrMorePattern p) { Pattern p1 = p.getOperand(); Pattern q1 = memoApply(p1); if (p1 == q1) return p; return builder.makeOneOrMore(q1); } public Pattern caseAfter(AfterPattern p) { Pattern p1 = p.getOperand1(); Pattern q1 = memoApply(p1); if (p1 == q1) return p; return builder.makeAfter(q1, p.getOperand2()); } public Pattern caseAttribute(AttributePattern p) { return builder.makeNotAllowed(); } final Pattern memoApply(Pattern p) { return apply(builder.getPatternMemo(p)).getPattern(); } PatternMemo apply(PatternMemo memo) { return memo.endAttributes(this); } ValidatorPatternBuilder getPatternBuilder() { return builder; } } EndTagDerivFunction.java000066400000000000000000000015131225366607500344140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class EndTagDerivFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; EndTagDerivFunction(ValidatorPatternBuilder builder) { this.builder = builder; } public Pattern caseOther(Pattern p) { return builder.makeNotAllowed(); } public Pattern caseChoice(ChoicePattern p) { return builder.makeChoice(memoApply(p.getOperand1()), memoApply(p.getOperand2())); } public Pattern caseAfter(AfterPattern p) { if (p.getOperand1().isNullable()) return p.getOperand2(); else return builder.makeNotAllowed(); } private Pattern memoApply(Pattern p) { return apply(builder.getPatternMemo(p)).getPattern(); } private PatternMemo apply(PatternMemo memo) { return memo.endTagDeriv(this); } } ErrorNameClass.java000066400000000000000000000006251225366607500334350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class ErrorNameClass implements NameClass { public boolean contains(Name name) { return false; } public int containsSpecificity(Name name) { return SPECIFICITY_NONE; } public void accept(NameClassVisitor visitor) { visitor.visitError(); } public boolean isOpen() { return false; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/ErrorPattern.java000066400000000000000000000005001225366607500332530ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class ErrorPattern extends Pattern { ErrorPattern() { super(false, EMPTY_CONTENT_TYPE, ERROR_HASH_CODE); } boolean samePattern(Pattern other) { return other instanceof ErrorPattern; } T apply(PatternFunction f) { return f.caseError(this); } } FeasibleTransform.java000066400000000000000000000026221225366607500341620ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import java.util.HashSet; import java.util.Set; public class FeasibleTransform { private static class FeasiblePatternFunction extends AbstractPatternFunction { private final SchemaPatternBuilder spb; private final Set elementDone = new HashSet(); FeasiblePatternFunction(SchemaPatternBuilder spb) { this.spb = spb; } public Pattern caseChoice(ChoicePattern p) { return spb.makeChoice(p.getOperand1().apply(this), p.getOperand2().apply(this)); } public Pattern caseGroup(GroupPattern p) { return spb.makeGroup(p.getOperand1().apply(this), p.getOperand2().apply(this)); } public Pattern caseInterleave(InterleavePattern p) { return spb.makeInterleave(p.getOperand1().apply(this), p.getOperand2().apply(this)); } public Pattern caseOneOrMore(OneOrMorePattern p) { return spb.makeOneOrMore(p.getOperand().apply(this)); } public Pattern caseElement(ElementPattern p) { if (!elementDone.contains(p)) { elementDone.add(p); p.setContent(p.getContent().apply(this)); } return spb.makeOptional(p); } public Pattern caseOther(Pattern p) { return spb.makeOptional(p); } } public static Pattern transform(SchemaPatternBuilder spb, Pattern p) { return p.apply(new FeasiblePatternFunction(spb)); } } FindElementFunction.java000066400000000000000000000041131225366607500344510ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import java.util.HashSet; import java.util.Set; class FindElementFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; private final Name name; private final Set processed = new HashSet(); private int specificity = NameClass.SPECIFICITY_NONE; private Pattern pattern = null; static public Pattern findElement(ValidatorPatternBuilder builder, Name name, Pattern start) { FindElementFunction f = new FindElementFunction(builder, name); start.apply(f); if (f.pattern == null) return builder.makeNotAllowed(); return f.pattern; } private FindElementFunction(ValidatorPatternBuilder builder, Name name) { this.builder = builder; this.name = name; } private boolean haveProcessed(Pattern p) { if (processed.contains(p)) return true; processed.add(p); return false; } private VoidValue caseBinary(BinaryPattern p) { if (!haveProcessed(p)) { p.getOperand1().apply(this); p.getOperand2().apply(this); } return VoidValue.VOID; } public VoidValue caseGroup(GroupPattern p) { return caseBinary(p); } public VoidValue caseInterleave(InterleavePattern p) { return caseBinary(p); } public VoidValue caseChoice(ChoicePattern p) { return caseBinary(p); } public VoidValue caseOneOrMore(OneOrMorePattern p) { if (!haveProcessed(p)) p.getOperand().apply(this); return VoidValue.VOID; } public VoidValue caseElement(ElementPattern p) { if (!haveProcessed(p)) { int s = p.getNameClass().containsSpecificity(name); if (s > specificity) { specificity = s; pattern = p.getContent(); } else if (s == specificity && s != NameClass.SPECIFICITY_NONE) pattern = builder.makeChoice(pattern, p.getContent()); p.getContent().apply(this); } return VoidValue.VOID; } public VoidValue caseOther(Pattern p) { return VoidValue.VOID; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/GroupPattern.java000066400000000000000000000022761225366607500332720ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class GroupPattern extends BinaryPattern { GroupPattern(Pattern p1, Pattern p2) { super(p1.isNullable() && p2.isNullable(), combineHashCode(GROUP_HASH_CODE, p1.hashCode(), p2.hashCode()), p1, p2); } Pattern expand(SchemaPatternBuilder b) { Pattern ep1 = p1.expand(b); Pattern ep2 = p2.expand(b); if (ep1 != p1 || ep2 != p2) return b.makeGroup(ep1, ep2); else return this; } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_group"); case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_group"); } super.checkRestrictions(context == ELEMENT_REPEAT_CONTEXT ? ELEMENT_REPEAT_GROUP_CONTEXT : context, dad, alpha); if (context != LIST_CONTEXT && !contentTypeGroupable(p1.getContentType(), p2.getContentType())) throw new RestrictionViolationException("group_string"); } T apply(PatternFunction f) { return f.caseGroup(this); } } IdSoundnessChecker.java000066400000000000000000000065111225366607500343000ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.StringSplitter; import org.relaxng.datatype.Datatype; 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.LocatorImpl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class IdSoundnessChecker { private final IdTypeMap idTypeMap; private final ErrorHandler eh; private final Map map = new HashMap(); private static class Entry { Locator idLoc; List idrefLocs; boolean hadId; } public IdSoundnessChecker(IdTypeMap idTypeMap, ErrorHandler eh) { this.idTypeMap = idTypeMap; this.eh = eh; } public void reset() { map.clear(); } public void endDocument() throws SAXException { for (String token : map.keySet()) { Entry entry = map.get(token); if (!entry.hadId) { for (LocatorImpl idrefLoc : entry.idrefLocs) error("missing_id", token, idrefLoc); } } } public void attribute(Name elementName, Name attributeName, String value, Locator locator) throws SAXException { int idType = idTypeMap.getIdType(elementName, attributeName); if (idType != Datatype.ID_TYPE_NULL) { String[] tokens = StringSplitter.split(value); switch (idType) { case Datatype.ID_TYPE_ID: if (tokens.length == 1) id(tokens[0], locator); else if (tokens.length == 0) error("id_no_tokens", locator); else error("id_multiple_tokens", locator); break; case Datatype.ID_TYPE_IDREF: if (tokens.length == 1) idref(tokens[0], locator); else if (tokens.length == 0) error("idref_no_tokens", locator); else error("idref_multiple_tokens", locator); break; case Datatype.ID_TYPE_IDREFS: if (tokens.length > 0) { for (int j = 0; j < tokens.length; j++) idref(tokens[j], locator); } else error("idrefs_no_tokens", locator); break; } } } private void id(String token, Locator locator) throws SAXException { Entry entry = map.get(token); if (entry == null) { entry = new Entry(); map.put(token, entry); } else if (entry.hadId) { error("duplicate_id", token, locator); error("first_id", token, entry.idLoc); return; } entry.idLoc = new LocatorImpl(locator); entry.hadId = true; } private void idref(String token, Locator locator) { Entry entry = map.get(token); if (entry == null) { entry = new Entry(); map.put(token, entry); } if (entry.hadId) return; if (entry.idrefLocs == null) entry.idrefLocs = new ArrayList(); entry.idrefLocs.add(new LocatorImpl(locator)); } private void error(String key, Locator locator) throws SAXException { eh.error(new SAXParseException(SchemaBuilderImpl.localizer.message(key), locator)); } private void error(String key, String arg, Locator locator) throws SAXException { eh.error(new SAXParseException(SchemaBuilderImpl.localizer.message(key, arg), locator)); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/IdTypeMap.java000066400000000000000000000002551225366607500324670ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; public interface IdTypeMap { int getIdType(Name elementName, Name attributeName); } IdTypeMapBuilder.java000066400000000000000000000235171225366607500337250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; public class IdTypeMapBuilder { private boolean hadError; private final ErrorHandler eh; private final PatternFunction idTypeFunction = new IdTypeFunction(); private final IdTypeMapImpl idTypeMap = new IdTypeMapImpl(); private final Set elementProcessed = new HashSet(); private final Stack elementsToProcess = new Stack(); private final List possibleConflicts = new ArrayList(); private void notePossibleConflict(NameClass elementNameClass, NameClass attributeNameClass, Locator loc) { possibleConflicts.add(new PossibleConflict(elementNameClass, attributeNameClass, loc)); } private static class WrappedSAXException extends RuntimeException { private final SAXException cause; WrappedSAXException(SAXException cause) { this.cause = cause; } } private static class PossibleConflict { private final NameClass elementNameClass; private final NameClass attributeNameClass; private final Locator locator; private PossibleConflict(NameClass elementNameClass, NameClass attributeNameClass, Locator locator) { this.elementNameClass = elementNameClass; this.attributeNameClass = attributeNameClass; this.locator = locator; } } private static class ScopedName { private final Name elementName; private final Name attributeName; private ScopedName(Name elementName, Name attributeName) { this.elementName = elementName; this.attributeName = attributeName; } public int hashCode() { return elementName.hashCode() ^ attributeName.hashCode(); } public boolean equals(Object obj) { if (!(obj instanceof ScopedName)) return false; ScopedName other = (ScopedName)obj; return elementName.equals(other.elementName) && attributeName.equals(other.attributeName); } } private static class IdTypeMapImpl implements IdTypeMap { private final Map table = new HashMap(); public int getIdType(Name elementName, Name attributeName) { Integer n = table.get(new ScopedName(elementName, attributeName)); if (n == null) return Datatype.ID_TYPE_NULL; return n; } private void add(Name elementName, Name attributeName, int idType) { table.put(new ScopedName(elementName, attributeName), idType); } } private class IdTypeFunction extends AbstractPatternFunction { public Integer caseOther(Pattern p) { return Datatype.ID_TYPE_NULL; } public Integer caseData(DataPattern p) { return p.getDatatype().getIdType(); } public Integer caseDataExcept(DataExceptPattern p) { return p.getDatatype().getIdType(); } public Integer caseValue(ValuePattern p) { return p.getDatatype().getIdType(); } } private class BuildFunction extends AbstractPatternFunction { private final NameClass elementNameClass; private final Locator locator; private final boolean attributeIsParent; BuildFunction(NameClass elementNameClass, Locator locator) { this.elementNameClass = elementNameClass; this.locator = locator; this.attributeIsParent = false; } BuildFunction(NameClass elementNameClass, Locator locator, boolean attributeIsParent) { this.elementNameClass = elementNameClass; this.locator = locator; this.attributeIsParent = attributeIsParent; } private BuildFunction down() { if (!attributeIsParent) return this; return new BuildFunction(elementNameClass, locator, false); } public VoidValue caseChoice(ChoicePattern p) { BuildFunction f = down(); p.getOperand1().apply(f); p.getOperand2().apply(f); return VoidValue.VOID; } public VoidValue caseInterleave(InterleavePattern p) { BuildFunction f = down(); p.getOperand1().apply(f); p.getOperand2().apply(f); return VoidValue.VOID; } public VoidValue caseGroup(GroupPattern p) { BuildFunction f = down(); p.getOperand1().apply(f); p.getOperand2().apply(f); return VoidValue.VOID; } public VoidValue caseOneOrMore(OneOrMorePattern p) { p.getOperand().apply(down()); return VoidValue.VOID; } public VoidValue caseElement(ElementPattern p) { if (elementProcessed.contains(p)) return VoidValue.VOID; elementProcessed.add(p); elementsToProcess.push(p); return VoidValue.VOID; } public VoidValue caseAttribute(AttributePattern p) { int idType = p.getContent().apply(idTypeFunction); if (idType != Datatype.ID_TYPE_NULL) { NameClass attributeNameClass = p.getNameClass(); if (!(attributeNameClass instanceof SimpleNameClass)) { error("id_attribute_name_class", p.getLocator()); return VoidValue.VOID; } elementNameClass.accept(new ElementNameClassVisitor(((SimpleNameClass)attributeNameClass).getName(), locator, idType)); } else notePossibleConflict(elementNameClass, p.getNameClass(), locator); p.getContent().apply(new BuildFunction(null, p.getLocator(), true)); return VoidValue.VOID; } private void datatype(Datatype dt) { if (dt.getIdType() != Datatype.ID_TYPE_NULL && !attributeIsParent) error("id_parent", locator); } public VoidValue caseData(DataPattern p) { datatype(p.getDatatype()); return VoidValue.VOID; } public VoidValue caseDataExcept(DataExceptPattern p) { datatype(p.getDatatype()); p.getExcept().apply(down()); return VoidValue.VOID; } public VoidValue caseValue(ValuePattern p) { datatype(p.getDatatype()); return VoidValue.VOID; } public VoidValue caseList(ListPattern p) { p.getOperand().apply(down()); return VoidValue.VOID; } public VoidValue caseOther(Pattern p) { return VoidValue.VOID; } } private class ElementNameClassVisitor implements NameClassVisitor { private final Name attributeName; private final Locator locator; private final int idType; ElementNameClassVisitor(Name attributeName, Locator locator, int idType) { this.attributeName = attributeName; this.locator = locator; this.idType = idType; } public void visitChoice(NameClass nc1, NameClass nc2) { nc1.accept(this); nc2.accept(this); } public void visitName(Name elementName) { int tem = idTypeMap.getIdType(elementName, attributeName); if (tem != Datatype.ID_TYPE_NULL && tem != idType) error("id_type_conflict", elementName, attributeName, locator); idTypeMap.add(elementName, attributeName, idType); } public void visitNsName(String ns) { visitOther(); } public void visitNsNameExcept(String ns, NameClass nc) { visitOther(); } public void visitAnyName() { visitOther(); } public void visitAnyNameExcept(NameClass nc) { visitOther(); } public void visitNull() { } public void visitError() { } private void visitOther() { error("id_element_name_class", locator); } } private void error(String key, Locator locator) { hadError = true; if (eh != null) try { eh.error(new SAXParseException(SchemaBuilderImpl.localizer.message(key), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } private void error(String key, Name arg1, Name arg2, Locator locator) { hadError = true; if (eh != null) try { eh.error(new SAXParseException(SchemaBuilderImpl.localizer.message(key, NameFormatter.format(arg1), NameFormatter.format(arg2)), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public IdTypeMapBuilder(ErrorHandler eh, Pattern pattern) throws SAXException { this.eh = eh; try { pattern.apply(new BuildFunction(null, null)); while (elementsToProcess.size() > 0) { ElementPattern p = elementsToProcess.pop(); p.getContent().apply(new BuildFunction(p.getNameClass(), p.getLocator())); } for (PossibleConflict pc : possibleConflicts) { if (pc.elementNameClass instanceof SimpleNameClass && pc.attributeNameClass instanceof SimpleNameClass) { Name elementName = ((SimpleNameClass)pc.elementNameClass).getName(); Name attributeName = ((SimpleNameClass)pc.attributeNameClass).getName(); int idType = idTypeMap.getIdType(elementName, attributeName); if (idType != Datatype.ID_TYPE_NULL) error("id_type_conflict", elementName, attributeName, pc.locator); } else { for (ScopedName sn : idTypeMap.table.keySet()) { if (pc.elementNameClass.contains(sn.elementName) && pc.attributeNameClass.contains(sn.attributeName)) { error("id_type_conflict", sn.elementName, sn.attributeName, pc.locator); break; } } } } } catch (WrappedSAXException e) { throw e.cause; } } public IdTypeMap getIdTypeMap() { if (hadError) return null; return idTypeMap; } } IgnoreMissingAttributesFunction.java000066400000000000000000000006241225366607500371060ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class IgnoreMissingAttributesFunction extends EndAttributesFunction { IgnoreMissingAttributesFunction(ValidatorPatternBuilder builder) { super(builder); } public Pattern caseAttribute(AttributePattern p) { return getPatternBuilder().makeEmpty(); } PatternMemo apply(PatternMemo memo) { return memo.ignoreMissingAttributes(this); } } InconsistentDataDerivType.java000066400000000000000000000006561225366607500356670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class InconsistentDataDerivType extends DataDerivType { static private final InconsistentDataDerivType instance = new InconsistentDataDerivType(); static InconsistentDataDerivType getInstance() { return instance; } private InconsistentDataDerivType() { } DataDerivType combine(DataDerivType ddt) { return this; } DataDerivType copy() { return this; } } InterleavePattern.java000066400000000000000000000035541225366607500342150ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class InterleavePattern extends BinaryPattern { InterleavePattern(Pattern p1, Pattern p2) { super(p1.isNullable() && p2.isNullable(), combineHashCode(INTERLEAVE_HASH_CODE, p1.hashCode(), p2.hashCode()), p1, p2); } Pattern expand(SchemaPatternBuilder b) { Pattern ep1 = p1.expand(b); Pattern ep2 = p2.expand(b); if (ep1 != p1 || ep2 != p2) return b.makeInterleave(ep1, ep2); else return this; } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_interleave"); case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_interleave"); case LIST_CONTEXT: throw new RestrictionViolationException("list_contains_interleave"); } if (context == ELEMENT_REPEAT_CONTEXT) context = ELEMENT_REPEAT_INTERLEAVE_CONTEXT; Alphabet a1; if (alpha != null && alpha.isEmpty()) a1 = alpha; else a1 = new Alphabet(); p1.checkRestrictions(context, dad, a1); if (a1.isEmpty()) p2.checkRestrictions(context, dad, a1); else { Alphabet a2 = new Alphabet(); p2.checkRestrictions(context, dad, a2); a1.checkOverlap(a2); if (alpha != null) { if (alpha != a1) alpha.addAlphabet(a1); alpha.addAlphabet(a2); } } if (!contentTypeGroupable(p1.getContentType(), p2.getContentType())) throw new RestrictionViolationException("interleave_string"); if (p1.getContentType() == MIXED_CONTENT_TYPE && p2.getContentType() == MIXED_CONTENT_TYPE) throw new RestrictionViolationException("interleave_text_overlap"); } T apply(PatternFunction f) { return f.caseInterleave(this); } } IntersectionNameClassNormalizer.java000066400000000000000000000015751225366607500370620ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Computes the normalized intersection of zero or more name classes. */ public class IntersectionNameClassNormalizer extends AbstractNameClassNormalizer { private final List nameClasses = new ArrayList(); public void add(NameClass nc) { nameClasses.add(nc); } protected void accept(NameClassVisitor visitor) { for (NameClass nameClass : nameClasses) (nameClass).accept(visitor); } protected boolean contains(Name name) { Iterator iter = nameClasses.iterator(); if (!iter.hasNext()) return false; for (;;) { if (!(iter.next()).contains(name)) return false; if (!iter.hasNext()) break; } return true; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/ListPattern.java000066400000000000000000000027371225366607500331130ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import org.xml.sax.Locator; import org.xml.sax.SAXException; class ListPattern extends Pattern { private final Pattern p; private final Locator locator; ListPattern(Pattern p, Locator locator) { super(false, DATA_CONTENT_TYPE, combineHashCode(LIST_HASH_CODE, p.hashCode())); this.p = p; this.locator = locator; } Pattern expand(SchemaPatternBuilder b) { Pattern ep = p.expand(b); if (ep != p) return b.makeList(ep, locator); else return this; } void checkRecursion(int depth) throws SAXException { p.checkRecursion(depth); } boolean samePattern(Pattern other) { return (other instanceof ListPattern && p == ((ListPattern)other).p); } T apply(PatternFunction f) { return f.caseList(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_list"); case START_CONTEXT: throw new RestrictionViolationException("start_contains_list"); case LIST_CONTEXT: throw new RestrictionViolationException("list_contains_list"); } try { p.checkRestrictions(LIST_CONTEXT, dad, null); } catch (RestrictionViolationException e) { e.maybeSetLocator(locator); throw e; } } Pattern getOperand() { return p; } } MatchablePatternImpl.java000066400000000000000000000010171225366607500346110ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.relaxng.match.MatchablePattern; import com.thaiopensource.relaxng.match.Matcher; public class MatchablePatternImpl implements MatchablePattern { private final SchemaPatternBuilder spb; private final Pattern start; public MatchablePatternImpl(SchemaPatternBuilder spb, Pattern start) { this.spb = spb; this.start = start; } public Matcher createMatcher() { return new PatternMatcher(start, new ValidatorPatternBuilder(spb)); } } MixedTextDerivFunction.java000066400000000000000000000025521225366607500351710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class MixedTextDerivFunction extends EndAttributesFunction { MixedTextDerivFunction(ValidatorPatternBuilder builder) { super(builder); } public Pattern caseText(TextPattern p) { return p; } public Pattern caseGroup(GroupPattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); final Pattern q1 = memoApply(p1); Pattern tem = (q1 == p1) ? p : getPatternBuilder().makeGroup(q1, p2); if (!p1.isNullable()) return tem; return getPatternBuilder().makeChoice(tem, memoApply(p2)); } public Pattern caseInterleave(InterleavePattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); final Pattern q1 = memoApply(p1); final Pattern q2 = memoApply(p2); final Pattern i1 = (q1 == p1) ? p : getPatternBuilder().makeInterleave(q1, p2); final Pattern i2 = (q2 == p2) ? p : getPatternBuilder().makeInterleave(p1, q2); return getPatternBuilder().makeChoice(i1, i2); } public Pattern caseOneOrMore(OneOrMorePattern p) { return getPatternBuilder().makeGroup(memoApply(p.getOperand()), getPatternBuilder().makeOptional(p)); } public Pattern caseOther(Pattern p) { return getPatternBuilder().makeNotAllowed(); } PatternMemo apply(PatternMemo memo) { return memo.mixedTextDeriv(this); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/NameClass.java000066400000000000000000000006441225366607500325030ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; public interface NameClass { static final int SPECIFICITY_NONE = -1; static final int SPECIFICITY_ANY_NAME = 0; static final int SPECIFICITY_NS_NAME = 1; static final int SPECIFICITY_NAME = 2; boolean contains(Name name); int containsSpecificity(Name name); void accept(NameClassVisitor visitor); boolean isOpen(); } NameClassNormalizer.java000066400000000000000000000012011225366607500344550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; /** * Normalizes a name classes. */ public class NameClassNormalizer extends AbstractNameClassNormalizer { private NameClass nameClass; public NameClassNormalizer(NameClass nameClass) { this.nameClass = nameClass; } protected boolean contains(Name name) { return nameClass.contains(name); } protected void accept(NameClassVisitor visitor) { nameClass.accept(visitor); } public NameClass getNameClass() { return nameClass; } public void setNameClass(NameClass nameClass) { this.nameClass = nameClass; } } NameClassVisitor.java000066400000000000000000000006071225366607500340030ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; public interface NameClassVisitor { void visitChoice(NameClass nc1, NameClass nc2); void visitNsName(String ns); void visitNsNameExcept(String ns, NameClass nc); void visitAnyName(); void visitAnyNameExcept(NameClass nc); void visitName(Name name); void visitNull(); void visitError(); } NameFormatter.java000066400000000000000000000007301225366607500333160ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class NameFormatter { static String format(Name name) { String localName = name.getLocalName(); String namespaceUri = name.getNamespaceUri(); if (namespaceUri.equals("")) return SchemaBuilderImpl.localizer.message("name_absent_namespace", localName); else return SchemaBuilderImpl.localizer.message("name_with_namespace", namespaceUri, localName); } } NormalizedAnyNameClass.java000066400000000000000000000031451225366607500351200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Set; /** * A NormalizedNameClass that includes an any name wildcard. */ public class NormalizedAnyNameClass extends NormalizedNameClass { private final Set excludedNamespaces; private final Set excludedNames; public NormalizedAnyNameClass(Set includedNames, Set excludedNamespaces, Set excludedNames) { super(includedNames); this.excludedNamespaces = immutable(excludedNamespaces); this.excludedNames = immutable(excludedNames); } public boolean isAnyNameIncluded() { return true; } public boolean contains(Name name) { if (excludedNamespaces.contains(name.getNamespaceUri())) return super.contains(name); else return !excludedNames.contains(name); } public boolean isEmpty() { return false; } public Set getExcludedNamespaces() { return excludedNamespaces; } public Set getExcludedNames() { return excludedNames; } public int hashCode() { return super.hashCode() ^ excludedNamespaces.hashCode() ^ excludedNames.hashCode(); } public boolean equals(Object obj) { if (!(obj instanceof NormalizedAnyNameClass)) return false; NormalizedAnyNameClass other = (NormalizedAnyNameClass)obj; if (!(excludedNamespaces.equals(other.excludedNamespaces))) return false; if (!(excludedNames.equals(other.excludedNames))) return false; return equal(this, other); } boolean includesNamespace(String ns) { return !getExcludedNamespaces().contains(ns); } } NormalizedNameClass.java000066400000000000000000000031721225366607500344500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Collections; import java.util.Set; /** * Base class for all implementations of com.thaiopensource.relaxng.match.NameClass. */ public abstract class NormalizedNameClass implements com.thaiopensource.relaxng.match.NameClass { private final Set includedNames; /** * Create a NormalizedNameClass representing a name class without any wildcards. * @param includedNames an immutable set of names */ public NormalizedNameClass(Set includedNames) { this.includedNames = immutable(includedNames); } public boolean isEmpty() { return includedNames.isEmpty(); } public boolean contains(Name name) { return includedNames.contains(name); } public boolean isAnyNameIncluded() { return false; } public Set getExcludedNamespaces() { return null; } public Set getIncludedNames() { return includedNames; } public Set getExcludedNames() { return null; } public Set getIncludedNamespaces() { return Collections.emptySet(); } public Set getExcludedLocalNames(String ns) { return null; } public abstract boolean equals(Object obj); boolean equal(NormalizedNameClass nc1, NormalizedNameClass nc2) { return nc1.includedNames.equals(nc2.includedNames); } public int hashCode() { return includedNames.hashCode(); } Set immutable(Set set) { if (set.isEmpty()) return Collections.emptySet(); return Collections.unmodifiableSet(set); } abstract boolean includesNamespace(String ns); } NormalizedNsNameClass.java000066400000000000000000000030041225366607500347430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Map; import java.util.Set; /** * A NormalizedNsNameClass that contains one or more namespace wildcards. */ public class NormalizedNsNameClass extends NormalizedNameClass { private final Map> nsMap; private final Set includedNamespaces; public NormalizedNsNameClass(Set includedNames, Map> nsMap) { super(includedNames); this.nsMap = nsMap; includedNamespaces = immutable(nsMap.keySet()); } public boolean isEmpty() { return super.isEmpty() && nsMap.isEmpty(); } public boolean contains(Name name) { Set excludedLocalNames = nsMap.get(name.getNamespaceUri()); if (excludedLocalNames == null) return super.contains(name); else return !excludedLocalNames.contains(name.getLocalName()); } public Set getIncludedNamespaces() { return includedNamespaces; } public Set getExcludedLocalNames(String ns) { return nsMap.get(ns); } public int hashCode() { return super.hashCode() ^ nsMap.hashCode(); } public boolean equals(Object obj) { if (!(obj instanceof NormalizedNsNameClass)) return false; NormalizedNsNameClass other = (NormalizedNsNameClass)obj; if (!nsMap.equals(other.nsMap)) return false; return equal(this, other); } boolean includesNamespace(String ns) { return getIncludedNamespaces().contains(ns); } } NotAllowedPattern.java000066400000000000000000000007001225366607500341550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class NotAllowedPattern extends Pattern { NotAllowedPattern() { super(false, EMPTY_CONTENT_TYPE, NOT_ALLOWED_HASH_CODE); } boolean isNotAllowed() { return true; } boolean samePattern(Pattern other) { // needs to work for UnexpandedNotAllowedPattern return other.getClass() == this.getClass(); } T apply(PatternFunction f) { return f.caseNotAllowed(this); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/NsNameClass.java000066400000000000000000000016421225366607500330030ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class NsNameClass implements NameClass { private final String namespaceUri; NsNameClass(String namespaceUri) { this.namespaceUri = namespaceUri; } public boolean contains(Name name) { return this.namespaceUri.equals(name.getNamespaceUri()); } public int containsSpecificity(Name name) { return contains(name) ? SPECIFICITY_NS_NAME : SPECIFICITY_NONE; } public int hashCode() { return namespaceUri.hashCode(); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof NsNameClass)) return false; return namespaceUri.equals(((NsNameClass)obj).namespaceUri); } public void accept(NameClassVisitor visitor) { visitor.visitNsName(namespaceUri); } public boolean isOpen() { return true; } public String getNamespaceUri() { return namespaceUri; } } NsNameExceptNameClass.java000066400000000000000000000022021225366607500346670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class NsNameExceptNameClass implements NameClass { private final NameClass nameClass; private final String namespaceURI; NsNameExceptNameClass(String namespaceURI, NameClass nameClass) { this.namespaceURI = namespaceURI; this.nameClass = nameClass; } public boolean contains(Name name) { return (this.namespaceURI.equals(name.getNamespaceUri()) && !nameClass.contains(name)); } public int containsSpecificity(Name name) { return contains(name) ? SPECIFICITY_NS_NAME : SPECIFICITY_NONE; } public boolean equals(Object obj) { if (obj == null || !(obj instanceof NsNameExceptNameClass)) return false; NsNameExceptNameClass other = (NsNameExceptNameClass)obj; return (namespaceURI.equals(other.namespaceURI) && nameClass.equals(other.nameClass)); } public int hashCode() { return namespaceURI.hashCode() ^ nameClass.hashCode(); } public void accept(NameClassVisitor visitor) { visitor.visitNsNameExcept(namespaceURI, nameClass); } public boolean isOpen() { return true; } } NullNameClass.java000066400000000000000000000013161225366607500332540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; /** * This is used for the name class of an element pattern when the content expands to notAllowed. */ class NullNameClass implements NameClass { public boolean contains(Name name) { return false; } public int containsSpecificity(Name name) { return SPECIFICITY_NONE; } public int hashCode() { return NullNameClass.class.hashCode(); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof NullNameClass)) return false; return true; } public void accept(NameClassVisitor visitor) { visitor.visitNull(); } public boolean isOpen() { return false; } } OneOrMorePattern.java000066400000000000000000000026771225366607500337710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.SAXException; class OneOrMorePattern extends Pattern { private final Pattern p; OneOrMorePattern(Pattern p) { super(p.isNullable(), p.getContentType(), combineHashCode(ONE_OR_MORE_HASH_CODE, p.hashCode())); this.p = p; } Pattern expand(SchemaPatternBuilder b) { Pattern ep = p.expand(b); if (ep != p) return b.makeOneOrMore(ep); else return this; } void checkRecursion(int depth) throws SAXException { p.checkRecursion(depth); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_one_or_more"); case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_one_or_more"); } p.checkRestrictions(context == ELEMENT_CONTEXT ? ELEMENT_REPEAT_CONTEXT : context, dad, alpha); if (context != LIST_CONTEXT && !contentTypeGroupable(p.getContentType(), p.getContentType())) throw new RestrictionViolationException("one_or_more_string"); } boolean samePattern(Pattern other) { return (other instanceof OneOrMorePattern && p == ((OneOrMorePattern)other).p); } T apply(PatternFunction f) { return f.caseOneOrMore(this); } Pattern getOperand() { return p; } } OverlapDetector.java000066400000000000000000000045701225366607500336620ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class OverlapDetector implements NameClassVisitor { private final NameClass nc1; private final NameClass nc2; private Name overlapExample = null; private static final String IMPOSSIBLE = "\u0000"; private OverlapDetector(NameClass nc1, NameClass nc2) { this.nc1 = nc1; this.nc2 = nc2; nc1.accept(this); nc2.accept(this); } private void probe(Name name) { if (nc1.contains(name) && nc2.contains(name)) overlapExample = name; } public void visitChoice(NameClass nc1, NameClass nc2) { nc1.accept(this); nc2.accept(this); } public void visitNsName(String ns) { probe(new Name(ns, IMPOSSIBLE)); } public void visitNsNameExcept(String ns, NameClass ex) { probe(new Name(ns, IMPOSSIBLE)); ex.accept(this); } public void visitAnyName() { probe(new Name(IMPOSSIBLE, IMPOSSIBLE)); } public void visitAnyNameExcept(NameClass ex) { probe(new Name(IMPOSSIBLE, IMPOSSIBLE)); ex.accept(this); } public void visitName(Name name) { probe(name); } public void visitNull() { } public void visitError() { } static void checkOverlap(NameClass nc1, NameClass nc2, String messageForName, String messageForNs, String messageForOther) throws RestrictionViolationException { if (nc2 instanceof SimpleNameClass) { SimpleNameClass snc = (SimpleNameClass)nc2; if (nc1.contains(snc.getName())) throw new RestrictionViolationException(messageForName, snc.getName()); } else if (nc1 instanceof SimpleNameClass) { SimpleNameClass snc = (SimpleNameClass)nc1; if (nc2.contains(snc.getName())) throw new RestrictionViolationException(messageForName, snc.getName()); } else { Name name = new OverlapDetector(nc1, nc2).overlapExample; if (name != null) { String localName = name.getLocalName(); if (localName == IMPOSSIBLE) { String ns = name.getNamespaceUri(); if (ns == IMPOSSIBLE) throw new RestrictionViolationException(messageForOther); else throw new RestrictionViolationException(messageForNs, ns); } else throw new RestrictionViolationException(messageForName, name); } } } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/Pattern.java000066400000000000000000000051571225366607500322560ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import org.xml.sax.SAXException; public abstract class Pattern { private final boolean nullable; private final int hc; private final int contentType; static final int TEXT_HASH_CODE = 1; static final int ERROR_HASH_CODE = 3; static final int EMPTY_HASH_CODE = 5; static final int NOT_ALLOWED_HASH_CODE = 7; static final int CHOICE_HASH_CODE = 11; static final int GROUP_HASH_CODE = 13; static final int INTERLEAVE_HASH_CODE = 17; static final int ONE_OR_MORE_HASH_CODE = 19; static final int ELEMENT_HASH_CODE = 23; static final int VALUE_HASH_CODE = 27; static final int ATTRIBUTE_HASH_CODE = 29; static final int DATA_HASH_CODE = 31; static final int LIST_HASH_CODE = 37; static final int AFTER_HASH_CODE = 41; static int combineHashCode(int hc1, int hc2, int hc3) { return hc1 * hc2 * hc3; } static int combineHashCode(int hc1, int hc2) { return hc1 * hc2; } static final int EMPTY_CONTENT_TYPE = 0; static final int ELEMENT_CONTENT_TYPE = 1; static final int MIXED_CONTENT_TYPE = 2; static final int DATA_CONTENT_TYPE = 3; Pattern(boolean nullable, int contentType, int hc) { this.nullable = nullable; this.contentType = contentType; this.hc = hc; } Pattern() { this.nullable = false; this.hc = hashCode(); this.contentType = EMPTY_CONTENT_TYPE; } void checkRecursion(int depth) throws SAXException { } Pattern expand(SchemaPatternBuilder b) { return this; } final boolean isNullable() { return nullable; } boolean isNotAllowed() { return false; } static final int START_CONTEXT = 0; static final int ELEMENT_CONTEXT = 1; static final int ELEMENT_REPEAT_CONTEXT = 2; static final int ELEMENT_REPEAT_GROUP_CONTEXT = 3; static final int ELEMENT_REPEAT_INTERLEAVE_CONTEXT = 4; static final int ATTRIBUTE_CONTEXT = 5; static final int LIST_CONTEXT = 6; static final int DATA_EXCEPT_CONTEXT = 7; void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { } // Know that other is not null abstract boolean samePattern(Pattern other); final int patternHashCode() { return hc; } final int getContentType() { return contentType; } boolean containsChoice(Pattern p) { return this == p; } abstract T apply(PatternFunction f); static boolean contentTypeGroupable(int ct1, int ct2) { if (ct1 == EMPTY_CONTENT_TYPE || ct2 == EMPTY_CONTENT_TYPE) return true; if (ct1 == DATA_CONTENT_TYPE || ct2 == DATA_CONTENT_TYPE) return false; return true; } } PatternBuilder.java000066400000000000000000000045511225366607500335030ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; public class PatternBuilder { private final EmptyPattern empty; protected final NotAllowedPattern notAllowed; protected final PatternInterner interner; public PatternBuilder() { empty = new EmptyPattern(); notAllowed = new NotAllowedPattern(); interner = new PatternInterner(); } public PatternBuilder(PatternBuilder parent) { empty = parent.empty; notAllowed = parent.notAllowed; interner = new PatternInterner(parent.interner); } Pattern makeEmpty() { return empty; } Pattern makeNotAllowed() { return notAllowed; } Pattern makeGroup(Pattern p1, Pattern p2) { if (p1 == empty) return p2; if (p2 == empty) return p1; if (p1 == notAllowed || p2 == notAllowed) return notAllowed; if (false && p1 instanceof GroupPattern) { GroupPattern sp = (GroupPattern)p1; return makeGroup(sp.p1, makeGroup(sp.p2, p2)); } Pattern p = new GroupPattern(p1, p2); return interner.intern(p); } Pattern makeInterleave(Pattern p1, Pattern p2) { if (p1 == empty) return p2; if (p2 == empty) return p1; if (p1 == notAllowed || p2 == notAllowed) return notAllowed; if (false && p1 instanceof InterleavePattern) { InterleavePattern ip = (InterleavePattern)p1; return makeInterleave(ip.p1, makeInterleave(ip.p2, p2)); } if (false) { if (p2 instanceof InterleavePattern) { InterleavePattern ip = (InterleavePattern)p2; if (p1.hashCode() > ip.p1.hashCode()) return makeInterleave(ip.p1, makeInterleave(p1, ip.p2)); } else if (p1.hashCode() > p2.hashCode()) return makeInterleave(p2, p1); } Pattern p = new InterleavePattern(p1, p2); return interner.intern(p); } Pattern makeChoice(Pattern p1, Pattern p2) { if (p1 == empty && p2.isNullable()) return p2; if (p2 == empty && p1.isNullable()) return p1; Pattern p = new ChoicePattern(p1, p2); return interner.intern(p); } Pattern makeOneOrMore(Pattern p) { if (p == empty || p == notAllowed || p instanceof OneOrMorePattern) return p; Pattern p1 = new OneOrMorePattern(p); return interner.intern(p1); } Pattern makeOptional(Pattern p) { return makeChoice(p, empty); } Pattern makeZeroOrMore(Pattern p) { return makeOptional(makeOneOrMore(p)); } } PatternDumper.java000066400000000000000000000312551225366607500333520ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import com.thaiopensource.xml.util.WellKnownNamespaces; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class PatternDumper { private static final String INTERNAL_NAMESPACE = "http://www.thaiopensource.com/relaxng/internal"; private boolean startTagOpen = false; private final ArrayList tagStack = new ArrayList(); private final StringBuilder buf; private int level = 0; private boolean suppressIndent = false; private final List patternList = new ArrayList(); private final Map localNamePatternCount = new HashMap(); private int otherPatternCount; private final Map patternNameMap = new HashMap(); private final PatternFunction dumper = new Dumper(); private final PatternFunction elementDumper = new ElementDumper(); private final PatternFunction optionalDumper = new OptionalDumper(); private final PatternFunction groupDumper = new GroupDumper(); private final PatternFunction choiceDumper = new ChoiceDumper(); private final PatternFunction interleaveDumper = new InterleaveDumper(); private final NameClassVisitor nameClassDumper = new NameClassDumper(); private final NameClassVisitor choiceNameClassDumper = new ChoiceNameClassDumper(); static public String toString(Pattern p) { return new PatternDumper().dump(p).getSchema(); } private PatternDumper() { buf = new StringBuilder(); } private String getSchema() { return buf.toString(); } private PatternDumper dump(Pattern p) { write(""); startElement("grammar"); attribute("xmlns", WellKnownNamespaces.RELAX_NG); startElement("start"); p.apply(dumper); endElement(); for (int i = 0; i < patternList.size(); i++) { startElement("define"); ElementPattern tem = patternList.get(i); attribute("name", getName(tem)); tem.apply(elementDumper); endElement(); } endElement(); write('\n'); return this; } private String getName(ElementPattern p) { String name = patternNameMap.get(p); // patterns for element patterns with local name X are named: X, X_2, X_3 // however if X is of the form Y_N (N > 0), then the patterns are named: X_1, X_2, X_3 // for element patterns with complex name classes, the patterns are named: _1, _2, _3 if (name == null) { NameClass nc = p.getNameClass(); if (nc instanceof SimpleNameClass) { String localName = ((SimpleNameClass)nc).getName().getLocalName(); Integer i = localNamePatternCount.get(localName); if (i == null) { i = 1; name = localName; // see if the name can be the same as one of our generated names int u = name.lastIndexOf('_'); if (u >= 0) { try { if (Integer.valueOf(name.substring(u + 1, name.length())) > 0) // it can, so transform it so that it cannot name += "_1"; } catch (NumberFormatException e) { // not a number, so cannot be the same as one of our generated names } } } else name = localName + "_" + ++i; localNamePatternCount.put(localName, i); } else name = "_" + ++otherPatternCount; patternList.add(p); patternNameMap.put(p, name); } return name; } private void startElement(String name) { closeStartTag(); indent(level); write('<'); write(name); push(name); startTagOpen = true; level++; } private void closeStartTag() { if (startTagOpen) { startTagOpen = false; write('>'); } } private void attribute(String name, String value) { write(' '); write(name); write('='); write('"'); chars(value, true); write('"'); } private void data(String str) { if (str.length() > 0) { closeStartTag(); chars(str, false); suppressIndent = true; } } private void chars(String str, boolean isAttribute) { int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); switch (c) { case '&': write("&"); break; case '<': write("<"); break; case '>': write(">"); break; case 0xD: write(" "); break; case 0xA: if (isAttribute) write(" "); else write(c); break; case 0x9: if (isAttribute) write(" "); else write(c); break; case '"': if (isAttribute) write("""); else write(c); break; default: write(c); break; } } } private void endElement() { --level; if (startTagOpen) { startTagOpen = false; write("/>"); pop(); } else { if (!suppressIndent) indent(level); write(""); } suppressIndent = false; } private void indent(int level) { write('\n'); for (int i = 0; i < level; i++) write(" "); } private void write(String str) { buf.append(str); } private void write(char c) { buf.append(c); } private void push(String s) { tagStack.add(s); } private String pop() { return tagStack.remove(tagStack.size() - 1); } class Dumper implements PatternFunction { public VoidValue caseEmpty(EmptyPattern p) { startElement("empty"); endElement(); return VoidValue.VOID; } public VoidValue caseNotAllowed(NotAllowedPattern p) { startElement("notAllowed"); endElement(); return VoidValue.VOID; } public VoidValue caseGroup(GroupPattern p) { startElement("group"); p.getOperand1().apply(groupDumper); p.getOperand2().apply(groupDumper); endElement(); return VoidValue.VOID; } public VoidValue caseInterleave(InterleavePattern p) { startElement("interleave"); p.getOperand1().apply(interleaveDumper); p.getOperand2().apply(interleaveDumper); endElement(); return VoidValue.VOID; } public VoidValue caseChoice(ChoicePattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); if (p1 instanceof EmptyPattern) p2.apply(optionalDumper); else if (p2 instanceof EmptyPattern) p1.apply(optionalDumper); else choice(p1, p2); return VoidValue.VOID; } protected void choice(Pattern p1, Pattern p2) { startElement("choice"); p1.apply(choiceDumper); p2.apply(choiceDumper); endElement(); } public VoidValue caseOneOrMore(OneOrMorePattern p) { startElement("oneOrMore"); p.getOperand().apply(dumper); endElement(); return VoidValue.VOID; } public VoidValue caseElement(ElementPattern p) { startElement("ref"); attribute("name", getName(p)); endElement(); return VoidValue.VOID; } public VoidValue caseAttribute(AttributePattern p) { startElement("attribute"); outputName(p.getNameClass()); p.getContent().apply(dumper); endElement(); return VoidValue.VOID; } protected void outputName(NameClass nc) { if (nc instanceof SimpleNameClass) { Name name = ((SimpleNameClass)nc).getName(); attribute("name", name.getLocalName()); attribute("ns", name.getNamespaceUri()); } else nc.accept(nameClassDumper); } public VoidValue caseData(DataPattern p) { startData(p); endElement(); return VoidValue.VOID; } private void startData(DataPattern p) { startElement("data"); final Name dtName = p.getDatatypeName(); attribute("type", dtName.getLocalName()); attribute("datatypeLibrary", dtName.getNamespaceUri()); for (Iterator iter = p.getParams().iterator(); iter.hasNext();) { startElement("param"); attribute("name", iter.next()); data(iter.next()); endElement(); } } public VoidValue caseDataExcept(DataExceptPattern p) { startData(p); startElement("except"); p.getExcept().apply(dumper); endElement(); endElement(); return VoidValue.VOID; } public VoidValue caseValue(ValuePattern p) { startElement("value"); Name dtName = p.getDatatypeName(); attribute("type", dtName.getLocalName()); attribute("datatypeLibrary", dtName.getNamespaceUri()); String stringValue = p.getStringValue(); final Object value = p.getValue(); String ns = ""; // XXX won't work with a datatypeLibrary that doesn't use Name to implement QName's if (value instanceof Name) { ns = ((Name)value).getNamespaceUri(); int colonIndex = stringValue.indexOf(':'); if (colonIndex < 0) stringValue = stringValue.substring(colonIndex + 1, stringValue.length()); } attribute("ns", ns); data(stringValue); endElement(); return VoidValue.VOID; } public VoidValue caseText(TextPattern p) { startElement("text"); endElement(); return VoidValue.VOID; } public VoidValue caseList(ListPattern p) { startElement("list"); p.getOperand().apply(dumper); endElement(); return VoidValue.VOID; } public VoidValue caseRef(RefPattern p) { return p.getPattern().apply(this); } public VoidValue caseAfter(AfterPattern p) { startElement("i:after"); attribute("xmlns:i", INTERNAL_NAMESPACE); p.getOperand1().apply(this); p.getOperand2().apply(this); endElement(); return VoidValue.VOID; } public VoidValue caseError(ErrorPattern p) { startElement("i:error"); attribute("xmlns:i", INTERNAL_NAMESPACE); endElement(); return VoidValue.VOID; } } class ElementDumper extends Dumper { public VoidValue caseElement(ElementPattern p) { startElement("element"); outputName(p.getNameClass()); p.getContent().apply(dumper); endElement(); return VoidValue.VOID; } } class OptionalDumper extends AbstractPatternFunction { public VoidValue caseOther(Pattern p) { startElement("optional"); p.apply(dumper); endElement(); return VoidValue.VOID; } public VoidValue caseOneOrMore(OneOrMorePattern p) { startElement("zeroOrMore"); p.getOperand().apply(dumper); endElement(); return VoidValue.VOID; } } class GroupDumper extends Dumper { public VoidValue caseGroup(GroupPattern p) { p.getOperand1().apply(this); p.getOperand2().apply(this); return VoidValue.VOID; } } class ChoiceDumper extends Dumper { protected void choice(Pattern p1, Pattern p2) { p1.apply(this); p2.apply(this); } } class InterleaveDumper extends Dumper { public VoidValue caseInterleave(InterleavePattern p) { p.getOperand1().apply(this); p.getOperand2().apply(this); return VoidValue.VOID; } } class NameClassDumper implements NameClassVisitor { public void visitChoice(NameClass nc1, NameClass nc2) { startElement("choice"); nc1.accept(choiceNameClassDumper); nc2.accept(choiceNameClassDumper); endElement(); } public void visitNsName(String ns) { startElement("nsName"); attribute("ns", ns); endElement(); } public void visitNsNameExcept(String ns, NameClass nc) { startElement("nsName"); attribute("ns", ns); startElement("except"); nc.accept(nameClassDumper); endElement(); endElement(); } public void visitAnyName() { startElement("anyName"); endElement(); } public void visitAnyNameExcept(NameClass nc) { startElement("anyName"); startElement("except"); nc.accept(nameClassDumper); endElement(); endElement(); } public void visitName(Name name) { startElement("name"); attribute("ns", name.getNamespaceUri()); data(name.getLocalName()); endElement(); } public void visitError() { startElement("error"); endElement(); } public void visitNull() { visitAnyName(); } } class ChoiceNameClassDumper extends NameClassDumper { public void visitChoice(NameClass nc1, NameClass nc2) { nc1.accept(this); nc2.accept(this); } } } PatternFunction.java000066400000000000000000000011501225366607500336720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; interface PatternFunction { T caseEmpty(EmptyPattern p); T caseNotAllowed(NotAllowedPattern p); T caseError(ErrorPattern p); T caseGroup(GroupPattern p); T caseInterleave(InterleavePattern p); T caseChoice(ChoicePattern p); T caseOneOrMore(OneOrMorePattern p); T caseElement(ElementPattern p); T caseAttribute(AttributePattern p); T caseData(DataPattern p); T caseDataExcept(DataExceptPattern p); T caseValue(ValuePattern p); T caseText(TextPattern p); T caseList(ListPattern p); T caseRef(RefPattern p); T caseAfter(AfterPattern p); } PatternFuture.java000066400000000000000000000004731225366607500333660ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.SAXException; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import java.io.IOException; public interface PatternFuture { Pattern getPattern(boolean isAttributesPattern) throws IllegalSchemaException, SAXException, IOException; } PatternInterner.java000066400000000000000000000027651225366607500337100ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; final class PatternInterner { private static final int INIT_SIZE = 256; private static final float LOAD_FACTOR = 0.3f; private Pattern[] table; private int used; private int usedLimit; PatternInterner() { table = null; used = 0; usedLimit = 0; } PatternInterner(PatternInterner parent) { table = parent.table; if (table != null) table = table.clone(); used = parent.used; usedLimit = parent.usedLimit; } Pattern intern(Pattern p) { int h; if (table == null) { table = new Pattern[INIT_SIZE]; usedLimit = (int)(INIT_SIZE * LOAD_FACTOR); h = firstIndex(p); } else { for (h = firstIndex(p); table[h] != null; h = nextIndex(h)) { if (p.samePattern(table[h])) return table[h]; } } if (used >= usedLimit) { // rehash Pattern[] oldTable = table; table = new Pattern[table.length << 1]; for (int i = oldTable.length; i > 0;) { --i; if (oldTable[i] != null) { int j; for (j = firstIndex(oldTable[i]); table[j] != null; j = nextIndex(j)) ; table[j] = oldTable[i]; } } for (h = firstIndex(p); table[h] != null; h = nextIndex(h)) ; usedLimit = (int)(table.length * LOAD_FACTOR); } used++; table[h] = p; return p; } private int firstIndex(Pattern p) { return p.patternHashCode() & (table.length - 1); } private int nextIndex(int i) { return i == 0 ? table.length - 1 : i - 1; } } PatternMatcher.java000066400000000000000000000571201225366607500335000ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.datatype.Datatype2; import com.thaiopensource.relaxng.match.MatchContext; import com.thaiopensource.relaxng.match.Matcher; import com.thaiopensource.util.Equal; import com.thaiopensource.util.Localizer; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class PatternMatcher implements Cloneable, Matcher { static private class Shared { private final Pattern start; private final ValidatorPatternBuilder builder; private Map recoverPatternTable; Shared(Pattern start, ValidatorPatternBuilder builder) { this.start = start; this.builder = builder; } Pattern findElement(Name name) { if (recoverPatternTable == null) recoverPatternTable = new HashMap(); Pattern p = recoverPatternTable.get(name); if (p == null) { p = FindElementFunction.findElement(builder, name, start); recoverPatternTable.put(name, p); } return p; } } private PatternMemo memo; private boolean textTyped; private boolean hadError; private boolean ignoreNextEndTagOrAttributeValue; private String errorMessage; private final Shared shared; private List dataDerivFailureList = new ArrayList(); public PatternMatcher(Pattern start, ValidatorPatternBuilder builder) { shared = new Shared(start, builder); memo = builder.getPatternMemo(start); } private PatternMatcher(PatternMemo memo, Shared shared) { this.memo = memo; this.shared = shared; } public Matcher start() { return new PatternMatcher(shared.builder.getPatternMemo(shared.start), shared); } public boolean equals(Object obj) { if (!(obj instanceof PatternMatcher)) return false; PatternMatcher other = (PatternMatcher)obj; // don't need to test equality of shared, because the memos can only be == // if the shareds are ==. return (memo == other.memo && hadError == other.hadError && Equal.equal(errorMessage, other.errorMessage) && ignoreNextEndTagOrAttributeValue == other.ignoreNextEndTagOrAttributeValue && textTyped == other.textTyped); } public int hashCode() { return memo.hashCode(); } public final Object clone() { try { PatternMatcher cloned = (PatternMatcher)super.clone(); cloned.dataDerivFailureList = new ArrayList(); return cloned; } catch (CloneNotSupportedException e) { throw new Error("unexpected CloneNotSupportedException"); } } public Matcher copy() { return (Matcher)clone(); } public boolean matchStartDocument() { if (memo.isNotAllowed()) return error("schema_allows_nothing"); return true; } public boolean matchEndDocument() { // XXX maybe check that memo.isNullable if !hadError return true; } public boolean matchStartTagOpen(Name name, String qName, MatchContext context) { if (setMemo(memo.startTagOpenDeriv(name))) return true; PatternMemo next = memo.startTagOpenRecoverDeriv(name); boolean ok = ignoreError(); if (!next.isNotAllowed()) { if (!ok) { Set missing = requiredElementNames(); if (!missing.isEmpty()) error(missing.size() == 1 ? "unexpected_element_required_element_missing" : "unexpected_element_required_elements_missing", errorArgQName(qName, name, context, false), formatNames(missing, FORMAT_NAMES_ELEMENT|FORMAT_NAMES_AND, context)); else error("element_not_allowed_yet", errorArgQName(qName, name, context, false), expectedContent(context)); } } else { final ValidatorPatternBuilder builder = shared.builder; next = builder.getPatternMemo(builder.makeAfter(shared.findElement(name), memo.getPattern())); if (!ok) error(next.isNotAllowed() ? "unknown_element" : "out_of_context_element", errorArgQName(qName, name, context, false), expectedContent(context)); } memo = next; return ok; } public boolean matchAttributeName(Name name, String qName, MatchContext context) { if (setMemo(memo.startAttributeDeriv(name))) return true; ignoreNextEndTagOrAttributeValue = true; boolean ok = ignoreError(); if (ok) return true; qName = errorArgQName(qName, name, context, true); NormalizedNameClass nnc = memo.possibleAttributeNames(); if (nnc.isEmpty()) error("no_attributes_allowed", qName); else error("invalid_attribute_name", qName, expectedAttributes(context)); return false; } public boolean matchAttributeValue(String value, Name name, String qName, MatchContext context) { if (ignoreNextEndTagOrAttributeValue) { ignoreNextEndTagOrAttributeValue = false; return true; } dataDerivFailureList.clear(); if (setMemo(memo.dataDeriv(value, context, dataDerivFailureList))) return true; boolean ok = error("invalid_attribute_value", errorArgQName(qName, name, context, true), formatDataDerivFailures(value, context)); memo = memo.recoverAfter(); return ok; } public boolean matchStartTagClose(Name name, String qName, MatchContext context) { boolean ok; if (setMemo(memo.endAttributes())) ok = true; else { ok = ignoreError(); if (!ok) { Set missing = requiredAttributeNames(); if (missing.isEmpty()) error("required_attributes_missing_expected", errorArgQName(qName, name, context, false), expectedAttributes(context)); else error(missing.size() == 1 ? "required_attribute_missing" : "required_attributes_missing", errorArgQName(qName, name, context, false), formatNames(missing, FORMAT_NAMES_ATTRIBUTE|FORMAT_NAMES_AND, context)); } memo = memo.ignoreMissingAttributes(); } textTyped = memo.getPattern().getContentType() == Pattern.DATA_CONTENT_TYPE; return ok; } public boolean matchTextBeforeEndTag(String string, Name name, String qName, MatchContext context) { if (textTyped) { ignoreNextEndTagOrAttributeValue = true; return setDataDeriv(string, name, qName, context); } else return matchUntypedText(string, context); } public boolean matchTextBeforeStartTag(String string, MatchContext context) { return matchUntypedText(string, context); } private boolean matchUntypedText(String string, MatchContext context) { if (DataDerivFunction.isBlank(string)) return true; return matchUntypedText(context); } public boolean matchUntypedText(MatchContext context) { if (setMemo(memo.mixedTextDeriv())) return true; return error("text_not_allowed", expectedContent(context)); } public boolean isTextTyped() { return textTyped; } private boolean setDataDeriv(String string, Name name, String qName, MatchContext context) { textTyped = false; PatternMemo textOnlyMemo = memo.textOnly(); dataDerivFailureList.clear(); if (setMemo(textOnlyMemo.dataDeriv(string, context, dataDerivFailureList))) return true; PatternMemo next = memo.recoverAfter(); boolean ok = ignoreError(); if (!ok && (!next.isNotAllowed() || textOnlyMemo.emptyAfter().dataDeriv(string, context).isNotAllowed())) { NormalizedNameClass nnc = memo.possibleStartTagNames(); if (!nnc.isEmpty() && DataDerivFunction.isBlank(string)) error("blank_not_allowed", errorArgQName(qName, name, context, false), expectedContent(context)); else error("invalid_element_value", errorArgQName(qName, name, context, false), formatDataDerivFailures(string, context)); } memo = next; return ok; } public boolean matchEndTag(Name name, String qName, MatchContext context) { if (ignoreNextEndTagOrAttributeValue) { ignoreNextEndTagOrAttributeValue = false; return true; } if (textTyped) return setDataDeriv("", name, qName, context); if (setMemo(memo.endTagDeriv())) return true; boolean ok = ignoreError(); PatternMemo next = memo.recoverAfter(); // The tricky thing here is that the derivative that we compute may be notAllowed simply because the parent // is notAllowed; we don't want to give an error in this case. if (!ok && (!next.isNotAllowed() // Retry computing the deriv on a pattern where the after is OK (not notAllowed) || memo.emptyAfter().endTagDeriv().isNotAllowed())) { Set missing = requiredElementNames(); if (!missing.isEmpty()) error(missing.size() == 1 ? "incomplete_element_required_element_missing" : "incomplete_element_required_elements_missing", errorArgQName(qName, name, context, false), formatNames(missing, FORMAT_NAMES_ELEMENT|FORMAT_NAMES_AND, context)); else // XXX Could do better here and describe what is required instead of what is possible error("incomplete_element_required_elements_missing_expected", errorArgQName(qName, name, context, false), expectedContent(context)); } memo = next; return ok; } public String getErrorMessage() { return errorMessage; } public boolean isValidSoFar() { return !hadError; } public com.thaiopensource.relaxng.match.NameClass possibleStartTagNames() { return memo.possibleStartTagNames(); } public com.thaiopensource.relaxng.match.NameClass possibleAttributeNames() { return memo.possibleAttributeNames(); } public Set requiredElementNames() { return memo.getPattern().apply(shared.builder.getRequiredElementsFunction()); } public Set requiredAttributeNames() { return memo.getPattern().apply(shared.builder.getRequiredAttributesFunction()); } private boolean setMemo(PatternMemo m) { if (m.isNotAllowed()) return false; else { memo = m; return true; } } private boolean ignoreError() { return hadError && memo.isNotAllowed(); } /* * Return true if the error was ignored, false otherwise. */ private boolean error(String key) { return error(key, new String[] { }); } private boolean error(String key, String arg) { return error(key, new String[] { arg }); } private boolean error(String key, String arg1, String arg2) { return error(key, new String[] { arg1, arg2 }); } private boolean error(String key, String arg1, String arg2, String arg3) { return error(key, new String[] { arg1, arg2, arg3 }); } private boolean error(String key, String[] args) { if (ignoreError()) return true; hadError = true; errorMessage = localizer().message(key, args); return false; } private String errorArgQName(String qName, Name name, MatchContext context, boolean isAttribute) { if (ignoreError()) return null; if (qName == null || qName.length() == 0) { final String ns = name.getNamespaceUri(); final String localName = name.getLocalName(); if (ns.length() == 0 || (!isAttribute && ns.equals(context.resolveNamespacePrefix("")))) qName = localName; else { String prefix = context.getPrefix(ns); if (prefix != null) qName = prefix + ":" + localName; // this shouldn't happen unless the parser isn't supplying prefixes properly else qName = "{" + ns + "}" + localName; } } return quoteQName(qName); } static private final int UNDEFINED_TOKEN_INDEX = -3; static private final int INCONSISTENT_TOKEN_INDEX = -2; private String formatDataDerivFailures(String str, MatchContext context) { if (ignoreError()) return null; if (dataDerivFailureList.size() == 0) return ""; if (dataDerivFailureList.size() > 1) { // remove duplicates Set failures = new HashSet(); failures.addAll(dataDerivFailureList); dataDerivFailureList.clear(); dataDerivFailureList.addAll(failures); } List stringValues = new ArrayList(); Set names = new HashSet(); List messages = new ArrayList(); int tokenIndex = UNDEFINED_TOKEN_INDEX; int tokenStart = -1; int tokenEnd = -1; for (DataDerivFailure fail : dataDerivFailureList) { Datatype dt = fail.getDatatype(); String s = fail.getStringValue(); if (s != null) { Object value = fail.getValue(); // we imply some special semantics for Datatype2 if (value instanceof Name && dt instanceof Datatype2) names.add((Name)value); else if (value instanceof String && dt instanceof Datatype2) stringValues.add((String)value); else stringValues.add(s); } else { String message = fail.getMessage(); // XXX this might produce strangely worded messages for 3rd party datatype libraries if (message != null) messages.add(message); else if (fail.getExcept() != null) return ""; // XXX do better for except else messages.add(localizer().message("require_datatype", fail.getDatatypeName().getLocalName())); } switch (tokenIndex) { case INCONSISTENT_TOKEN_INDEX: break; case UNDEFINED_TOKEN_INDEX: tokenIndex = fail.getTokenIndex(); tokenStart = fail.getTokenStart(); tokenEnd = fail.getTokenEnd(); break; default: if (tokenIndex != fail.getTokenIndex()) tokenIndex = INCONSISTENT_TOKEN_INDEX; break; } } if (stringValues.size() > 0) { Collections.sort(stringValues); for (int i = 0; i < stringValues.size(); i++) stringValues.set(i, quoteValue(stringValues.get(i))); messages.add(localizer().message("require_values", formatList(stringValues, "or"))); } if (names.size() > 0) // XXX provide the strings as well so that a sensible prefix can be chosen if none is declared messages.add(localizer().message("require_qnames", formatNames(names, FORMAT_NAMES_OR|FORMAT_NAMES_ELEMENT, context))); if (messages.size() == 0) return ""; String arg = formatList(messages, "or"); // XXX should do something with inconsistent token index (e.g. list { integer+ } | "foo" ) if (tokenIndex >= 0 && tokenStart >= 0 && tokenEnd <= str.length()) { if (tokenStart == str.length()) return localizer().message("missing_token", arg); return localizer().message("token_failures", quoteValue(str.substring(tokenStart, tokenEnd)), arg); } return localizer().message("data_failures", arg); } private String quoteValue(String str) { StringBuilder buf = new StringBuilder(); appendAttributeValue(buf, str); return buf.toString(); } private String expectedAttributes(MatchContext context) { if (ignoreError()) return null; NormalizedNameClass nnc = memo.possibleAttributeNames(); if (nnc.isEmpty()) return ""; Set expectedNames = nnc.getIncludedNames(); if (!expectedNames.isEmpty()) return localizer().message(nnc.isAnyNameIncluded() || !nnc.getIncludedNamespaces().isEmpty() ? "expected_attribute_or_other_ns" : "expected_attribute", formatNames(expectedNames, FORMAT_NAMES_ATTRIBUTE|FORMAT_NAMES_OR, context)); return ""; } private String expectedContent(MatchContext context) { if (ignoreError()) return null; List expected = new ArrayList(); if (!memo.endTagDeriv().isNotAllowed()) expected.add(localizer().message("element_end_tag")); // getContentType isn't so well-defined on after patterns switch (memo.emptyAfter().getPattern().getContentType()) { case Pattern.MIXED_CONTENT_TYPE: // A pattern such as (element foo { empty }, text) has a MIXED_CONTENT_TYPE // but text is not allowed everywhere. if (!memo.mixedTextDeriv().isNotAllowed()) expected.add(localizer().message("text")); break; case Pattern.DATA_CONTENT_TYPE: expected.add(localizer().message("data")); break; } NormalizedNameClass nnc = memo.possibleStartTagNames(); Set expectedNames = nnc.getIncludedNames(); // XXX say something about wildcards if (!expectedNames.isEmpty()) { expected.add(localizer().message("element_list", formatNames(expectedNames, FORMAT_NAMES_ELEMENT|FORMAT_NAMES_OR, context))); if (nnc.isAnyNameIncluded() || !nnc.getIncludedNamespaces().isEmpty()) expected.add(localizer().message("element_other_ns")); } if (expected.isEmpty()) return ""; return localizer().message("expected", formatList(expected, "or")); } static final String GENERATED_PREFIXES[] = { "ns", "ns-", "ns_", "NS", "NS-", "NS_"}; // Values for flags parameter of formatNames static private final int FORMAT_NAMES_ELEMENT = 0x0; static private final int FORMAT_NAMES_ATTRIBUTE = 0x1; static private final int FORMAT_NAMES_AND = 0x0; static private final int FORMAT_NAMES_OR = 0x2; private static String formatNames(Set names, int flags, MatchContext context) { if (names.isEmpty()) return ""; Map nsDecls = new HashMap(); List qNames = generateQNames(names, flags, context, nsDecls); Collections.sort(qNames); int len = qNames.size(); for (int i = 0; i < len; i++) qNames.set(i, quoteQName(qNames.get(i))); String result = formatList(qNames, (flags & FORMAT_NAMES_OR) != 0 ? "or" : "and"); if (nsDecls.size() != 0) result = localizer().message("qnames_nsdecls", result, formatNamespaceDecls(nsDecls)); return result; } private static List generateQNames(Set names, int flags, MatchContext context, Map nsDecls) { String defaultNamespace; if ((flags & FORMAT_NAMES_ATTRIBUTE) != 0) defaultNamespace = ""; else { defaultNamespace = context.resolveNamespacePrefix(""); for (Name name : names) { if (name.getNamespaceUri().length() == 0) { if (defaultNamespace != null) nsDecls.put("", ""); defaultNamespace = ""; break; } } } List qNames = new ArrayList(); Set undeclaredNamespaces = new HashSet(); List namesWithUndeclaredNamespaces = new ArrayList(); for (Name name : names) { String ns = name.getNamespaceUri(); String prefix; if (ns.equals(defaultNamespace)) prefix = ""; else { prefix = context.getPrefix(ns); // If we have no prefix for the namespace and we have an attribute, set the prefix to null // to mark that the namespace is undeclared. if ((flags & FORMAT_NAMES_ATTRIBUTE) != 0 && "".equals(prefix) && !"".equals(ns)) prefix = null; } if (prefix == null) { undeclaredNamespaces.add(ns); namesWithUndeclaredNamespaces.add(name); } else qNames.add(makeQName(prefix, name.getLocalName())); } if (namesWithUndeclaredNamespaces.isEmpty()) return qNames; if (undeclaredNamespaces.size() == 1 && defaultNamespace == null) nsDecls.put(undeclaredNamespaces.iterator().next(), ""); else choosePrefixes(undeclaredNamespaces, context, nsDecls); // now nsDecls has a prefix for each namespace for (Name name : namesWithUndeclaredNamespaces) qNames.add(makeQName(nsDecls.get(name.getNamespaceUri()), name.getLocalName())); return qNames; } private static void choosePrefixes(Set nsSet, MatchContext context, Map nsDecls) { List nsList = new ArrayList(nsSet); Collections.sort(nsList); int len = nsList.size(); String prefix; int tryIndex = 0; do { if (tryIndex < GENERATED_PREFIXES.length) prefix = GENERATED_PREFIXES[tryIndex]; else { // default is just to stick as many underscores as necessary at the beginning prefix = "_" + GENERATED_PREFIXES[0]; for (int i = GENERATED_PREFIXES.length; i < tryIndex; i++) prefix += "_" + prefix; } for (int i = 0; i < len; i++) { if (context.resolveNamespacePrefix(len == 1 ? prefix : prefix + (i + 1)) != null) { prefix = null; break; } } ++tryIndex; } while (prefix == null); for (int i = 0; i < len; i++) { String ns = nsList.get(i); nsDecls.put(ns, len == 1 ? prefix : prefix + (i + 1)); } } private static String formatList(List list, String conjunction) { int len = list.size(); switch (len) { case 0: return ""; case 1: return list.get(0); case 2: return localizer().message(conjunction + "_list_pair", list.get(0), list.get(1)); } String s = localizer().message(conjunction + "_list_many_first", list.get(0)); for (int i = 1; i < len - 1; i++) s = localizer().message(conjunction + "_list_many_middle", s, list.get(i)); return localizer().message(conjunction + "_list_many_last", s, list.get(len - 1)); } // nsDecls maps namespaces to prefixes private static String formatNamespaceDecls(Map nsDecls) { List list = new ArrayList(); for (Map.Entry entry : nsDecls.entrySet()) { StringBuilder buf = new StringBuilder(); String prefix = entry.getValue(); if (prefix.length() == 0) buf.append("xmlns"); else buf.append("xmlns:").append(prefix); buf.append('='); appendAttributeValue(buf, entry.getKey()); list.add(buf.toString()); } Collections.sort(list); StringBuilder buf = new StringBuilder(); for (String aList : list) { if (buf.length() != 0) buf.append(" "); buf.append(aList); } return buf.toString(); } private static String quoteForAttributeValue(char c) { switch (c) { case '<': return "<"; case '"': return """; case '&': return "&"; case 0xA: return " "; case 0xD: return " "; case 0x9: return " "; } return null; } private static StringBuilder appendAttributeValue(StringBuilder buf, String value) { buf.append('"'); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); String quoted = quoteForAttributeValue(c); if (quoted != null) buf.append(quoted); else buf.append(c); } buf.append('"'); return buf; } private static String makeQName(String prefix, String localName) { if (prefix.length() == 0) return localName; return prefix + ":" + localName; } static private String quoteQName(String qName) { return localizer().message("qname", qName); } static private Localizer localizer() { return SchemaBuilderImpl.localizer; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/PatternMemo.java000066400000000000000000000155011225366607500330660ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.ValidationContext; import java.util.HashMap; import java.util.List; import java.util.Map; final class PatternMemo { private final Pattern pattern; private final ValidatorPatternBuilder builder; private final boolean notAllowed; private PatternMemo memoEndAttributes; private PatternMemo memoTextOnly; private PatternMemo memoEndTagDeriv; private PatternMemo memoMixedTextDeriv; private PatternMemo memoIgnoreMissingAttributes; private Map startTagOpenDerivMap; private Map startTagOpenRecoverDerivMap; private Map startAttributeDerivMap; private DataDerivType memoDataDerivType; private PatternMemo memoRecoverAfter; private PatternMemo memoEmptyAfter; private NormalizedNameClass memoPossibleAttributeNames; private NormalizedNameClass memoPossibleStartTagNames; PatternMemo(Pattern pattern, ValidatorPatternBuilder builder) { this.pattern = pattern; this.builder = builder; this.notAllowed = pattern.isNotAllowed(); } Pattern getPattern() { return pattern; } ValidatorPatternBuilder getPatternBuilder() { return builder; } boolean isNotAllowed() { return notAllowed; } PatternMemo endAttributes() { if (memoEndAttributes == null) memoEndAttributes = applyForPatternMemo(builder.getEndAttributesFunction()); return memoEndAttributes; } PatternMemo endAttributes(PatternFunction f) { if (memoEndAttributes == null) memoEndAttributes = applyForPatternMemo(f); return memoEndAttributes; } PatternMemo ignoreMissingAttributes() { if (memoIgnoreMissingAttributes == null) memoIgnoreMissingAttributes = applyForPatternMemo(builder.getIgnoreMissingAttributesFunction()); return memoIgnoreMissingAttributes; } PatternMemo ignoreMissingAttributes(PatternFunction f) { if (memoIgnoreMissingAttributes == null) memoIgnoreMissingAttributes = applyForPatternMemo(f); return memoIgnoreMissingAttributes; } PatternMemo textOnly() { if (memoTextOnly == null) memoTextOnly = applyForPatternMemo(builder.getTextOnlyFunction()); return memoTextOnly; } PatternMemo textOnly(PatternFunction f) { if (memoTextOnly == null) memoTextOnly = applyForPatternMemo(f); return memoTextOnly; } PatternMemo endTagDeriv() { if (memoEndTagDeriv == null) memoEndTagDeriv = applyForPatternMemo(builder.getEndTagDerivFunction()); return memoEndTagDeriv; } PatternMemo endTagDeriv(PatternFunction f) { if (memoEndTagDeriv == null) memoEndTagDeriv = applyForPatternMemo(f); return memoEndTagDeriv; } PatternMemo mixedTextDeriv() { if (memoMixedTextDeriv == null) memoMixedTextDeriv = applyForPatternMemo(builder.getMixedTextDerivFunction()); return memoMixedTextDeriv; } PatternMemo mixedTextDeriv(PatternFunction f) { if (memoMixedTextDeriv == null) memoMixedTextDeriv = applyForPatternMemo(f); return memoMixedTextDeriv; } PatternMemo startTagOpenDeriv(Name name) { return startTagOpenDeriv(name, null); } PatternMemo startTagOpenDeriv(StartTagOpenDerivFunction f) { return startTagOpenDeriv(f.getName(), f); } private PatternMemo startTagOpenDeriv(Name name, StartTagOpenDerivFunction f) { PatternMemo tem; if (startTagOpenDerivMap == null) startTagOpenDerivMap = new HashMap(); else { tem = startTagOpenDerivMap.get(name); if (tem != null) return tem; } if (f == null) f = new StartTagOpenDerivFunction(name, builder); tem = applyForPatternMemo(f); startTagOpenDerivMap.put(name, tem); return tem; } PatternMemo startTagOpenRecoverDeriv(Name name) { return startTagOpenRecoverDeriv(name, null); } PatternMemo startTagOpenRecoverDeriv(StartTagOpenRecoverDerivFunction f) { return startTagOpenRecoverDeriv(f.getName(), f); } private PatternMemo startTagOpenRecoverDeriv(Name name, StartTagOpenRecoverDerivFunction f) { PatternMemo tem; if (startTagOpenRecoverDerivMap == null) startTagOpenRecoverDerivMap = new HashMap(); else { tem = startTagOpenRecoverDerivMap.get(name); if (tem != null) return tem; } if (f == null) f = new StartTagOpenRecoverDerivFunction(name, builder); tem = applyForPatternMemo(f); startTagOpenRecoverDerivMap.put(name, tem); return tem; } PatternMemo startAttributeDeriv(Name name) { return startAttributeDeriv(name, null); } PatternMemo startAttributeDeriv(StartAttributeDerivFunction f) { return startAttributeDeriv(f.getName(), f); } private PatternMemo startAttributeDeriv(Name name, StartAttributeDerivFunction f) { PatternMemo tem; if (startAttributeDerivMap == null) startAttributeDerivMap = new HashMap(); else { tem = startAttributeDerivMap.get(name); if (tem != null) return tem; } if (f == null) f = new StartAttributeDerivFunction(name, builder); tem = applyForPatternMemo(f); startAttributeDerivMap.put(name, tem); return tem; } DataDerivType dataDerivType() { if (memoDataDerivType == null) memoDataDerivType = DataDerivTypeFunction.dataDerivType(builder, pattern).copy(); return memoDataDerivType; } PatternMemo dataDeriv(String str, ValidationContext vc) { return dataDerivType().dataDeriv(builder, pattern, str, vc, null); } PatternMemo dataDeriv(String str, ValidationContext vc, List fail) { return dataDerivType().dataDeriv(builder, pattern, str, vc, fail); } PatternMemo recoverAfter() { if (memoRecoverAfter == null) memoRecoverAfter = applyForPatternMemo(builder.getRecoverAfterFunction()); return memoRecoverAfter; } PatternMemo emptyAfter() { if (memoEmptyAfter == null) memoEmptyAfter = applyForPatternMemo(new ApplyAfterFunction(builder) { Pattern apply(Pattern p) { return builder.makeEmpty(); } // allow emptyAfter to be applied to anything public Pattern caseOther(Pattern p) { return p; } }); return memoEmptyAfter; } NormalizedNameClass possibleStartTagNames() { if (memoPossibleStartTagNames == null) memoPossibleStartTagNames = builder.getPossibleStartTagNamesFunction().applyTo(pattern); return memoPossibleStartTagNames; } NormalizedNameClass possibleAttributeNames() { if (memoPossibleAttributeNames == null) memoPossibleAttributeNames = builder.getPossibleAttributeNamesFunction().applyTo(pattern); return memoPossibleAttributeNames; } private PatternMemo applyForPatternMemo(PatternFunction f) { return builder.getPatternMemo(pattern.apply(f)); } } PossibleAttributeNamesFunction.java000066400000000000000000000007161225366607500367140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; /** * PatternFunction to compute the name class of possible attributes. * Computes a NormalizedNameClass. */ class PossibleAttributeNamesFunction extends PossibleNamesFunction { public VoidValue caseAttribute(AttributePattern p) { add(p.getNameClass()); return VoidValue.VOID; } public VoidValue caseGroup(GroupPattern p) { return caseBinary(p); } } PossibleNamesFunction.java000066400000000000000000000023061225366607500350250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; /** * Common base class for PossibleAttributeNamesFunction and PossibleStartTagNamesFunction. * @see PossibleAttributeNamesFunction * @see PossibleStartTagNamesFunction */ abstract class PossibleNamesFunction extends AbstractPatternFunction { private final UnionNameClassNormalizer normalizer = new UnionNameClassNormalizer(); NormalizedNameClass applyTo(Pattern p) { normalizer.setNameClass(new NullNameClass()); p.apply(this); return normalizer.normalize(); } void add(NameClass nc) { normalizer.add(nc); } public VoidValue caseAfter(AfterPattern p) { return p.getOperand1().apply(this); } public VoidValue caseBinary(BinaryPattern p) { p.getOperand1().apply(this); p.getOperand2().apply(this); return VoidValue.VOID; } public VoidValue caseChoice(ChoicePattern p) { return caseBinary(p); } public VoidValue caseInterleave(InterleavePattern p) { return caseBinary(p); } public VoidValue caseOneOrMore(OneOrMorePattern p) { return p.getOperand().apply(this); } public VoidValue caseOther(Pattern p) { return VoidValue.VOID; } } PossibleStartTagNamesFunction.java000066400000000000000000000010641225366607500364770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; /** * PatternFunction to compute the name class of possible start-tags. * Computes a NormalizedNameClass. */ class PossibleStartTagNamesFunction extends PossibleNamesFunction { public VoidValue caseElement(ElementPattern p) { add(p.getNameClass()); return VoidValue.VOID; } public VoidValue caseGroup(GroupPattern p) { p.getOperand1().apply(this); if (p.getOperand1().isNullable()) p.getOperand2().apply(this); return VoidValue.VOID; } } RecoverAfterFunction.java000066400000000000000000000011361225366607500346500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class RecoverAfterFunction extends AbstractPatternFunction { private final ValidatorPatternBuilder builder; RecoverAfterFunction(ValidatorPatternBuilder builder) { this.builder = builder; } public Pattern caseOther(Pattern p) { throw new RuntimeException("recover after botch"); } public Pattern caseChoice(ChoicePattern p) { return builder.makeChoice(p.getOperand1().apply(this), p.getOperand2().apply(this)); } public Pattern caseAfter(AfterPattern p) { return p.getOperand2(); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/RefPattern.java000066400000000000000000000041511225366607500327040ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; class RefPattern extends Pattern { private Pattern p; private Locator refLoc; private final String name; private int checkRecursionDepth = -1; private boolean combineImplicit = false; private byte combineType = COMBINE_NONE; private byte replacementStatus = REPLACEMENT_KEEP; private boolean expanded = false; static final byte REPLACEMENT_KEEP = 0; static final byte REPLACEMENT_REQUIRE = 1; static final byte REPLACEMENT_IGNORE = 2; static final byte COMBINE_NONE = 0; static final byte COMBINE_CHOICE = 1; static final byte COMBINE_INTERLEAVE = 2; RefPattern(String name) { this.name = name; } Pattern getPattern() { return p; } void setPattern(Pattern p) { this.p = p; } Locator getRefLocator() { return refLoc; } void setRefLocator(Locator loc) { this.refLoc = loc; } void checkRecursion(int depth) throws SAXException { if (checkRecursionDepth == -1) { checkRecursionDepth = depth; p.checkRecursion(depth); checkRecursionDepth = -2; } else if (depth == checkRecursionDepth) // XXX try to recover from this? throw new SAXParseException(SchemaBuilderImpl.localizer.message("recursive_reference", name), refLoc); } Pattern expand(SchemaPatternBuilder b) { if (!expanded) { p = p.expand(b); expanded = true; } return p; } boolean samePattern(Pattern other) { return false; } T apply(PatternFunction f) { return f.caseRef(this); } byte getReplacementStatus() { return replacementStatus; } void setReplacementStatus(byte replacementStatus) { this.replacementStatus = replacementStatus; } boolean isCombineImplicit() { return combineImplicit; } void setCombineImplicit() { combineImplicit = true; } byte getCombineType() { return combineType; } void setCombineType(byte combineType) { this.combineType = combineType; } String getName() { return name; } } RequiredAttributesFunction.java000066400000000000000000000011641225366607500361110ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Set; /** * Implements a function on a pattern that returns the set of required attributes. * The return value is a non-null Set each member of is a non-null Name. Note that * in the schema attribute foo|bar { text }, neither foo nor bar are required attributes. */ class RequiredAttributesFunction extends RequiredElementsOrAttributesFunction { public Set caseAttribute(AttributePattern p) { return caseNamed(p.getNameClass()); } public Set caseGroup(GroupPattern p) { return union(p); } } RequiredElementsFunction.java000066400000000000000000000013331225366607500355350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Set; /** * Implements a function on a pattern that returns the set of required elements. * The return value is a non-null Set each member of is a non-null Name. Note that * in the schema element foo|bar { text }, neither foo nor bar are required elements. */ public class RequiredElementsFunction extends RequiredElementsOrAttributesFunction { public Set caseElement(ElementPattern p) { return caseNamed(p.getNameClass()); } public Set caseGroup(GroupPattern p) { Pattern p1 = p.getOperand1(); if (!p1.isNullable()) return p1.apply(this); return p.getOperand2().apply(this); } } RequiredElementsOrAttributesFunction.java000066400000000000000000000026761225366607500401200ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Common functionality between RequiredAttributesFunction and RequiredElementsFunction */ abstract class RequiredElementsOrAttributesFunction extends AbstractPatternFunction> { public Set caseOther(Pattern p) { return Collections.emptySet(); } public Set caseChoice(ChoicePattern p) { Set s1 = p.getOperand1().apply(this); Set s2 = p.getOperand2().apply(this); if (s1.isEmpty()) return s1; if (s2.isEmpty()) return s2; s1.retainAll(s2); return s1; } protected Set caseNamed(NameClass nc) { if (!(nc instanceof SimpleNameClass)) return Collections.emptySet(); Set s = new HashSet(); s.add(((SimpleNameClass)nc).getName()); return s; } protected Set union(BinaryPattern p) { Set s1 = p.getOperand1().apply(this); Set s2 = p.getOperand2().apply(this); if (s1.isEmpty()) return s2; if (s2.isEmpty()) return s1; s1.addAll(s2); return s1; } public Set caseInterleave(InterleavePattern p) { return union(p); } public Set caseAfter(AfterPattern p) { return p.getOperand1().apply(this); } public Set caseOneOrMore(OneOrMorePattern p) { return p.getOperand().apply(this); } } RestrictionViolationException.java000066400000000000000000000016461225366607500366320ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.xml.sax.Locator; import com.thaiopensource.xml.util.Name; class RestrictionViolationException extends Exception { private final String messageId; private Locator loc; private Name name; private String namespaceUri; RestrictionViolationException(String messageId) { this.messageId = messageId; } RestrictionViolationException(String messageId, Name name) { this.messageId = messageId; this.name = name; } RestrictionViolationException(String messageId, String namespaceUri) { this.messageId = messageId; this.namespaceUri = namespaceUri; } String getMessageId() { return messageId; } Locator getLocator() { return loc; } void maybeSetLocator(Locator loc) { if (this.loc == null) this.loc = loc; } Name getName() { return name; } String getNamespaceUri() { return namespaceUri; } } SchemaBuilderImpl.java000066400000000000000000000734171225366607500341170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.relaxng.parse.BuildException; import com.thaiopensource.relaxng.parse.Context; import com.thaiopensource.relaxng.parse.DataPatternBuilder; import com.thaiopensource.relaxng.parse.Div; import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; import com.thaiopensource.relaxng.parse.Grammar; import com.thaiopensource.relaxng.parse.GrammarSection; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Include; import com.thaiopensource.relaxng.parse.IncludedGrammar; import com.thaiopensource.relaxng.parse.ParseReceiver; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.ParsedPatternFuture; import com.thaiopensource.relaxng.parse.SchemaBuilder; import com.thaiopensource.relaxng.parse.Scope; import com.thaiopensource.relaxng.parse.SubParseable; import com.thaiopensource.relaxng.parse.SubParser; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeBuilder; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeLibrary; import org.relaxng.datatype.DatatypeLibraryFactory; import org.relaxng.datatype.ValidationContext; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class SchemaBuilderImpl extends AnnotationsImpl implements ElementAnnotationBuilder, SchemaBuilder { private final SchemaBuilderImpl parent; private boolean hadError = false; private final SubParser subParser; private final SchemaPatternBuilder pb; private final DatatypeLibraryFactory datatypeLibraryFactory; private final String inheritNs; private final ErrorHandler eh; private final OpenIncludes openIncludes; private final AttributeNameClassChecker attributeNameClassChecker = new AttributeNameClassChecker(); static final Localizer localizer = new Localizer(SchemaBuilderImpl.class); static class OpenIncludes { final String uri; final OpenIncludes parent; OpenIncludes(String uri, OpenIncludes parent) { this.uri = uri; this.parent = parent; } } static public Pattern parse(Parseable parseable, ErrorHandler eh, DatatypeLibraryFactory datatypeLibraryFactory, SchemaPatternBuilder pb, boolean isAttributesPattern) throws IllegalSchemaException, IOException, SAXException { try { SchemaBuilderImpl sb = new SchemaBuilderImpl(parseable, eh, new BuiltinDatatypeLibraryFactory(datatypeLibraryFactory), pb); Pattern pattern = parseable.parse(sb, new RootScope(sb)); if (isAttributesPattern) pattern = sb.wrapAttributesPattern(pattern); return sb.expandPattern(pattern); } catch (BuildException e) { throw unwrapBuildException(e); } } static public PatternFuture installHandlers(ParseReceiver parser, XMLReader xr, ErrorHandler eh, DatatypeLibraryFactory dlf, SchemaPatternBuilder pb) throws SAXException { final SchemaBuilderImpl sb = new SchemaBuilderImpl(parser, eh, new BuiltinDatatypeLibraryFactory(dlf), pb); final ParsedPatternFuture pf = parser.installHandlers(xr, sb, new RootScope(sb)); return new PatternFuture() { public Pattern getPattern(boolean isAttributesPattern) throws IllegalSchemaException, SAXException, IOException { try { Pattern pattern = pf.getParsedPattern(); if (isAttributesPattern) pattern = sb.wrapAttributesPattern(pattern); return sb.expandPattern(pattern); } catch (BuildException e) { throw unwrapBuildException(e); } } }; } static public RuntimeException unwrapBuildException(BuildException e) throws SAXException, IllegalSchemaException, IOException { Throwable t = e.getCause(); if (t instanceof IOException) throw (IOException)t; if (t instanceof RuntimeException) return (RuntimeException)t; if (t instanceof IllegalSchemaException) throw new IllegalSchemaException(); if (t instanceof SAXException) throw (SAXException)t; if (t instanceof Exception) throw new SAXException((Exception)t); throw new SAXException(t.getClass().getName() + " thrown"); } private Pattern wrapAttributesPattern(Pattern pattern) { // XXX where can we get a locator from? return makeElement(makeAnyName(null, null), pattern, null, null); } private Pattern expandPattern(Pattern pattern) throws IllegalSchemaException, BuildException { if (!hadError) { try { pattern.checkRecursion(0); pattern = pattern.expand(pb); pattern.checkRestrictions(Pattern.START_CONTEXT, null, null); if (!hadError) return pattern; } catch (SAXParseException e) { error(e); } catch (SAXException e) { throw new BuildException(e); } catch (RestrictionViolationException e) { if (e.getName() != null) error(e.getMessageId(), NameFormatter.format(e.getName()), e.getLocator()); else if (e.getNamespaceUri() != null) error(e.getMessageId(), e.getNamespaceUri(), e.getLocator()); else error(e.getMessageId(), e.getLocator()); } } throw new IllegalSchemaException(); } private SchemaBuilderImpl(SubParser subParser, ErrorHandler eh, DatatypeLibraryFactory datatypeLibraryFactory, SchemaPatternBuilder pb) { this.parent = null; this.subParser = subParser; this.eh = eh; this.datatypeLibraryFactory = datatypeLibraryFactory; this.pb = pb; this.inheritNs = ""; this.openIncludes = null; } private SchemaBuilderImpl(String inheritNs, String uri, SchemaBuilderImpl parent) { this.parent = parent; this.subParser = parent.subParser; this.eh = parent.eh; this.datatypeLibraryFactory = parent.datatypeLibraryFactory; this.pb = parent.pb; this.inheritNs = parent.resolveInherit(inheritNs); this.openIncludes = new OpenIncludes(uri, parent.openIncludes); } public Pattern makeChoice(List patterns, Locator loc, AnnotationsImpl anno) throws BuildException { int nPatterns = patterns.size(); if (nPatterns <= 0) throw new IllegalArgumentException(); Pattern result = patterns.get(0); for (int i = 1; i < nPatterns; i++) result = pb.makeChoice(result, patterns.get(i)); return result; } public Pattern makeInterleave(List patterns, Locator loc, AnnotationsImpl anno) throws BuildException { int nPatterns = patterns.size(); if (nPatterns <= 0) throw new IllegalArgumentException(); Pattern result = patterns.get(0); for (int i = 1; i < nPatterns; i++) result = pb.makeInterleave(result, patterns.get(i)); return result; } public Pattern makeGroup(List patterns, Locator loc, AnnotationsImpl anno) throws BuildException { int nPatterns = patterns.size(); if (nPatterns <= 0) throw new IllegalArgumentException(); Pattern result = patterns.get(0); for (int i = 1; i < nPatterns; i++) result = pb.makeGroup(result, patterns.get(i)); return result; } public Pattern makeOneOrMore(Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeOneOrMore(p); } public Pattern makeZeroOrMore(Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeZeroOrMore(p); } public Pattern makeOptional(Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeOptional(p); } public Pattern makeList(Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeList(p, loc); } public Pattern makeMixed(Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeMixed(p); } public Pattern makeEmpty(Locator loc, AnnotationsImpl anno) { return pb.makeEmpty(); } public Pattern makeNotAllowed(Locator loc, AnnotationsImpl anno) { return pb.makeUnexpandedNotAllowed(); } public Pattern makeText(Locator loc, AnnotationsImpl anno) { return pb.makeText(); } public Pattern makeErrorPattern() { return pb.makeError(); } public NameClass makeErrorNameClass() { return new ErrorNameClass(); } public Pattern makeAttribute(NameClass nc, Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { String messageId = attributeNameClassChecker.checkNameClass(nc); if (messageId != null) error(messageId, loc); return pb.makeAttribute(nc, p, loc); } public Pattern makeElement(NameClass nc, Pattern p, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeElement(nc, p, loc); } private class DummyDataPatternBuilder implements DataPatternBuilder { public void addParam(String name, String value, Context context, String ns, Locator loc, AnnotationsImpl anno) throws BuildException { } public void annotation(VoidValue ea) throws BuildException { } public Pattern makePattern(Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeError(); } public Pattern makePattern(Pattern except, Locator loc, AnnotationsImpl anno) throws BuildException { return pb.makeError(); } } private class ValidationContextImpl implements ValidationContext { private final ValidationContext vc; private final String ns; ValidationContextImpl(ValidationContext vc, String ns) { this.vc = vc; this.ns = ns.length() == 0 ? null : ns; } public String resolveNamespacePrefix(String prefix) { String result = prefix.length() == 0 ? ns : vc.resolveNamespacePrefix(prefix); if (result == INHERIT_NS) { if (inheritNs.length() == 0) return null; return inheritNs; } return result; } public String getBaseUri() { return vc.getBaseUri(); } public boolean isUnparsedEntity(String entityName) { return vc.isUnparsedEntity(entityName); } public boolean isNotation(String notationName) { return vc.isNotation(notationName); } } private class DataPatternBuilderImpl implements DataPatternBuilder { private final DatatypeBuilder dtb; private final Name dtName; private final List params = new ArrayList(); DataPatternBuilderImpl(DatatypeBuilder dtb, Name dtName) { this.dtb = dtb; this.dtName = dtName; } public void addParam(String name, String value, Context context, String ns, Locator loc, AnnotationsImpl anno) throws BuildException { try { dtb.addParameter(name, value, new ValidationContextImpl(context, ns)); params.add(name); params.add(value); } catch (DatatypeException e) { String detail = e.getMessage(); int pos = e.getIndex(); String displayedParam; if (pos == DatatypeException.UNKNOWN) displayedParam = null; else displayedParam = displayParam(value, pos); if (displayedParam != null) { if (detail != null) error("invalid_param_detail_display", detail, displayedParam, loc); else error("invalid_param_display", displayedParam, loc); } else if (detail != null) error("invalid_param_detail", detail, loc); else error("invalid_param", loc); } } public void annotation(VoidValue ea) throws BuildException { } String displayParam(String value, int pos) { if (pos < 0) pos = 0; else if (pos > value.length()) pos = value.length(); return localizer.message("display_param", value.substring(0, pos), value.substring(pos)); } public Pattern makePattern(Locator loc, AnnotationsImpl anno) throws BuildException { try { return pb.makeData(dtb.createDatatype(), dtName, params); } catch (DatatypeException e) { String detail = e.getMessage(); if (detail != null) error("invalid_params_detail", detail, loc); else error("invalid_params", loc); return pb.makeError(); } } public Pattern makePattern(Pattern except, Locator loc, AnnotationsImpl anno) throws BuildException { try { return pb.makeDataExcept(dtb.createDatatype(), dtName, params, except, loc); } catch (DatatypeException e) { String detail = e.getMessage(); if (detail != null) error("invalid_params_detail", detail, loc); else error("invalid_params", loc); return pb.makeError(); } } } public DataPatternBuilder makeDataPatternBuilder(String datatypeLibrary, String type, Locator loc) throws BuildException { DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary); if (dl == null) error("unrecognized_datatype_library", datatypeLibrary, loc); else { try { return new DataPatternBuilderImpl(dl.createDatatypeBuilder(type), new Name(datatypeLibrary, type)); } catch (DatatypeException e) { String detail = e.getMessage(); if (detail != null) error("unsupported_datatype_detail", datatypeLibrary, type, detail, loc); else error("unrecognized_datatype", datatypeLibrary, type, loc); } } return new DummyDataPatternBuilder(); } public Pattern makeValue(String datatypeLibrary, String type, String value, Context context, String ns, Locator loc, AnnotationsImpl anno) throws BuildException { DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary); if (dl == null) error("unrecognized_datatype_library", datatypeLibrary, loc); else { try { DatatypeBuilder dtb = dl.createDatatypeBuilder(type); try { Datatype dt = dtb.createDatatype(); Object obj = dt.createValue(value, new ValidationContextImpl(context, ns)); if (obj != null) return pb.makeValue(dt, new Name(datatypeLibrary, type), obj, value); error("invalid_value", value, loc); } catch (DatatypeException e) { String detail = e.getMessage(); if (detail != null) error("datatype_requires_param_detail", detail, loc); else error("datatype_requires_param", loc); } } catch (DatatypeException e) { error("unrecognized_datatype", datatypeLibrary, type, loc); } } return pb.makeError(); } static class GrammarImpl implements Grammar, Div, IncludedGrammar { private final SchemaBuilderImpl sb; private final Map defines; private final RefPattern startRef; private final Scope parent; private GrammarImpl(SchemaBuilderImpl sb, Scope parent) { this.sb = sb; this.parent = parent; this.defines = new HashMap(); this.startRef = new RefPattern(null); } protected GrammarImpl(SchemaBuilderImpl sb, GrammarImpl g) { this.sb = sb; parent = g.parent; startRef = g.startRef; defines = g.defines; } public Pattern endGrammar(Locator loc, AnnotationsImpl anno) throws BuildException { for (String name : defines.keySet()) { RefPattern rp = defines.get(name); if (rp.getPattern() == null) { sb.error("reference_to_undefined", name, rp.getRefLocator()); rp.setPattern(sb.pb.makeError()); } } Pattern start = startRef.getPattern(); if (start == null) { sb.error("missing_start_element", loc); start = sb.pb.makeError(); } return start; } public void endDiv(Locator loc, AnnotationsImpl anno) throws BuildException { // nothing to do } public Pattern endIncludedGrammar(Locator loc, AnnotationsImpl anno) throws BuildException { return null; } public void define(String name, GrammarSection.Combine combine, Pattern pattern, Locator loc, AnnotationsImpl anno) throws BuildException { define(lookup(name), combine, pattern, loc); } private void define(RefPattern rp, GrammarSection.Combine combine, Pattern pattern, Locator loc) throws BuildException { switch (rp.getReplacementStatus()) { case RefPattern.REPLACEMENT_KEEP: if (combine == null) { if (rp.isCombineImplicit()) { if (rp.getName() == null) sb.error("duplicate_start", loc); else sb.error("duplicate_define", rp.getName(), loc); } else rp.setCombineImplicit(); } else { byte combineType = (combine == COMBINE_CHOICE ? RefPattern.COMBINE_CHOICE : RefPattern.COMBINE_INTERLEAVE); if (rp.getCombineType() != RefPattern.COMBINE_NONE && rp.getCombineType() != combineType) { if (rp.getName() == null) sb.error("conflict_combine_start", loc); else sb.error("conflict_combine_define", rp.getName(), loc); } rp.setCombineType(combineType); } if (rp.getPattern() == null) rp.setPattern(pattern); else if (rp.getCombineType() == RefPattern.COMBINE_INTERLEAVE) rp.setPattern(sb.pb.makeInterleave(rp.getPattern(), pattern)); else rp.setPattern(sb.pb.makeChoice(rp.getPattern(), pattern)); break; case RefPattern.REPLACEMENT_REQUIRE: rp.setReplacementStatus(RefPattern.REPLACEMENT_IGNORE); break; case RefPattern.REPLACEMENT_IGNORE: break; } } public void topLevelAnnotation(VoidValue ea) throws BuildException { } public void topLevelComment(CommentListImpl comments) throws BuildException { } private RefPattern lookup(String name) { if (name == START) return startRef; return lookup1(name); } private RefPattern lookup1(String name) { RefPattern p = defines.get(name); if (p == null) { p = new RefPattern(name); defines.put(name, p); } return p; } public Pattern makeRef(String name, Locator loc, AnnotationsImpl anno) throws BuildException { RefPattern p = lookup1(name); if (p.getRefLocator() == null && loc != null) p.setRefLocator(loc); return p; } public Pattern makeParentRef(String name, Locator loc, AnnotationsImpl anno) throws BuildException { if (parent == null) { sb.error("parent_ref_outside_grammar", loc); return sb.makeErrorPattern(); } return parent.makeRef(name, loc, anno); } public Div makeDiv() { return this; } public Include makeInclude() { return new IncludeImpl(sb, this); } } static class RootScope implements Scope { private final SchemaBuilderImpl sb; RootScope(SchemaBuilderImpl sb) { this.sb = sb; } public Pattern makeParentRef(String name, Locator loc, AnnotationsImpl anno) throws BuildException { sb.error("parent_ref_outside_grammar", loc); return sb.makeErrorPattern(); } public Pattern makeRef(String name, Locator loc, AnnotationsImpl anno) throws BuildException { sb.error("ref_outside_grammar", loc); return sb.makeErrorPattern(); } } static class Override { Override(RefPattern prp, Override next) { this.prp = prp; this.next = next; } final RefPattern prp; final Override next; byte replacementStatus; } private static class IncludeImpl implements Include, Div { private final SchemaBuilderImpl sb; private Override overrides; private final GrammarImpl grammar; private IncludeImpl(SchemaBuilderImpl sb, GrammarImpl grammar) { this.sb = sb; this.grammar = grammar; } public void define(String name, GrammarSection.Combine combine, Pattern pattern, Locator loc, AnnotationsImpl anno) throws BuildException { RefPattern rp = grammar.lookup(name); overrides = new Override(rp, overrides); grammar.define(rp, combine, pattern, loc); } public void endDiv(Locator loc, AnnotationsImpl anno) throws BuildException { // nothing to do } public void topLevelAnnotation(VoidValue ea) throws BuildException { // nothing to do } public void topLevelComment(CommentListImpl comments) throws BuildException { } public Div makeDiv() { return this; } public void endInclude(String href, String base, String ns, Locator loc, AnnotationsImpl anno) throws BuildException { SubParseable subParseable = sb.subParser.createSubParseable(href, base); String uri = subParseable.getUri(); for (OpenIncludes inc = sb.openIncludes; inc != null; inc = inc.parent) { if (inc.uri.equals(uri)) { sb.error("recursive_include", uri, loc); return; } } for (Override o = overrides; o != null; o = o.next) { o.replacementStatus = o.prp.getReplacementStatus(); o.prp.setReplacementStatus(RefPattern.REPLACEMENT_REQUIRE); } try { SchemaBuilderImpl isb = new SchemaBuilderImpl(ns, uri, sb); subParseable.parseAsInclude(isb, new GrammarImpl(isb, grammar)); for (Override o = overrides; o != null; o = o.next) { if (o.prp.getReplacementStatus() == RefPattern.REPLACEMENT_REQUIRE) { if (o.prp.getName() == null) sb.error("missing_start_replacement", loc); else sb.error("missing_define_replacement", o.prp.getName(), loc); } } } catch (IllegalSchemaException e) { sb.noteError(); } finally { for (Override o = overrides; o != null; o = o.next) o.prp.setReplacementStatus(o.replacementStatus); } } public Include makeInclude() { return null; } } public Grammar makeGrammar(Scope parent) { return new GrammarImpl(this, parent); } public Pattern makeExternalRef(String href, String base, String ns, Scope scope, Locator loc, AnnotationsImpl anno) throws BuildException { SubParseable subParseable = subParser.createSubParseable(href, base); String uri = subParseable.getUri(); for (OpenIncludes inc = openIncludes; inc != null; inc = inc.parent) { if (inc.uri.equals(uri)) { error("recursive_include", uri, loc); return pb.makeError(); } } try { return subParseable.parse(new SchemaBuilderImpl(ns, uri, this), scope); } catch (IllegalSchemaException e) { noteError(); return pb.makeError(); } } public NameClass makeNameClassChoice(List nameClasses, Locator loc, AnnotationsImpl anno) { int nNameClasses = nameClasses.size(); if (nNameClasses <= 0) throw new IllegalArgumentException(); NameClass result = nameClasses.get(0); for (int i = 1; i < nNameClasses; i++) result = new ChoiceNameClass(result, nameClasses.get(i)); return result; } public NameClass makeName(String ns, String localName, String prefix, Locator loc, AnnotationsImpl anno) { return new SimpleNameClass(new Name(resolveInherit(ns), localName)); } public NameClass makeNsName(String ns, Locator loc, AnnotationsImpl anno) { return new NsNameClass(resolveInherit(ns)); } public NameClass makeNsName(String ns, NameClass except, Locator loc, AnnotationsImpl anno) { return new NsNameExceptNameClass(resolveInherit(ns), except); } public NameClass makeAnyName(Locator loc, AnnotationsImpl anno) { return new AnyNameClass(); } public NameClass makeAnyName(NameClass except, Locator loc, AnnotationsImpl anno) { return new AnyNameExceptNameClass(except); } public AnnotationsImpl makeAnnotations(CommentListImpl comments, Context context) { return this; } public VoidValue makeElementAnnotation() throws BuildException { return VoidValue.VOID; } public void addText(String value, Locator loc, CommentListImpl comments) throws BuildException { } public ElementAnnotationBuilder makeElementAnnotationBuilder(String ns, String localName, String prefix, Locator loc, CommentListImpl comments, Context context) { return this; } public CommentListImpl makeCommentList() { return this; } public boolean usesComments() { return false; } public Pattern annotatePattern(Pattern p, AnnotationsImpl anno) throws BuildException { return p; } public NameClass annotateNameClass(NameClass nc, AnnotationsImpl anno) throws BuildException { return nc; } public Pattern annotateAfterPattern(Pattern p, VoidValue e) throws BuildException { return p; } public NameClass annotateAfterNameClass(NameClass nc, VoidValue e) throws BuildException { return nc; } public Pattern commentAfterPattern(Pattern p, CommentListImpl comments) throws BuildException { return p; } public NameClass commentAfterNameClass(NameClass nc, CommentListImpl comments) throws BuildException { return nc; } private String resolveInherit(String ns) { if (ns == INHERIT_NS) return inheritNs; return ns; } private class LocatorImpl implements Locator { private final String systemId; private final int lineNumber; private final int columnNumber; private LocatorImpl(String systemId, int lineNumber, int columnNumber) { this.systemId = systemId; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } public String getPublicId() { return null; } public String getSystemId() { return systemId; } public int getLineNumber() { return lineNumber; } public int getColumnNumber() { return columnNumber; } } public Locator makeLocation(String systemId, int lineNumber, int columnNumber) { return new LocatorImpl(systemId, lineNumber, columnNumber); } private void error(SAXParseException message) throws BuildException { noteError(); try { if (eh != null) eh.error(message); } catch (SAXException e) { throw new BuildException(e); } } /* private void warning(SAXParseException message) throws BuildException { try { if (eh != null) eh.warning(message); } catch (SAXException e) { throw new BuildException(e); } } */ private void error(String key, Locator loc) throws BuildException { error(new SAXParseException(localizer.message(key), loc)); } private void error(String key, String arg, Locator loc) throws BuildException { error(new SAXParseException(localizer.message(key, arg), loc)); } private void error(String key, String arg1, String arg2, Locator loc) throws BuildException { error(new SAXParseException(localizer.message(key, arg1, arg2), loc)); } private void error(String key, String arg1, String arg2, String arg3, Locator loc) throws BuildException { error(new SAXParseException(localizer.message(key, new Object[]{arg1, arg2, arg3}), loc)); } private void noteError() { if (!hadError && parent != null) parent.noteError(); hadError = true; } } SchemaPatternBuilder.java000066400000000000000000000047231225366607500346250ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.xml.sax.Locator; import java.util.List; public class SchemaPatternBuilder extends PatternBuilder { private boolean idTypes; private final UnexpandedNotAllowedPattern unexpandedNotAllowed = new UnexpandedNotAllowedPattern(); private final TextPattern text = new TextPattern(); private final PatternInterner schemaInterner = new PatternInterner(); public SchemaPatternBuilder() { } public boolean hasIdTypes() { return idTypes; } Pattern makeElement(NameClass nameClass, Pattern content, Locator loc) { Pattern p = new ElementPattern(nameClass, content, loc); return schemaInterner.intern(p); } Pattern makeAttribute(NameClass nameClass, Pattern value, Locator loc) { if (value == notAllowed) return value; Pattern p = new AttributePattern(nameClass, value, loc); return schemaInterner.intern(p); } Pattern makeData(Datatype dt, Name dtName, List params) { noteDatatype(dt); Pattern p = new DataPattern(dt, dtName, params); return schemaInterner.intern(p); } Pattern makeDataExcept(Datatype dt, Name dtName, List params, Pattern except, Locator loc) { noteDatatype(dt); Pattern p = new DataExceptPattern(dt, dtName, params, except, loc); return schemaInterner.intern(p); } Pattern makeValue(Datatype dt, Name dtName, Object value, String stringValue) { noteDatatype(dt); Pattern p = new ValuePattern(dt, dtName, value, stringValue); return schemaInterner.intern(p); } Pattern makeText() { return text; } Pattern makeOneOrMore(Pattern p) { if (p == text) return p; return super.makeOneOrMore(p); } Pattern makeUnexpandedNotAllowed() { return unexpandedNotAllowed; } Pattern makeError() { Pattern p = new ErrorPattern(); return schemaInterner.intern(p); } Pattern makeChoice(Pattern p1, Pattern p2) { if (p1 == notAllowed || p1 == p2) return p2; if (p2 == notAllowed) return p1; return super.makeChoice(p1, p2); } Pattern makeList(Pattern p, Locator loc) { if (p == notAllowed) return p; Pattern p1 = new ListPattern(p, loc); return schemaInterner.intern(p1); } Pattern makeMixed(Pattern p) { return makeInterleave(text, p); } private void noteDatatype(Datatype dt) { if (dt.getIdType() != Datatype.ID_TYPE_NULL) idTypes = true; } } SimpleNameClass.java000066400000000000000000000015311225366607500335720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class SimpleNameClass implements NameClass { private final Name name; SimpleNameClass(Name name) { this.name = name; } public boolean contains(Name name) { return this.name.equals(name); } public int containsSpecificity(Name name) { return contains(name) ? SPECIFICITY_NAME : SPECIFICITY_NONE; } public int hashCode() { return name.hashCode(); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof SimpleNameClass)) return false; SimpleNameClass other = (SimpleNameClass)obj; return name.equals(other.name); } Name getName() { return name; } public void accept(NameClassVisitor visitor) { visitor.visitName(name); } public boolean isOpen() { return false; } } SingleDataDerivType.java000066400000000000000000000013511225366607500344210ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.ValidationContext; import java.util.List; /** * DerivType for a Pattern whose derivative wrt any data is always the same. */ class SingleDataDerivType extends DataDerivType { private PatternMemo memo; SingleDataDerivType() { } PatternMemo dataDeriv(ValidatorPatternBuilder builder, Pattern p, String str, ValidationContext vc, List fail) { if (memo == null) // this type never adds any failures memo = super.dataDeriv(builder, p, str, vc, null); return memo; } DataDerivType copy() { return new SingleDataDerivType(); } DataDerivType combine(DataDerivType ddt) { return ddt; } }StartAttributeDerivFunction.java000066400000000000000000000024331225366607500362350ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class StartAttributeDerivFunction extends StartTagOpenDerivFunction { StartAttributeDerivFunction(Name name, ValidatorPatternBuilder builder) { super(name, builder); } public Pattern caseElement(ElementPattern p) { return getPatternBuilder().makeNotAllowed(); } public Pattern caseGroup(GroupPattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); return getPatternBuilder().makeChoice( memoApply(p1).apply(new ApplyAfterFunction(getPatternBuilder()) { Pattern apply(Pattern x) { return getPatternBuilder().makeGroup(x, p2); } }), memoApply(p2).apply(new ApplyAfterFunction(getPatternBuilder()) { Pattern apply(Pattern x) { return getPatternBuilder().makeGroup(p1, x); } })); } public Pattern caseAttribute(AttributePattern p) { if (!p.getNameClass().contains(getName())) return getPatternBuilder().makeNotAllowed(); return getPatternBuilder().makeAfter(p.getContent(), getPatternBuilder().makeEmpty()); } PatternMemo apply(PatternMemo memo) { return memo.startAttributeDeriv(this); } } StartTagOpenDerivFunction.java000066400000000000000000000050661225366607500356340ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class StartTagOpenDerivFunction extends AbstractPatternFunction { private final Name name; private final ValidatorPatternBuilder builder; StartTagOpenDerivFunction(Name name, ValidatorPatternBuilder builder) { this.name = name; this.builder = builder; } public Pattern caseChoice(ChoicePattern p) { return builder.makeChoice(memoApply(p.getOperand1()), memoApply(p.getOperand2())); } public Pattern caseGroup(GroupPattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); Pattern tem = memoApply(p1).apply(new ApplyAfterFunction(builder) { Pattern apply(Pattern x) { return builder.makeGroup(x, p2); } }); return p1.isNullable() ? builder.makeChoice(tem, memoApply(p2)) : tem; } public Pattern caseInterleave(InterleavePattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); return builder.makeChoice( memoApply(p1).apply(new ApplyAfterFunction(builder) { Pattern apply(Pattern x) { return builder.makeInterleave(x, p2); } }), memoApply(p2).apply(new ApplyAfterFunction(builder) { Pattern apply(Pattern x) { return builder.makeInterleave(p1, x); } })); } public Pattern caseAfter(AfterPattern p) { final Pattern p1 = p.getOperand1(); final Pattern p2 = p.getOperand2(); return memoApply(p1).apply(new ApplyAfterFunction(builder) { Pattern apply(Pattern x) { return builder.makeAfter(x, p2); } }); } public Pattern caseOneOrMore(final OneOrMorePattern p) { final Pattern p1 = p.getOperand(); return memoApply(p1).apply(new ApplyAfterFunction(builder) { Pattern apply(Pattern x) { return builder.makeGroup(x, builder.makeOptional(p)); } }); } public Pattern caseElement(ElementPattern p) { if (!p.getNameClass().contains(name)) return builder.makeNotAllowed(); return builder.makeAfter(p.getContent(), builder.makeEmpty()); } public Pattern caseOther(Pattern p) { return builder.makeNotAllowed(); } final Pattern memoApply(Pattern p) { return apply(builder.getPatternMemo(p)).getPattern(); } PatternMemo apply(PatternMemo memo) { return memo.startTagOpenDeriv(this); } Name getName() { return name; } ValidatorPatternBuilder getPatternBuilder() { return builder; } } StartTagOpenRecoverDerivFunction.java000066400000000000000000000011141225366607500371500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; class StartTagOpenRecoverDerivFunction extends StartTagOpenDerivFunction { StartTagOpenRecoverDerivFunction(Name name, ValidatorPatternBuilder builder) { super(name, builder); } public Pattern caseGroup(GroupPattern p) { Pattern tem = super.caseGroup(p); if (p.getOperand1().isNullable()) return tem; return getPatternBuilder().makeChoice(tem, memoApply(p.getOperand2())); } PatternMemo apply(PatternMemo memo) { return memo.startTagOpenRecoverDeriv(this); } } StringDatatype.java000066400000000000000000000021731225366607500335170ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.datatype.Datatype2; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeStreamingValidator; import org.relaxng.datatype.ValidationContext; import org.relaxng.datatype.helpers.StreamingValidatorImpl; class StringDatatype implements Datatype2 { public boolean isValid(String str, ValidationContext vc) { return true; } public void checkValid(String str, ValidationContext vc) throws DatatypeException { if (!isValid(str, vc)) throw new DatatypeException(); } public Object createValue(String str, ValidationContext vc) { return str; } public boolean isContextDependent() { return false; } public boolean alwaysValid() { return true; } public int getIdType() { return ID_TYPE_NULL; } public boolean sameValue(Object obj1, Object obj2) { return obj1.equals(obj2); } public int valueHashCode(Object obj) { return obj.hashCode(); } public DatatypeStreamingValidator createStreamingValidator(ValidationContext vc) { return new StreamingValidatorImpl(this, vc); } } StringNormalizer.java000066400000000000000000000006201225366607500340610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import java.util.StringTokenizer; class StringNormalizer { static String normalize(String s) { StringBuilder buf = new StringBuilder(); for (StringTokenizer e = new StringTokenizer(s); e.hasMoreElements();) { if (buf.length() > 0) buf.append(' '); buf.append((String)e.nextElement()); } return buf.toString(); } } StringPattern.java000066400000000000000000000002451225366607500333570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; abstract class StringPattern extends Pattern { StringPattern(int hc) { super(false, DATA_CONTENT_TYPE, hc); } } TextOnlyFunction.java000066400000000000000000000006601225366607500340500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class TextOnlyFunction extends EndAttributesFunction { TextOnlyFunction(ValidatorPatternBuilder builder) { super(builder); } public Pattern caseAttribute(AttributePattern p) { return p; } public Pattern caseElement(ElementPattern p) { return getPatternBuilder().makeNotAllowed(); } PatternMemo apply(PatternMemo memo) { return memo.textOnly(this); } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/TextPattern.java000066400000000000000000000014031225366607500331110ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; class TextPattern extends Pattern { TextPattern() { super(true, MIXED_CONTENT_TYPE, TEXT_HASH_CODE); } boolean samePattern(Pattern other) { return other instanceof TextPattern; } T apply(PatternFunction f) { return f.caseText(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case DATA_EXCEPT_CONTEXT: throw new RestrictionViolationException("data_except_contains_text"); case START_CONTEXT: throw new RestrictionViolationException("start_contains_text"); case LIST_CONTEXT: throw new RestrictionViolationException("list_contains_text"); } } } TokenDatatype.java000066400000000000000000000003741225366607500333320ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import org.relaxng.datatype.ValidationContext; class TokenDatatype extends StringDatatype { public Object createValue(String str, ValidationContext vc) { return StringNormalizer.normalize(str); } } UnexpandedNotAllowedPattern.java000066400000000000000000000004221225366607500361720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; class UnexpandedNotAllowedPattern extends NotAllowedPattern { UnexpandedNotAllowedPattern() { } boolean isNotAllowed() { return false; } Pattern expand(SchemaPatternBuilder b) { return b.makeNotAllowed(); } } UnionNameClassNormalizer.java000066400000000000000000000005531225366607500354770ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; /** * Normalizes the union of zero or more name classes. */ public class UnionNameClassNormalizer extends NameClassNormalizer { public UnionNameClassNormalizer() { super(new NullNameClass()); } public void add(NameClass nameClass) { setNameClass(new ChoiceNameClass(getNameClass(), nameClass)); } } ValidatorPatternBuilder.java000066400000000000000000000127761225366607500353610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.util.VoidValue; import com.thaiopensource.xml.util.Name; import java.util.HashMap; import java.util.Map; import java.util.Set; public class ValidatorPatternBuilder extends PatternBuilder { private final Map patternMemoMap = new HashMap(); private final PatternFunction endAttributesFunction; private final PatternFunction ignoreMissingAttributesFunction; private final PatternFunction endTagDerivFunction; private final PatternFunction mixedTextDerivFunction; private final PatternFunction textOnlyFunction; private final PatternFunction recoverAfterFunction; private final PatternFunction dataDerivTypeFunction; private final Map choiceMap = new HashMap(); private final PatternFunction removeChoicesFunction = new RemoveChoicesFunction(); private final PatternFunction noteChoicesFunction = new NoteChoicesFunction(); private final PatternFunction> requiredElementsFunction = new RequiredElementsFunction(); private final PatternFunction> requiredAttributesFunction = new RequiredAttributesFunction(); private final PossibleNamesFunction possibleStartTagNamesFunction = new PossibleStartTagNamesFunction(); private final PossibleNamesFunction possibleAttributeNamesFunction = new PossibleAttributeNamesFunction(); private class NoteChoicesFunction extends AbstractPatternFunction { public VoidValue caseOther(Pattern p) { choiceMap.put(p, p); return VoidValue.VOID; } public VoidValue caseChoice(ChoicePattern p) { p.getOperand1().apply(this); p.getOperand2().apply(this); return VoidValue.VOID; } } private class RemoveChoicesFunction extends AbstractPatternFunction { public Pattern caseOther(Pattern p) { if (choiceMap.get(p) != null) return notAllowed; return p; } public Pattern caseChoice(ChoicePattern p) { Pattern p1 = p.getOperand1().apply(this); Pattern p2 = p.getOperand2().apply(this); if (p1 == p.getOperand1() && p2 == p.getOperand2()) return p; if (p1 == notAllowed) return p2; if (p2 == notAllowed) return p1; Pattern p3 = new ChoicePattern(p1, p2); return interner.intern(p3); } } public ValidatorPatternBuilder(PatternBuilder builder) { super(builder); endAttributesFunction = new EndAttributesFunction(this); ignoreMissingAttributesFunction = new IgnoreMissingAttributesFunction(this); endTagDerivFunction = new EndTagDerivFunction(this); mixedTextDerivFunction = new MixedTextDerivFunction(this); textOnlyFunction = new TextOnlyFunction(this); recoverAfterFunction = new RecoverAfterFunction(this); dataDerivTypeFunction = new DataDerivTypeFunction(this); } PatternMemo getPatternMemo(Pattern p) { PatternMemo memo = patternMemoMap.get(p); if (memo == null) { memo = new PatternMemo(p, this); patternMemoMap.put(p, memo); } return memo; } PatternFunction getEndAttributesFunction() { return endAttributesFunction; } PatternFunction getIgnoreMissingAttributesFunction() { return ignoreMissingAttributesFunction; } PatternFunction> getRequiredElementsFunction() { return requiredElementsFunction; } PatternFunction> getRequiredAttributesFunction() { return requiredAttributesFunction; } PossibleNamesFunction getPossibleStartTagNamesFunction() { return possibleStartTagNamesFunction; } PossibleNamesFunction getPossibleAttributeNamesFunction() { return possibleAttributeNamesFunction; } PatternFunction getEndTagDerivFunction() { return endTagDerivFunction; } PatternFunction getMixedTextDerivFunction() { return mixedTextDerivFunction; } PatternFunction getTextOnlyFunction() { return textOnlyFunction; } PatternFunction getRecoverAfterFunction() { return recoverAfterFunction; } PatternFunction getDataDerivTypeFunction() { return dataDerivTypeFunction; } Pattern makeAfter(Pattern p1, Pattern p2) { Pattern p = new AfterPattern(p1, p2); return interner.intern(p); } Pattern makeChoice(Pattern p1, Pattern p2) { if (p1 == p2) return p1; if (p1 == notAllowed) return p2; if (p2 == notAllowed) return p1; if (!(p1 instanceof ChoicePattern)) { if (p2.containsChoice(p1)) return p2; } else if (!(p2 instanceof ChoicePattern)) { if (p1.containsChoice(p2)) return p1; } else { p1.apply(noteChoicesFunction); p2 = p2.apply(removeChoicesFunction); if (choiceMap.size() > 0) choiceMap.clear(); if (p2 == notAllowed) return p1; } if (p1 instanceof AfterPattern && p2 instanceof AfterPattern) { AfterPattern ap1 = (AfterPattern)p1; AfterPattern ap2 = (AfterPattern)p2; if (ap1.getOperand1() == ap2.getOperand1()) return makeAfter(ap1.getOperand1(), makeChoice(ap1.getOperand2(), ap2.getOperand2())); if (ap1.getOperand1() == notAllowed) return ap2; if (ap2.getOperand1() == notAllowed) return ap1; if (ap1.getOperand2() == ap2.getOperand2()) return makeAfter(makeChoice(ap1.getOperand1(), ap2.getOperand1()), ap1.getOperand2()); } return super.makeChoice(p1, p2); } } ValueDataDerivType.java000066400000000000000000000040651225366607500342610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.ValidationContext; import java.util.HashMap; import java.util.List; import java.util.Map; /** * DataDerivType for a pattern which is a choice of values of the same datatype. */ class ValueDataDerivType extends DataDerivType { private final Datatype dt; private final Name dtName; private PatternMemo noValue; private Map valueMap; ValueDataDerivType(Datatype dt, Name dtName) { this.dt = dt; this.dtName = dtName; } DataDerivType copy() { return new ValueDataDerivType(dt, dtName); } PatternMemo dataDeriv(ValidatorPatternBuilder builder, Pattern p, String str, ValidationContext vc, List fail) { Object value = dt.createValue(str, vc); if (value == null) { if (noValue == null) noValue = super.dataDeriv(builder, p, str, vc, fail); else if (fail != null && noValue.isNotAllowed()) { try { dt.checkValid(str, vc); } catch (DatatypeException e) { fail.add(new DataDerivFailure(dt, dtName, e)); } } return noValue; } else { DatatypeValue dtv = new DatatypeValue(value, dt); if (valueMap == null) valueMap = new HashMap(); PatternMemo tem = valueMap.get(dtv); if (tem == null) { tem = super.dataDeriv(builder, p, str, vc, fail); valueMap.put(dtv, tem); } else if (tem.isNotAllowed() && fail != null) super.dataDeriv(builder, p, str, vc, fail); return tem; } } DataDerivType combine(DataDerivType ddt) { if (ddt instanceof ValueDataDerivType) { if (((ValueDataDerivType)ddt).dt == this.dt) return this; else return InconsistentDataDerivType.getInstance(); } else return ddt.combine(this); } Datatype getDatatype() { return dt; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/ValuePattern.java000066400000000000000000000024721225366607500332500ustar00rootroot00000000000000package com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.relaxng.datatype.Datatype; class ValuePattern extends StringPattern { private final Object obj; private final Datatype dt; private final Name dtName; private final String stringValue; ValuePattern(Datatype dt, Name dtName, Object obj, String stringValue) { super(combineHashCode(VALUE_HASH_CODE, dt.valueHashCode(obj))); this.dt = dt; this.dtName = dtName; this.obj = obj; this.stringValue = stringValue; } boolean samePattern(Pattern other) { if (getClass() != other.getClass()) return false; if (!(other instanceof ValuePattern)) return false; return (dt.equals(((ValuePattern)other).dt) && dt.sameValue(obj, ((ValuePattern)other).obj)); } T apply(PatternFunction f) { return f.caseValue(this); } void checkRestrictions(int context, DuplicateAttributeDetector dad, Alphabet alpha) throws RestrictionViolationException { switch (context) { case START_CONTEXT: throw new RestrictionViolationException("start_contains_value"); } } Datatype getDatatype() { return dt; } Name getDatatypeName() { return dtName; } Object getValue() { return obj; } String getStringValue() { return stringValue; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/resources/000077500000000000000000000000001225366607500320005ustar00rootroot00000000000000Messages.properties000066400000000000000000000270331225366607500356130ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/pattern/resources# Properties file specifying messages illegal_href_attribute=illegal \"href\" attribute ns_attribute_ignored=\"ns\" attribute ignored reference_to_undefined=reference to undefined pattern \"{0}\" missing_start_element=missing \"start\" element recursive_reference=bad recursive reference to pattern \"{0}\" recursive_include=recursive inclusion of URL \"{0}\" duplicate_define=multiple definitions of \"{0}\" without \"combine\" attribute duplicate_start=multiple definitions of start without \"combine\" attribute conflict_combine_define=conflicting values of \"combine\" attribute for definition of \"{0}\" conflict_combine_start=conflicting values of \"combine\" attribute for definition of start missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything interleave_string=interleave of \"string\" or \"data\" element group_string=group of \"string\" or \"data\" element one_or_more_string=repeat of \"string\" or \"data\" element unrecognized_datatype=datatype \"{1}\" from library \"{0}\" not recognized unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} unrecognized_datatype_library=datatype library \"{0}\" not recognized unrecognized_builtin_datatype=no such builtin datatype \"{0}\": must be \"string\" or \"token\" invalid_value=\"{0}\" is not a valid value of the datatype parent_ref_outside_grammar=reference to non-existent parent grammar ref_outside_grammar=reference to non-existent grammar expected_one_name_class=found \"{0}\" element but expected no further content builtin_param=builtin datatypes do not have any parameters invalid_param_display=invalid parameter:\n{0} invalid_param_detail_display=invalid parameter: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters datatype_requires_parameter=datatype cannot be used without parameters datatype_requires_parameter_detail=datatype cannot be used without parameters: {0} attribute_contains_attribute=an attribute pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//attribute) attribute_contains_element=an attribute pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//ref) data_except_contains_attribute=a data pattern must not exclude an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//attribute) data_except_contains_element=a data pattern must not exclude an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//ref) data_except_contains_empty=a data pattern must not exclude an empty pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//empty) data_except_contains_group=a data pattern must not exclude a group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//group) data_except_contains_interleave=a data pattern must not exclude an interleaved group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//interleave) data_except_contains_list=a data pattern must not exclude a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//list) data_except_contains_one_or_more=a data pattern must not exclude a repetition (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//oneOrMore) data_except_contains_text=a data pattern must not exclude a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//text) list_contains_attribute=a list pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//attribute) list_contains_element=a list pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//ref) list_contains_list=a list pattern must not contain a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//list) list_contains_text=a list pattern must not contain a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//text) list_contains_interleave=a list pattern must not contain an interleave pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//interleave) one_or_more_contains_group_contains_attribute=a group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=an interleaved group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//interleave//attribute) start_contains_attribute=found element matching the prohibited path start//attribute in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_data=found element matching the prohibited path start//data in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_empty=found element matching the prohibited path start//empty in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_group=found element matching the prohibited path start//group in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_interleave=found element matching the prohibited path start//interleave in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_list=found element matching the prohibited path start//list in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_one_or_more=found element matching the prohibited path start//oneOrMore in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_text=found element matching the prohibited path start//text in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_value=found element matching the prohibited path start//value in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) duplicate_attribute=duplicate attribute duplicate_attribute_name=duplicate attribute {0} duplicate_attribute_ns=attributes from namespace \"{0}\" can occur more than once interleave_element_overlap=overlapping element names in operands of \"interleave\" interleave_element_overlap_name=the element {0} can occur in more than one operand of \"interleave\" interleave_element_overlap_ns=elements from namespace \"{0}\" can occur in more than one operand of \"interleave\" interleave_text_overlap=both operands of \"interleave\" contain \"text\" open_name_class_not_repeated=attribute using \"nsName\" or \"anyName\" must be in \"oneOrMore\" xmlns_uri_attribute=attribute must not have namespace URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=attribute must not be named \"xmlns\" # Validation errors unknown_element=element {0} not allowed anywhere{1} unexpected_element_required_element_missing=element {0} not allowed yet; missing required element {1} unexpected_element_required_elements_missing=element {0} not allowed yet; missing required elements {1} element_not_allowed_yet=element {0} not allowed yet{1} out_of_context_element=element {0} not allowed here{1} no_attributes_allowed=found attribute {0}, but no attributes allowed here invalid_attribute_name=attribute {0} not allowed here{1} invalid_attribute_value=value of attribute {0} is invalid{1} required_attributes_missing_expected=element {0} missing one or more required attributes{1} required_attribute_missing=element {0} missing required attribute {1} required_attributes_missing=element {0} missing required attributes {1} incomplete_element_required_elements_missing_expected=element {0} incomplete{1} incomplete_element_required_element_missing=element {0} incomplete; missing required element {1} incomplete_element_required_elements_missing=element {0} incomplete; missing required elements {1} text_not_allowed=text not allowed here{0} document_incomplete=document incompletely matched invalid_element_value=character content of element {0} invalid{1} blank_not_allowed=empty content for element {0} not allowed{1} schema_allows_nothing=schema does not allow anything: it is equivalent to # ID correctness errors id_element_name_class=an \"element\" pattern containing an \"attribute\" pattern with a non-null ID-type must have a name class that contains only \"choice\" and \"name\" elements id_attribute_name_class=an \"attribute\" pattern with a non-null ID-type must have a name class that is a single name id_parent=a \"data\" or \"value\" pattern with non-null ID-type must occur as the child of an \"attribute\" pattern id_type_conflict=conflicting ID-types for attribute {1} of element {0} # ID soundness errors id_no_tokens=value of attribute of type ID contained no tokens id_multiple_tokens=value of attribute of type ID contained multiple tokens idref_no_tokens=value of attribute of type IDREF contained no tokens idref_multiple_tokens=value of attribute of type IDREF contained multiple tokens idrefs_no_tokens=value of attribute of type IDREFS contained no tokens missing_id=IDREF \"{0}\" without matching ID duplicate_id=ID \"{0}\" has already been defined first_id=first occurrence of ID \"{0}\" # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" from namespace \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (with {1}) or_list_pair={0} or {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} or {1} and_list_pair={0} and {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} and {1} expected=; expected {0} element_end_tag=the element end-tag text=text data=data element_list=element {0} element_other_ns=an element from another namespace expected_attribute=; expected attribute {0} expected_attribute_or_other_ns=; expected attribute {0} or an attribute from another namespace data_failures=; {0} token_failures=; token {0} invalid; {1} missing_token=; missing token; {0} expected_data=; expected data require_values=must be equal to {0} require_qnames=must be a QName equal to {0} require_datatype=must be a valid instance of datatype {0} jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/sax/000077500000000000000000000000001225366607500271045ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/sax/Context.java000066400000000000000000000035761225366607500314060ustar00rootroot00000000000000package com.thaiopensource.relaxng.sax; import com.thaiopensource.relaxng.match.MatchContext; import com.thaiopensource.relaxng.parse.sax.DtdContext; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.xml.sax.SAXException; public class Context extends DtdContext implements MatchContext { protected PrefixMapping prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); public Context() { } public void startPrefixMapping(String prefix, String uri) throws SAXException { prefixMapping = new PrefixMapping(prefix, "".equals(uri) ? null : uri, prefixMapping); } public void endPrefixMapping(String prefix) throws SAXException { prefixMapping = prefixMapping.getPrevious(); } public String getBaseUri() { return null; } protected static final class PrefixMapping { private final String prefix; // null for undeclaring private final String namespaceURI; private final PrefixMapping previous; PrefixMapping(String prefix, String namespaceURI, PrefixMapping prev) { this.prefix = prefix; this.namespaceURI = namespaceURI; this.previous = prev; } PrefixMapping getPrevious() { return previous; } } public String resolveNamespacePrefix(String prefix) { PrefixMapping tem = prefixMapping; do { if (tem.prefix.equals(prefix)) return tem.namespaceURI; tem = tem.previous; } while (tem != null); return null; } public void reset() { prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); clearDtdContext(); } public String getPrefix(String namespaceURI) { PrefixMapping tem = prefixMapping; do { if (namespaceURI.equals(tem.namespaceURI) && tem.namespaceURI == resolveNamespacePrefix(tem.prefix)) return tem.prefix; tem = tem.previous; } while (tem != null); return null; } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/sax/IdContentHandler.java000066400000000000000000000046111225366607500331360ustar00rootroot00000000000000package com.thaiopensource.relaxng.sax; import com.thaiopensource.relaxng.pattern.IdSoundnessChecker; import com.thaiopensource.relaxng.pattern.IdTypeMap; import com.thaiopensource.xml.util.Name; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; public class IdContentHandler implements ContentHandler { private final IdSoundnessChecker checker; private Locator locator; public IdContentHandler(IdTypeMap idTypeMap, ErrorHandler eh) { this.checker = new IdSoundnessChecker(idTypeMap, eh); } public void reset() { checker.reset(); locator = null; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startDocument() throws SAXException { } public void endDocument() throws SAXException { checker.endDocument(); setComplete(); } protected void setComplete() { /// XXX what's the point of this? } public void startPrefixMapping(String s, String s1) throws SAXException { } public void endPrefixMapping(String s) throws SAXException { } public void startElement(String namespaceUri, String localName, String qName, Attributes attributes) throws SAXException { Name elementName = new Name(namespaceUri, localName); int len = attributes.getLength(); for (int i = 0; i < len; i++) { Name attributeName = new Name(attributes.getURI(i), attributes.getLocalName(i)); String value = attributes.getValue(i); checker.attribute(elementName, attributeName, value, locator); } } public void endElement(String s, String s1, String s2) throws SAXException { } public void characters(char[] chars, int i, int i1) throws SAXException { } public void ignorableWhitespace(char[] chars, int i, int i1) throws SAXException { } public void processingInstruction(String s, String s1) throws SAXException { } public void skippedEntity(String s) throws SAXException { } public void notationDecl(String name, String publicId, String systemId) throws SAXException { } public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { } } jing-trang-20131210+dfsg+1/mod/pattern/src/main/com/thaiopensource/relaxng/sax/PatternValidator.java000066400000000000000000000072611225366607500332400ustar00rootroot00000000000000package com.thaiopensource.relaxng.sax; import com.thaiopensource.relaxng.match.Matcher; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.PatternMatcher; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.xml.util.Name; 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.SAXParseException; public class PatternValidator extends Context implements ContentHandler, DTDHandler { private Matcher matcher; private final ErrorHandler eh; private boolean bufferingCharacters = false; private final StringBuilder charBuf = new StringBuilder(); private Locator locator = null; public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (bufferingCharacters) { bufferingCharacters = false; check(matcher.matchTextBeforeStartTag(charBuf.toString(), this)); } Name name = new Name(namespaceURI, localName); check(matcher.matchStartTagOpen(name, qName, this)); int len = atts.getLength(); for (int i = 0; i < len; i++) { Name attName = new Name(atts.getURI(i), atts.getLocalName(i)); String attQName = atts.getQName(i); check(matcher.matchAttributeName(attName, attQName, this)); check(matcher.matchAttributeValue(atts.getValue(i), attName, attQName, this)); } check(matcher.matchStartTagClose(name, qName, this)); if (matcher.isTextTyped()) { bufferingCharacters = true; charBuf.setLength(0); } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (bufferingCharacters) { bufferingCharacters = false; if (charBuf.length() > 0) check(matcher.matchTextBeforeEndTag(charBuf.toString(), new Name(namespaceURI, localName), qName, this)); } check(matcher.matchEndTag(new Name(namespaceURI, localName), qName, this)); } public void characters(char ch[], int start, int length) throws SAXException { if (bufferingCharacters) { charBuf.append(ch, start, length); return; } for (int i = 0; i < length; i++) { switch (ch[start + i]) { case ' ': case '\r': case '\t': case '\n': break; default: check(matcher.matchUntypedText(this)); return; } } } public void endDocument() throws SAXException { check(matcher.matchEndDocument()); } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startDocument() throws SAXException { check(matcher.matchStartDocument()); } public void processingInstruction(String target, String date) { } public void skippedEntity(String name) { } public void ignorableWhitespace(char[] ch, int start, int len) { } public void startPrefixMapping(String prefix, String uri) throws SAXException { if (bufferingCharacters) { bufferingCharacters = false; check(matcher.matchTextBeforeStartTag(charBuf.toString(), this)); } super.startPrefixMapping(prefix, uri); } public PatternValidator(Pattern pattern, ValidatorPatternBuilder builder, ErrorHandler eh) { this.matcher = new PatternMatcher(pattern, builder); this.eh = eh; } public void reset() { super.reset(); bufferingCharacters = false; locator = null; matcher = matcher.start(); } private void check(boolean ok) throws SAXException { if (!ok) eh.error(new SAXParseException(matcher.getErrorMessage(), locator)); } } jing-trang-20131210+dfsg+1/mod/pattern/src/test/000077500000000000000000000000001225366607500210765ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/000077500000000000000000000000001225366607500216545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/thaiopensource/000077500000000000000000000000001225366607500247045ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500263445ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/thaiopensource/relaxng/pattern/000077500000000000000000000000001225366607500300215ustar00rootroot00000000000000NameClassNormalizerTest.java000066400000000000000000000056051225366607500353640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.xml.util.Name; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Test NameClassNormalizer. */ public class NameClassNormalizerTest { @DataProvider(name = "pairs") Object[][] createPairs() { final Name foo = new Name("", "foo"); final String ns1 = "http://www.example.com/1"; final Name ns1foo = new Name(ns1, "foo"); Map> ns1Map = new HashMap>(); ns1Map.put(ns1, new HashSet()); final NormalizedNameClass ns1NNC = new NormalizedNsNameClass(emptyNameSet(), ns1Map); final NormalizedNameClass anyNNC = new NormalizedAnyNameClass(emptyNameSet(), emptyStringSet(), emptyNameSet()); final NormalizedNsNameClass fooNNC = new NormalizedNsNameClass(Collections.singleton(foo), emptyMap()); final NormalizedNsNameClass ns1fooNNC = new NormalizedNsNameClass(Collections.singleton(ns1foo), emptyMap()); final NormalizedNsNameClass emptyNNC = new NormalizedNsNameClass(emptyNameSet(), emptyMap()); return new Object[][] { { new SimpleNameClass(foo), fooNNC}, { new ChoiceNameClass(new SimpleNameClass(foo), new SimpleNameClass(foo)), fooNNC }, { new AnyNameClass(), anyNNC }, { new AnyNameExceptNameClass(new AnyNameClass()), emptyNNC }, { new NsNameClass(ns1), ns1NNC }, { new ChoiceNameClass(new SimpleNameClass(foo), new AnyNameClass()), anyNNC }, { new ChoiceNameClass(new NsNameClass(ns1), new AnyNameClass()), anyNNC }, { new NsNameExceptNameClass(ns1, new AnyNameClass()), emptyNNC }, { new NsNameExceptNameClass(ns1, new NsNameClass(ns1)), emptyNNC }, { new NsNameExceptNameClass(ns1, new SimpleNameClass(foo)), ns1NNC }, { new NsNameExceptNameClass(ns1, new NsNameExceptNameClass(ns1, new SimpleNameClass(ns1foo))), ns1fooNNC } }; } @Test(dataProvider = "pairs") public void testNormalize(NameClass nc, NormalizedNameClass nnc) { Assert.assertEquals(new NameClassNormalizer(nc).normalize(), nnc); } static private Set emptyNameSet() { return Collections.emptySet(); } static private Set emptyStringSet() { return Collections.emptySet(); } static private Map> emptyMap() { return Collections.emptyMap(); } } PatternMatcherTest.java000066400000000000000000000110251225366607500343650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/pattern/src/test/com/thaiopensource/relaxng/patternpackage com.thaiopensource.relaxng.pattern; import com.thaiopensource.relaxng.match.Matcher; import com.thaiopensource.relaxng.sax.Context; import com.thaiopensource.xml.util.Name; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.LocatorImpl; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.Map; /** * Test PatternMatcher. */ public class PatternMatcherTest extends SchemaPatternBuilder { final SchemaPatternBuilder spb = new SchemaPatternBuilder(); static private final Name root = new Name("", "root"); static private final Map> EMPTY_MAP = Collections.emptyMap(); @DataProvider(name = "startTagPairs") Object[][] startTagPairs() { final Name foo = new Name("", "foo"); final Name bar = new Name("", "bar"); Set nameSet = new HashSet(); nameSet.add(foo); nameSet.add(bar); final NormalizedNameClass foobarNNC = new NormalizedNsNameClass(nameSet, EMPTY_MAP); final Locator loc = new LocatorImpl(); return new Object[][] { { rootMatcher(makeChoice(makeElement(new SimpleNameClass(foo), makeEmpty(), loc), makeElement(new SimpleNameClass(bar), makeEmpty(), loc))), foobarNNC } }; } @Test(dataProvider = "startTagPairs") public void testPossibleStartTagNames(Matcher matcher, NormalizedNameClass nnc) { Assert.assertEquals(matcher.possibleStartTagNames(), nnc); } private Matcher rootMatcher(Pattern start) { Matcher matcher = new PatternMatcher(start, new ValidatorPatternBuilder(this)); Assert.assertTrue(matcher.matchStartDocument()); return matcher; } @DataProvider(name = "attributePairs") Object[][] attributePairs() { final Name foo = new Name("", "foo"); final Name bar = new Name("", "bar"); Set nameSet = new HashSet(); nameSet.add(foo); nameSet.add(bar); final NormalizedNameClass foobarNNC = new NormalizedNsNameClass(nameSet, EMPTY_MAP); final Locator loc = new LocatorImpl(); return new Object[][] { { rootAttributeMatcher(makeElement(new SimpleNameClass(root), makeGroup(makeAttribute(new SimpleNameClass(foo), makeText(), loc), makeAttribute(new SimpleNameClass(bar), makeText(), loc)), loc)), foobarNNC } }; } private Matcher rootAttributeMatcher(Pattern start) { Matcher matcher = rootMatcher(start); Assert.assertTrue(matcher.matchStartTagOpen(root, "", new Context())); return matcher; } @Test(dataProvider = "attributePairs") public void testPossibleAttributeNames(Matcher matcher, NormalizedNameClass nnc) { Assert.assertEquals(matcher.possibleAttributeNames(), nnc); } @DataProvider(name = "missingNamespacedAttribute") Object[][] missingNamespacedAttribute() { final Name foo = new Name("http://example.com/", "foo"); final Locator loc = new LocatorImpl(); return new Object[][] {{ rootMissingNamespacedAttributeMatcher( makeElement( new SimpleNameClass(root), makeAttribute(new SimpleNameClass(foo), makeText(), loc), loc ) ) }}; } private Matcher rootMissingNamespacedAttributeMatcher(Pattern start) { Matcher matcher = rootMatcher(start); // Declare the attribute namespace "http://example.com/" as default namespace. Context context = new Context(); try { context.startPrefixMapping("", "http://example.com/"); } catch (SAXException e) { Assert.fail(e.getMessage(), e); } // Start the root element Assert.assertTrue(matcher.matchStartTagOpen(root, "", context)); // Close the root element, we should get the required attribute missing error. Assert.assertFalse(matcher.matchStartTagClose(root, "", context)); return matcher; } @Test(dataProvider = "missingNamespacedAttribute") public void testErrorMessageAttributeNames(Matcher matcher) { // Before fixing issue 105 the error message was // element "root" missing required attribute "foo" // Now we should get the correct namespace for the missing attribute: Assert.assertEquals(matcher.getErrorMessage(), "element \"root\" missing required attribute \"ns:foo\" (with xmlns:ns=\"http://example.com/\")"); } } jing-trang-20131210+dfsg+1/mod/picl/000077500000000000000000000000001225366607500166025ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/mod.xml000066400000000000000000000005541225366607500201070ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/picl/src/000077500000000000000000000000001225366607500173715ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/000077500000000000000000000000001225366607500203155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/000077500000000000000000000000001225366607500210735ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/000077500000000000000000000000001225366607500241235ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/000077500000000000000000000000001225366607500257145ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/000077500000000000000000000000001225366607500266435ustar00rootroot00000000000000AttributePathPattern.java000066400000000000000000000003761225366607500335530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; class AttributePathPattern extends PathPattern { AttributePathPattern(String[] names, boolean[] descendantsOrSelf) { super(names, descendantsOrSelf); } boolean isAttribute() { return true; } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/ChoicePattern.java000066400000000000000000000011431225366607500322350ustar00rootroot00000000000000package com.thaiopensource.validate.picl; class ChoicePattern extends Pattern { private final Pattern[] choices; ChoicePattern(Pattern[] choices) { this.choices = choices; } boolean matches(Path path, int rootDepth) { for (int i = 0; i < choices.length; i++) if (choices[i].matches(path, rootDepth)) return true; return false; } public String toString() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < choices.length; i++) { if (i != 0) buf.append('|'); buf.append(choices[i].toString()); } return buf.toString(); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/Constraint.java000066400000000000000000000001501225366607500316260ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface Constraint { void activate(PatternManager pm); } ElementPathPattern.java000066400000000000000000000003721225366607500331750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; class ElementPathPattern extends PathPattern { ElementPathPattern(String[] names, boolean[] descendantsOrSelf) { super(names, descendantsOrSelf); } boolean isAttribute() { return false; } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/ErrorContext.java000066400000000000000000000006311225366607500321440ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import org.xml.sax.Locator; interface ErrorContext { /** * If locator is null, use this object's locator. */ void error(Locator locator, String key); /** * If locator is null, use this object's locator. */ void error(Locator locator, String key, String arg); /** * Returns non-volatile Locator, never-null. */ Locator saveLocator(); } InvalidPatternException.java000066400000000000000000000001371225366607500342330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; class InvalidPatternException extends Exception { } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/KeyConstraint.java000066400000000000000000000031671225366607500323120ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import org.xml.sax.Locator; import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; class KeyConstraint implements Constraint { private final Pattern key; KeyConstraint(Pattern key) { this.key = key; } static class KeyIndex { private final Hashtable table; KeyIndex() { table = new Hashtable(); } KeyInfo lookupCreate(Object key) { KeyInfo info = (KeyInfo)table.get(key); if (info == null) { info = new KeyInfo(); table.put(key, info); } return info; } Enumeration keys() { return table.keys(); } } static class KeyInfo { String representation; Locator firstKeyLocator; Vector pendingRefLocators; } static class KeySelectionHandler extends SelectedValueHandler { private final KeyIndex index; KeySelectionHandler(KeyIndex index) { this.index = index; } void select(ErrorContext ec, Locator locator, Object value, String representation) { KeyInfo info = index.lookupCreate(value); if (info.firstKeyLocator == null) { if (locator == null) locator = ec.saveLocator(); info.firstKeyLocator = locator; info.pendingRefLocators = null; info.representation = representation; } else ec.error(locator, "duplicate_key", representation); } } public void activate(PatternManager pm) { activate(pm, new KeyIndex()); } void activate(PatternManager pm, KeyIndex index) { pm.registerPattern(key, new ValueSelectionHandler(new KeySelectionHandler(index))); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/KeyRefConstraint.java000066400000000000000000000031761225366607500327470ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import org.xml.sax.Locator; import java.util.Vector; import java.util.Enumeration; class KeyRefConstraint extends KeyConstraint { private final Pattern ref; static class RefSelectionHandler extends SelectedValueHandler { private final KeyIndex index; RefSelectionHandler(KeyConstraint.KeyIndex index) { this.index = index; } void select(ErrorContext ec, Locator locator, Object value, String representation) { KeyInfo info = index.lookupCreate(value); if (info.firstKeyLocator == null) { if (info.pendingRefLocators == null) info.pendingRefLocators = new Vector(); if (locator == null) locator = ec.saveLocator(); info.pendingRefLocators.addElement(locator); } if (info.representation == null) info.representation = representation; } public void selectComplete(ErrorContext ec) { for (Enumeration e = index.keys(); e.hasMoreElements();) { Object key = e.nextElement(); KeyInfo info = index.lookupCreate(key); if (info.pendingRefLocators == null) continue; for (int i = 0, len = info.pendingRefLocators.size(); i < len; i++) { Locator loc = (Locator)info.pendingRefLocators.elementAt(i); ec.error(loc, "undefined_key", info.representation); } } } } KeyRefConstraint(Pattern key, Pattern ref) { super(key); this.ref = ref; } void activate(PatternManager pm, KeyIndex index) { super.activate(pm, index); pm.registerPattern(ref, new ValueSelectionHandler(new RefSelectionHandler(index))); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/MultiConstraint.java000066400000000000000000000005411225366607500326450ustar00rootroot00000000000000package com.thaiopensource.validate.picl; class MultiConstraint implements Constraint { private final Constraint[] constraints; MultiConstraint(Constraint[] constraints) { this.constraints = constraints; } public void activate(PatternManager pm) { for (int i = 0; i < constraints.length; i++) constraints[i].activate(pm); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/NamespaceContext.java000066400000000000000000000002151225366607500327450ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface NamespaceContext { String getNamespaceUri(String string); String defaultPrefix(); } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/NotAllowedPattern.java000066400000000000000000000003301225366607500331100ustar00rootroot00000000000000package com.thaiopensource.validate.picl; class NotAllowedPattern extends Pattern { boolean matches(Path path, int rootDepth) { return false; } public String toString() { return "(notAllowed)"; } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/Path.java000066400000000000000000000002461225366607500304040ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface Path { int length(); String getLocalName(int i); String getNamespaceUri(int i); boolean isAttribute(); } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/PathPattern.java000066400000000000000000000057401225366607500317460ustar00rootroot00000000000000package com.thaiopensource.validate.picl; abstract class PathPattern extends Pattern { private final String[] names; private final boolean[] descendantsOrSelf; static final String ANY = "#any"; PathPattern(String[] names, boolean[] descendantsOrSelf) { this.names = names; this.descendantsOrSelf = descendantsOrSelf; } abstract boolean isAttribute(); boolean matches(Path path, int rootDepth) { return (isAttribute() == path.isAttribute() && matchSegment(path, rootDepth, path.length() - rootDepth, 0, names.length >> 1, false)); } private boolean matchSegment(Path path, int pathStartIndex, int pathLength, int patternStartIndex, int patternLength, boolean ignoreRightmostDescendantsOrSelf) { if (patternLength > pathLength) return false; while (patternLength > 0 && (ignoreRightmostDescendantsOrSelf || !descendantsOrSelf[patternStartIndex + patternLength])) { if (!matchStep(path, pathStartIndex + pathLength - 1, patternStartIndex + patternLength - 1)) return false; pathLength--; patternLength--; ignoreRightmostDescendantsOrSelf = false; } while (patternLength > 0 && !descendantsOrSelf[patternStartIndex]) { if (!matchStep(path, pathStartIndex, patternStartIndex)) return false; pathStartIndex++; patternStartIndex++; pathLength--; patternLength--; } if (patternLength == 0) return descendantsOrSelf[patternStartIndex] || pathLength == 0; for (pathLength--; pathLength >= patternLength; pathLength--) if (matchSegment(path, pathStartIndex, pathLength, patternStartIndex, patternLength, true)) return true; return false; } private boolean matchStep(Path path, int pathIndex, int patternIndex) { patternIndex *= 2; return (matchName(path.getNamespaceUri(pathIndex), names[patternIndex]) && matchName(path.getLocalName(pathIndex), names[patternIndex + 1])); } private static boolean matchName(String str, String pattern) { if (pattern == ElementPathPattern.ANY) return true; return str.equals(pattern); } public String toString() { StringBuffer buf = new StringBuffer(); for (int i = 0, j = 0; i < names.length; i += 2, j++) { if (j != 0) buf.append(descendantsOrSelf[j] ? "//" : "/"); else if (descendantsOrSelf[0]) buf.append(".//"); if (isAttribute() && i + 2 == names.length) buf.append('@'); if (names[i] == ANY) buf.append('*'); else { if (names[i].length() != 0) { buf.append('{'); buf.append(names[i]); buf.append('}'); } buf.append(names[i + 1] == ANY ? "*" : names[i + 1]); } } if (names.length == 0) buf.append(descendantsOrSelf[0] ? ".//." : "."); else if (descendantsOrSelf[descendantsOrSelf.length - 1]) buf.append("//."); return buf.toString(); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/Pattern.java000066400000000000000000000001741225366607500311250ustar00rootroot00000000000000package com.thaiopensource.validate.picl; abstract class Pattern { abstract boolean matches(Path path, int rootDepth); } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/PatternBuilder.java000066400000000000000000000060041225366607500324320ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import java.util.Vector; class PatternBuilder { static final byte CHILD = 0; static final byte ATTRIBUTE = 1; private boolean hadDescendantOrSelf = false; private final Vector choices = new Vector(); private final Vector names = new Vector(); private final Vector descendantsOrSelf = new Vector(); private static final int NO_ATTRIBUTE = 0; private static final int LAST_WAS_ATTRIBUTE = 1; private static final int NON_LEAF_ATTRIBUTE = 2; private int attributeType = NO_ATTRIBUTE; void addName(byte type, String namespaceUri, String localName) { descendantsOrSelf.addElement(Boolean.valueOf(hadDescendantOrSelf)); hadDescendantOrSelf = false; names.addElement(namespaceUri); names.addElement(localName); switch (attributeType) { case LAST_WAS_ATTRIBUTE: attributeType = NON_LEAF_ATTRIBUTE; break; case NO_ATTRIBUTE: if (type == ATTRIBUTE) attributeType = LAST_WAS_ATTRIBUTE; break; } } void addAnyName(byte type) { addName(type, PathPattern.ANY, PathPattern.ANY); } void addNsName(byte type, String namespaceUri) { addName(type, namespaceUri, PathPattern.ANY); } void addDescendantsOrSelf() { if (attributeType == NO_ATTRIBUTE) hadDescendantOrSelf = true; } private PathPattern wrapUpAlternative() { PathPattern result; if (attributeType == NON_LEAF_ATTRIBUTE) result = null; else { String[] namesArray = new String[names.size()]; for (int i = 0; i < namesArray.length; i++) namesArray[i] = (String)names.elementAt(i); boolean[] descendantsOrSelfArray = new boolean[descendantsOrSelf.size() + 1]; for (int i = 0; i < descendantsOrSelfArray.length - 1; i++) descendantsOrSelfArray[i] = ((Boolean)descendantsOrSelf.elementAt(i)).booleanValue(); descendantsOrSelfArray[descendantsOrSelfArray.length - 1] = hadDescendantOrSelf; if (attributeType == NO_ATTRIBUTE) result = new ElementPathPattern(namesArray, descendantsOrSelfArray); else result = new AttributePathPattern(namesArray, descendantsOrSelfArray); } cleanupAlternative(); return result; } private void cleanupAlternative() { attributeType = NO_ATTRIBUTE; hadDescendantOrSelf = false; names.setSize(0); descendantsOrSelf.setSize(0); } void cleanup() { cleanupAlternative(); choices.setSize(0); } void alternative() { Pattern pattern = wrapUpAlternative(); if (pattern != null) choices.addElement(pattern); } Pattern createPattern() { Pattern pattern = wrapUpAlternative(); if (choices.size() == 0) { if (pattern == null) return new NotAllowedPattern(); return pattern; } else { if (pattern != null) choices.addElement(pattern); Pattern[] patterns = new Pattern[choices.size()]; for (int i = 0; i < patterns.length; i++) patterns[i] = (Pattern)choices.elementAt(i); return new ChoicePattern(patterns); } } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/PatternManager.java000066400000000000000000000002761225366607500324230ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface PatternManager { void registerPattern(Pattern pattern, SelectionHandler handler); void registerValueHandler(ValueHandler handler); } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/PatternParser.java000066400000000000000000000203751225366607500323070ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import com.thaiopensource.util.Localizer; import com.thaiopensource.xml.util.Naming; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.Locator; import org.xml.sax.SAXParseException; class PatternParser { private final ErrorHandler eh; private final Localizer localizer; private String pattern; private int patternOffset; private int patternLength; private int currentToken; private int tokenStartOffset; private String tokenNamespaceUri; private String tokenLocalName; private final PatternBuilder builder = new PatternBuilder(); private NamespaceContext namespaceContext; private final StringBuffer nameBuffer = new StringBuffer(); private static final int TOKEN_EOF = 0; private static final int TOKEN_SLASH = 1; private static final int TOKEN_SLASH_SLASH = 2; private static final int TOKEN_CHOICE = 3; private static final int TOKEN_CHILD_AXIS = 4; private static final int TOKEN_ATTRIBUTE_AXIS = 5; private static final int TOKEN_DOT = 6; private static final int TOKEN_QNAME = 7; private static final int TOKEN_NCNAME_STAR = 8; private static final int TOKEN_STAR = 9; private Locator locator; PatternParser(ErrorHandler eh, Localizer localizer) { this.eh = eh; this.localizer = localizer; } Pattern parse(String pattern, Locator locator, NamespaceContext namespaceContext) throws SAXException, InvalidPatternException { this.pattern = pattern; this.patternOffset = 0; this.patternLength = pattern.length(); this.locator = locator; this.namespaceContext = namespaceContext; try { do { parseChoice(); } while (currentToken == TOKEN_CHOICE); return builder.createPattern(); } finally { builder.cleanup(); } } private void parseChoice() throws SAXException, InvalidPatternException { for (;;) { parseStep(); advance(); switch (currentToken) { case TOKEN_SLASH: break; case TOKEN_SLASH_SLASH: builder.addDescendantsOrSelf(); break; case TOKEN_CHOICE: builder.alternative(); return; case TOKEN_EOF: return; default: throw error("expected_step_connector"); } } } private void parseStep() throws SAXException, InvalidPatternException { advance(); byte type; switch (currentToken) { case TOKEN_ATTRIBUTE_AXIS: type = PatternBuilder.ATTRIBUTE; advance(); break; case TOKEN_CHILD_AXIS: type = PatternBuilder.CHILD; advance(); break; case TOKEN_DOT: return; default: type = PatternBuilder.CHILD; break; } switch (currentToken) { case TOKEN_QNAME: builder.addName(type, tokenNamespaceUri, tokenLocalName); break; case TOKEN_STAR: builder.addAnyName(type); break; case TOKEN_NCNAME_STAR: builder.addNsName(type, tokenNamespaceUri); break; default: throw error("expected_name_test"); } } private void advance() throws SAXException, InvalidPatternException { for (;;) { tokenStartOffset = patternOffset; if (patternOffset >= patternLength) { currentToken = TOKEN_EOF; return; } char ch = pattern.charAt(patternOffset); switch (ch) { case ' ': case '\t': case '\r': case '\n': patternOffset++; continue; case '.': patternOffset++; currentToken = TOKEN_DOT; return; case '@': patternOffset++; currentToken = TOKEN_ATTRIBUTE_AXIS; return; case '|': patternOffset++; currentToken = TOKEN_CHOICE; return; case '/': if (++patternOffset < patternLength && pattern.charAt(patternOffset) == '/') { patternOffset++; currentToken = TOKEN_SLASH_SLASH; } else currentToken = TOKEN_SLASH; return; case '*': patternOffset++; currentToken = TOKEN_STAR; return; } String name = scanNCName("illegal_char"); if ((name.equals("child") || name.equals("attribute")) && tryScanDoubleColon()) { currentToken = name.charAt(0) == 'c' ? TOKEN_CHILD_AXIS : TOKEN_ATTRIBUTE_AXIS; return; } if (patternOffset < patternLength && pattern.charAt(patternOffset) == ':') { tokenNamespaceUri = expandPrefix(name); patternOffset++; if (patternOffset == patternLength) throw error("expected_star_or_ncname"); if (pattern.charAt(patternOffset) == '*') { patternOffset++; currentToken = TOKEN_NCNAME_STAR; return; } tokenLocalName = scanNCName("expected_star_or_ncname"); currentToken = TOKEN_QNAME; return; } tokenLocalName = name; tokenNamespaceUri = namespaceContext.defaultPrefix(); currentToken = TOKEN_QNAME; return; } } private boolean tryScanDoubleColon() { for (int i = patternOffset; i < patternLength; i++) { switch (pattern.charAt(i)) { case ' ': case '\t': case '\r': case '\n': break; case ':': if (++i < patternLength && pattern.charAt(i) == ':') { patternOffset = i + 1; return true; } default: return false; } } return false; } private String expandPrefix(String prefix) throws SAXException, InvalidPatternException { String ns = namespaceContext.getNamespaceUri(prefix); if (ns == null) throw error("unbound_prefix", prefix); return ns; } private String scanNCName(String message) throws SAXException, InvalidPatternException { char ch = pattern.charAt(patternOffset++); if (!maybeNameStartChar(ch)) throw error(message); nameBuffer.setLength(0); nameBuffer.append(ch); for (; patternOffset < patternLength; patternOffset++) { ch = pattern.charAt(patternOffset); if (!maybeNameChar(ch)) break; nameBuffer.append(ch); } String name = nameBuffer.toString(); if (!Naming.isNcname(name)) throw error("illegal_ncname", name); return name; } private static boolean maybeNameStartChar(char ch) { return ch > 0x80 || Character.isLetter(ch) || ch == '_'; } private static boolean maybeNameChar(char ch) { return ch > 0x80 || Character.isLetterOrDigit(ch) || ".-_".indexOf(ch) >= 0; } private InvalidPatternException error(String key) throws SAXException { if (eh != null) eh.error(new SAXParseException(addContext(localizer.message(key)), locator)); return new InvalidPatternException(); } private InvalidPatternException error(String key, String arg) throws SAXException { if (eh != null) eh.error(new SAXParseException(addContext(localizer.message(key, arg)), locator)); return new InvalidPatternException(); } private String addContext(String message) { return localizer.message("context", new Object[] { message, pattern.substring(0, tokenStartOffset), pattern.substring(tokenStartOffset, patternOffset), pattern.substring(patternOffset) }); } static public void main(String[] args) throws SAXException { PatternParser parser = new PatternParser(new com.thaiopensource.xml.sax.ErrorHandlerImpl(), new Localizer(PatternParser.class)); String[] tests = { "foo//bar", ".", ".//.//././././/foo", "foo:bar", "bar:*", "*", "/", "foo/bar|bar/baz", "foo/", "", ".//.", ".//", "foo / @ bar", "child::foo:bar", "attribute::baz" }; NamespaceContext nsc = new NamespaceContext() { public String getNamespaceUri(String prefix) { return "http://" + prefix; } public String defaultPrefix() { return ""; } }; for (int i = 0; i < tests.length; i++) { try { Pattern pattern = parser.parse(tests[i], null, nsc); System.out.println(tests[i] + " => " + pattern.toString()); } catch (InvalidPatternException e) { } } } } PiclSchemaReceiverFactory.java000066400000000000000000000013111225366607500344500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; import com.thaiopensource.validate.auto.SchemaReceiverFactory; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.Option; import com.thaiopensource.util.PropertyMap; public class PiclSchemaReceiverFactory implements SchemaReceiverFactory { private static final String PICL_URI = SchemaReader.BASE_URI + "picl"; public SchemaReceiver createSchemaReceiver(String namespaceUri, PropertyMap properties) { if (!PICL_URI.equals(namespaceUri)) return null; return new SchemaReceiverImpl(properties); } public Option getOption(String uri) { return null; } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/SchemaImpl.java000066400000000000000000000010011225366607500315200ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import com.thaiopensource.validate.AbstractSchema; import com.thaiopensource.validate.Validator; import com.thaiopensource.util.PropertyMap; class SchemaImpl extends AbstractSchema { private final Constraint constraint; SchemaImpl(PropertyMap properties, Constraint constraint) { super(properties); this.constraint = constraint; } public Validator createValidator(PropertyMap properties) { return new ValidatorImpl(constraint, properties); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/SchemaParser.java000066400000000000000000000076701225366607500320750ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.SinglePropertyMap; import com.thaiopensource.util.Localizer; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.xml.sax.CountingErrorHandler; import com.thaiopensource.xml.sax.DelegatingContentHandler; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.Attributes; import java.util.Vector; import java.util.Stack; class SchemaParser extends DelegatingContentHandler implements SchemaFuture, NamespaceContext { private final Vector constraints = new Vector(); private final PropertyMap properties; private final CountingErrorHandler ceh; private Locator locator; private final Stack prefixes = new Stack(); private final Localizer localizer = new Localizer(SchemaParser.class); private final PatternParser patternParser; SchemaParser(PropertyMap properties, Schema piclSchema) { this.properties = properties; ceh = new CountingErrorHandler(properties.get(ValidateProperty.ERROR_HANDLER)); Validator validator = piclSchema.createValidator(SinglePropertyMap.newInstance(ValidateProperty.ERROR_HANDLER, ceh)); setDelegate(validator.getContentHandler()); patternParser = new PatternParser(ceh, localizer); } public void setDocumentLocator(Locator locator) { super.setDocumentLocator(locator); this.locator = locator; } public void startDocument() throws SAXException { super.startDocument(); prefixes.push("xml"); prefixes.push(WellKnownNamespaces.XML); } public void startPrefixMapping(String prefix, String uri) throws SAXException { if (prefix == null) prefix = ""; prefixes.push(prefix); if (uri != null && uri.length() == 0) uri = null; prefixes.push(uri); super.startPrefixMapping(prefix, uri); } public void endPrefixMapping(String prefix) throws SAXException { prefixes.pop(); prefixes.pop(); super.endPrefixMapping(prefix); } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { super.startElement(namespaceURI, localName, qName, atts); if (ceh.getHadErrorOrFatalError()) return; if (!localName.equals("constraint")) return; String key = atts.getValue("", "key"); try { Pattern keyPattern = patternParser.parse(key, locator, this); String ref = atts.getValue("", "ref"); if (ref != null) { Pattern refPattern = patternParser.parse(ref, locator, this); constraints.addElement(new KeyRefConstraint(keyPattern, refPattern)); } else constraints.addElement(new KeyConstraint(keyPattern)); } catch (InvalidPatternException e) { } } public Schema getSchema() throws IncorrectSchemaException { if (ceh.getHadErrorOrFatalError()) throw new IncorrectSchemaException(); Constraint constraint; if (constraints.size() == 1) constraint = (Constraint)constraints.elementAt(0); else { Constraint[] v = new Constraint[constraints.size()]; for (int i = 0; i < v.length; i++) v[i] = (Constraint)constraints.elementAt(i); constraint = new MultiConstraint(v); } return new SchemaImpl(properties, constraint); } public RuntimeException unwrapException(RuntimeException e) { return e; } public String getNamespaceUri(String prefix) { for (int i = prefixes.size(); i > 0; i -= 2) { if (prefixes.elementAt(i - 2).equals(prefix)) return (String)prefixes.elementAt(i - 1); } return null; } public String defaultPrefix() { return ""; } } SchemaReceiverImpl.java000066400000000000000000000044241225366607500331420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; import com.thaiopensource.util.PropertyMap; import com.thaiopensource.util.SinglePropertyMap; import com.thaiopensource.validate.IncorrectSchemaException; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.auto.SchemaFuture; import com.thaiopensource.validate.auto.SchemaReceiver; import com.thaiopensource.validate.rng.CompactSchemaReader; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import java.io.IOException; import java.net.URL; class SchemaReceiverImpl implements SchemaReceiver { private final String PICL_SCHEMA = "picl.rnc"; private Schema piclSchema = null; private final PropertyMap properties; SchemaReceiverImpl(PropertyMap properties) { this.properties = SinglePropertyMap.newInstance(ValidateProperty.ERROR_HANDLER, properties.get(ValidateProperty.ERROR_HANDLER)); } public SchemaFuture installHandlers(XMLReader xr) throws SAXException { SchemaParser parser = new SchemaParser(properties, getPiclSchema()); xr.setContentHandler(parser); return parser; } private Schema getPiclSchema() throws SAXException { if (piclSchema == null) { String className = SchemaReceiverImpl.class.getName(); String resourceName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + PICL_SCHEMA; URL nrlSchemaUrl = getResource(resourceName); try { piclSchema = CompactSchemaReader.getInstance().createSchema(new InputSource(nrlSchemaUrl.toString()), properties); } catch (IncorrectSchemaException e) { throw new SAXException("unexpected internal error in RNC schema for picl"); } catch (IOException e) { throw new SAXException(e); } } return piclSchema; } private static URL getResource(String resourceName) { ClassLoader cl = SchemaReceiverImpl.class.getClassLoader(); // XXX see if we should borrow 1.2 code from Service if (cl == null) return ClassLoader.getSystemResource(resourceName); else return cl.getResource(resourceName); } } SelectedValueHandler.java000066400000000000000000000006471225366607500334610ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; import org.xml.sax.Locator; abstract class SelectedValueHandler { /** * If locator is non-null, it is a non-volatile location to be used for errors. * If locator is null, then the ErrorContext's location should be used. */ abstract void select(ErrorContext ec, Locator locator, Object value, String representation); void selectComplete(ErrorContext ec) { } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/SelectionHandler.java000066400000000000000000000003711225366607500327320ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface SelectionHandler { void selectElement(ErrorContext ec, Path path, PatternManager pm); void selectAttribute(ErrorContext ec, Path path, String value); void selectComplete(ErrorContext ec); } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/ValidatorImpl.java000066400000000000000000000160711225366607500322620ustar00rootroot00000000000000package com.thaiopensource.validate.picl; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.LocatorImpl; import org.xml.sax.ContentHandler; import org.xml.sax.Attributes; import org.xml.sax.DTDHandler; import org.xml.sax.SAXException; import org.xml.sax.Locator; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import java.util.Stack; class ValidatorImpl extends DefaultHandler implements Validator, Path, PatternManager, ErrorContext { private final Constraint constraint; private final Stack openElements = new Stack(); private final Stack valueHandlers = new Stack(); private final Stack activePatterns = new Stack(); private final AttributePath attributePath = new AttributePath(); private Locator locator; private final ErrorHandler eh; private final Localizer localizer = new Localizer(ValidatorImpl.class); private static class WrappedSAXException extends RuntimeException { final SAXException exception; WrappedSAXException(SAXException exception) { this.exception = exception; } } static class ActivePattern { final int rootDepth; final Pattern pattern; final SelectionHandler handler; ActivePattern(int rootDepth, Pattern pattern, SelectionHandler handler) { this.rootDepth = rootDepth; this.pattern = pattern; this.handler = handler; } } static class OpenElement { final String namespaceUri; final String localName; int nActivePatterns; int nValueHandlers; OpenElement(String namespaceUri, String localName) { this.namespaceUri = namespaceUri; this.localName = localName; } } class AttributePath implements Path { private Attributes atts; private int attIndex; void set(Attributes atts, int attIndex) { this.atts = atts; this.attIndex = attIndex; } public boolean isAttribute() { return true; } public int length() { return ValidatorImpl.this.length() + 1; } public String getLocalName(int i) { if (i == openElements.size()) return atts.getLocalName(attIndex); return ValidatorImpl.this.getLocalName(i); } public String getNamespaceUri(int i) { if (i == openElements.size()) return atts.getURI(attIndex); return ValidatorImpl.this.getNamespaceUri(i); } } ValidatorImpl(Constraint constraint, PropertyMap properties) { this.constraint = constraint; this.eh = properties.get(ValidateProperty.ERROR_HANDLER); } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return null; } public void reset() { openElements.setSize(0); valueHandlers.setSize(0); activePatterns.setSize(0); locator = null; } public int length() { return openElements.size(); } public String getLocalName(int i) { return ((OpenElement)openElements.elementAt(i)).localName; } public String getNamespaceUri(int i) { return ((OpenElement)openElements.elementAt(i)).namespaceUri; } public boolean isAttribute() { return false; } public void registerPattern(Pattern pattern, SelectionHandler handler) { // XXX what about case where it matches dot? activePatterns.push(new ActivePattern(openElements.size(), pattern, handler)); ((OpenElement)openElements.peek()).nActivePatterns += 1; } public void registerValueHandler(ValueHandler handler) { valueHandlers.push(handler); ((OpenElement)openElements.peek()).nValueHandlers += 1; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startDocument() throws SAXException { if (locator == null) { LocatorImpl tem = new LocatorImpl(); tem.setLineNumber(-1); tem.setColumnNumber(-1); locator = tem; } openElements.push(new OpenElement("", "#root")); try { constraint.activate(this); } catch (WrappedSAXException e) { throw e.exception; } } public void endDocument() throws SAXException { try { popOpenElement(); } catch (WrappedSAXException e) { throw e.exception; } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { openElements.push(new OpenElement(uri, localName)); for (int i = 0, len = valueHandlers.size(); i < len; i++) ((ValueHandler)valueHandlers.elementAt(i)).tag(this); for (int i = 0, len = activePatterns.size(); i < len; i++) { ActivePattern ap = (ActivePattern)activePatterns.elementAt(i); if (ap.pattern.matches(this, ap.rootDepth)) ap.handler.selectElement(this, this, this); } int nActivePatterns = activePatterns.size(); for (int i = 0, len = attributes.getLength(); i < len; i++) { attributePath.set(attributes, i); for (int j = 0; j < nActivePatterns; j++) { ActivePattern ap = (ActivePattern)activePatterns.elementAt(j); if (ap.pattern.matches(attributePath, ap.rootDepth)) ap.handler.selectAttribute(this, attributePath, attributes.getValue(i)); } } } catch (WrappedSAXException e) { throw e.exception; } } public void endElement(String uri, String localName, String qName) throws SAXException { try { popOpenElement(); } catch (WrappedSAXException e) { throw e.exception; } } public void characters(char ch[], int start, int length) throws SAXException { try { for (int i = 0, len = valueHandlers.size(); i < len; i++) ((ValueHandler)valueHandlers.elementAt(i)).characters(this, ch, start, length); } catch (WrappedSAXException e) { throw e.exception; } } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { characters(ch, start, length); } private void popOpenElement() { OpenElement top = (OpenElement)openElements.pop(); for (int i = 0; i < top.nValueHandlers; i++) { ValueHandler h = (ValueHandler)valueHandlers.pop(); h.valueComplete(this); } for (int i = 0; i < top.nActivePatterns; i++) { ActivePattern ap = (ActivePattern)activePatterns.pop(); ap.handler.selectComplete(this); } } public void error(Locator locator, String key) { if (locator == null) locator = this.locator; try { eh.error(new SAXParseException(localizer.message(key), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void error(Locator locator, String key, String arg) { if (locator == null) locator = this.locator; try { eh.error(new SAXParseException(localizer.message(key, arg), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public Locator saveLocator() { return new LocatorImpl(locator); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/ValueHandler.java000066400000000000000000000003161225366607500320600ustar00rootroot00000000000000package com.thaiopensource.validate.picl; interface ValueHandler { void characters(ErrorContext ec, char[] buf, int start, int len); void tag(ErrorContext ec); void valueComplete(ErrorContext ec); } ValueSelectionHandler.java000066400000000000000000000024111225366607500336450ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/piclpackage com.thaiopensource.validate.picl; import org.xml.sax.Locator; class ValueSelectionHandler implements SelectionHandler { private final SelectedValueHandler handler; ValueSelectionHandler(SelectedValueHandler handler) { this.handler = handler; } public void selectAttribute(ErrorContext ec, Path path, String value) { handler.select(ec, null, value, value); } static class ValueHandlerImpl implements ValueHandler { private final StringBuffer buf = new StringBuffer(); private final Locator locator; private final SelectedValueHandler handler; ValueHandlerImpl(SelectedValueHandler handler, Locator locator) { this.handler = handler; this.locator = locator; } public void characters(ErrorContext ec, char[] chars, int start, int len) { buf.append(chars, start, len); } public void tag(ErrorContext ec) { } public void valueComplete(ErrorContext ec) { String value = buf.toString(); handler.select(ec, locator, value, value); } } public void selectElement(ErrorContext ec, Path path, PatternManager pm) { pm.registerValueHandler(new ValueHandlerImpl(handler, ec.saveLocator())); } public void selectComplete(ErrorContext ec) { handler.selectComplete(ec); } } jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/resources/000077500000000000000000000000001225366607500306555ustar00rootroot00000000000000Messages.properties000066400000000000000000000006141225366607500344640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/resourcesexpected_step_connector=expected "/" or "//" or "|" expected_name_test=expected a name test expected_star_or_ncname=expected \"*\" or name following prefix unbound_prefix=undeclared prefix \"{0}\" illegal_char=unexpected character illegal_ncname="{0}" is not a valid XML name undefined_key=no key with value \"{0}\" duplicate_key=duplicate key with value \"{0}\" context={0}\n\ {1}>>>{2}<<<{3} jing-trang-20131210+dfsg+1/mod/picl/src/main/com/thaiopensource/validate/picl/resources/picl.rnc000066400000000000000000000023121225366607500323060ustar00rootroot00000000000000default namespace = "http://www.thaiopensource.com/validate/picl" start = element constraints { element constraint { attribute key { text }, attribute ref { text }? }* } # Planned eventually to be this. finalStart = element constraints { inherited, constraints } constraints = (key|ref|context)+ context = element context { select?, inherited, constraints } key = element key { attribute name { xsd:NCName }?, # names are scoped to the context attribute allowDuplicates { xsd:boolean }?, select, inherited, element field { select, inherited, convert?, dflt? }*, constraints? } ref = element ref { select, element not { select }*, refBody } refBody = attribute name { xsd:NCName }?, # names are scoped to same context inherited, element field { select, inherited, convert?, dflt? }+, element ref { refBody }? select = attribute select { path } convert = attribute convert { "detag" | "split" | "localFragmentId" } dflt = attribute default { "null" | "skip" } | attribute defaultValue { text } path = xsd:string inherited = attribute ns { xsd:anyURI }?, attribute datatypeLibrary { xsd:anyURI }? jing-trang-20131210+dfsg+1/mod/picl/test/000077500000000000000000000000001225366607500175615ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/picl/test/picltest.xml000066400000000000000000000015171225366607500221360ustar00rootroot00000000000000 forward xyzzy forward xyzzy forward xyzzy forward xyzy jing-trang-20131210+dfsg+1/mod/regex-gen/000077500000000000000000000000001225366607500175345ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/mod.xml000066400000000000000000000000731225366607500210350ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/regex-gen/src/000077500000000000000000000000001225366607500203235ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/000077500000000000000000000000001225366607500212475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/000077500000000000000000000000001225366607500220255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/000077500000000000000000000000001225366607500250555ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/000077500000000000000000000000001225366607500266705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/000077500000000000000000000000001225366607500274665ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/regex/000077500000000000000000000000001225366607500306005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/regex/java/000077500000000000000000000000001225366607500315215ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/regex/java/gen/000077500000000000000000000000001225366607500322725ustar00rootroot00000000000000CategoriesGen.java000066400000000000000000000112511225366607500355750ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/regex/java/genpackage com.thaiopensource.datatype.xsd.regex.java.gen; import java.io.File; import java.io.OutputStream; import java.io.FileOutputStream; import java.io.Writer; import java.io.BufferedWriter; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.List; import java.util.Vector; import java.util.Iterator; import java.util.Set; public class CategoriesGen { static public void main(String[] args) throws IOException { if (args.length != 3) { System.err.println("usage: " + CategoriesGen.class.getName() + " className srcDir UnicodeData.txt"); System.exit(2); } BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(args[2]))); CategoriesGen g = new CategoriesGen(); g.load(r); String className = args[0]; String srcDir = args[1]; int lastDot = className.lastIndexOf('.'); String pkg; if (lastDot < 0) pkg = null; else { pkg = className.substring(0, lastDot); className = className.substring(lastDot + 1); srcDir = srcDir + File.separator + pkg.replace('.', File.separatorChar); } String srcFile = srcDir + File.separator + className + ".java"; OutputStream stm = new FileOutputStream(srcFile); Writer w = new BufferedWriter(new OutputStreamWriter(stm)); String lineSep = System.getProperty("line.separator"); w.write("// This file was automatically generated by "); w.write(CategoriesGen.class.getName()); w.write(lineSep); if (pkg != null) w.write("package " + pkg + ";" + lineSep + lineSep); w.write("class " + className + " {" + lineSep); g.save(w, lineSep); w.write("}" + lineSep); w.close(); } void load(BufferedReader r) throws IOException { String lastCategory = null; int lastCode = 0; int firstCode = 0; for (;;) { String line = r.readLine(); if (line == null) break; int semi = line.indexOf(';'); if (semi != 5 && semi != 6) continue; int code = Integer.parseInt(line.substring(0, semi), 16); int semi2 = line.indexOf(';', semi + 1); String name = line.substring(semi, semi2); String category = line.substring(semi2 + 1, semi2 + 3); if (!category.equals(lastCategory) || !(lastCode + 1 == code || name.endsWith(", Last>"))) { if (lastCategory != null) add(firstCode, lastCode, lastCategory); lastCategory = category; firstCode = code; } lastCode = code; } if (lastCategory != null) add(firstCode, lastCode, lastCategory); } private final Map map = new HashMap(); static class Range { private final int lower; private final int upper; public Range(int lower, int upper) { this.lower = lower; this.upper = upper; } } void add(int firstCode, int lastCode, String category) { List list = (List)map.get(category); if (list == null) { list = new Vector(); map.put(category, list); } list.add(new Range(firstCode, lastCode)); } static private final String INDENT = " "; void save(Writer w, String lineSep) throws IOException { Set set = map.entrySet(); w.write(lineSep); w.write(INDENT); w.write("static final String CATEGORY_NAMES = \""); for (Iterator iter = set.iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry)iter.next(); w.write((String)entry.getKey()); } w.write("\";"); w.write(lineSep); w.write(lineSep); w.write(INDENT); w.write("static final int[][] CATEGORY_RANGES = {"); w.write(lineSep); for (Iterator iter = set.iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry)iter.next(); w.write(INDENT); w.write(INDENT); w.write('{'); w.write(lineSep); w.write(INDENT); w.write(INDENT); w.write(INDENT); w.write("// "); w.write((String)entry.getKey()); w.write(lineSep); List list = (List)entry.getValue(); for (int i = 0, len = list.size(); i < len; i++) { Range r = (Range)list.get(i); w.write(INDENT); w.write(INDENT); w.write(INDENT); w.write("0x"); w.write(Integer.toHexString(r.lower)); w.write(", "); w.write("0x"); w.write(Integer.toHexString(r.upper)); if (i + 1 != len) w.write(","); w.write(lineSep); } w.write(INDENT); w.write(INDENT); w.write('}'); if (iter.hasNext()) w.write(','); w.write(lineSep); } w.write(INDENT); w.write("};"); w.write(lineSep); } } NamingExceptionsGen.java000066400000000000000000000114751225366607500367730ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex-gen/src/main/com/thaiopensource/datatype/xsd/regex/java/genpackage com.thaiopensource.datatype.xsd.regex.java.gen; import com.thaiopensource.xml.util.Naming; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.List; import java.util.Vector; public class NamingExceptionsGen { static public void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("Usage: " + NamingExceptionsGen.class.toString() + " className srcDir"); System.exit(1); } String className = args[0]; String srcDir = args[1]; int lastDot = className.lastIndexOf('.'); String pkg; if (lastDot < 0) pkg = null; else { pkg = className.substring(0, lastDot); className = className.substring(lastDot + 1); srcDir = srcDir + File.separator + pkg.replace('.', File.separatorChar); } String srcFile = srcDir + File.separator + className + ".java"; OutputStream stm = new FileOutputStream(srcFile); Writer w = new BufferedWriter(new OutputStreamWriter(stm)); String lineSep = System.getProperty("line.separator"); w.write("// This file was automatically generated by "); w.write(NamingExceptionsGen.class.getName()); w.write(lineSep); if (pkg != null) w.write("package " + pkg + ";" + lineSep + lineSep); w.write("class " + className + " {" + lineSep); gen(true, w, lineSep); gen(false, w, lineSep); w.write("}" + lineSep); w.close(); } static private void gen(boolean isStart, Writer w, String lineSep) throws IOException { char[] buf = new char[1]; boolean excluding = false; char excludeMin = 0; char excludeMax = 0; List includeList = new Vector(); List excludeRangeList = new Vector(); for (int i = 0; i < 65536; i++) { char ch = (char)i; buf[0] = ch; String s = new String(buf); boolean isName = isStart ? Naming.isName(s) : Naming.isNmtoken(s); if (isName && excluding) { excludeRangeList.add(new Character(excludeMin)); excludeRangeList.add(new Character(excludeMax)); excluding = false; } if (isName != isApproxName(ch, isStart)) { if (isName) includeList.add(new Character(ch)); else { if (!excluding) { excluding = true; excludeMin = ch; } excludeMax = ch; } } } if (excluding) { excludeRangeList.add(new Character(excludeMin)); excludeRangeList.add(new Character(excludeMax)); } String prefix = isStart ? "NMSTRT" : "NMCHAR"; genList(prefix + "_INCLUDES", includeList, w, lineSep); genList(prefix + "_EXCLUDE_RANGES", excludeRangeList, w, lineSep); w.write(INDENT); w.write("static final String "); w.write(prefix); w.write("_CATEGORIES = \""); w.write(isStart ? NMSTRT_CATEGORIES : NMCHAR_CATEGORIES); w.write("\";"); w.write(lineSep); } static private final int CHARS_PER_LINE = 10; static private final String INDENT = " "; static private void genList(String varName, List includeList, Writer w, String lineSep) throws IOException { w.write(INDENT); w.write("static final String "); w.write(varName); w.write(" ="); w.write(lineSep); w.write(INDENT); w.write(INDENT); w.write('"'); for (int i = 0, len = includeList.size(); i < len; i++) { w.write("\\u"); w.write(hex(((Character)includeList.get(i)).charValue())); if (i % CHARS_PER_LINE == CHARS_PER_LINE - 1 && i + 1 != len) { w.write("\" +"); w.write(lineSep); w.write(INDENT); w.write(INDENT); w.write('"'); } } w.write("\";"); w.write(lineSep); } static private final String HEX_DIGITS = "0123456789ABCDEF"; static String hex(char c) { char[] buf = new char[4]; buf[0] = HEX_DIGITS.charAt((c >> 12) & 0xF); buf[1] = HEX_DIGITS.charAt((c >> 8) & 0xF); buf[2] = HEX_DIGITS.charAt((c >> 4) & 0xF); buf[3] = HEX_DIGITS.charAt(c & 0xF); return new String(buf); } static private final String NMSTRT_CATEGORIES = "LlLuLoLtNl"; static private final String NMCHAR_CATEGORIES = NMSTRT_CATEGORIES + "McMeMnLmNd"; static private boolean isApproxName(char c, boolean isStart) { switch (Character.getType(c)) { 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 return true; case Character.COMBINING_SPACING_MARK: // Mc case Character.ENCLOSING_MARK: // Me case Character.NON_SPACING_MARK: // Mn case Character.MODIFIER_LETTER: // Lm case Character.DECIMAL_DIGIT_NUMBER: // Nd return !isStart; } return false; } } jing-trang-20131210+dfsg+1/mod/regex/000077500000000000000000000000001225366607500167655ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/mod.xml000066400000000000000000000061161225366607500202720ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/regex/src/000077500000000000000000000000001225366607500175545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/000077500000000000000000000000001225366607500205005ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/000077500000000000000000000000001225366607500212565ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/000077500000000000000000000000001225366607500243065ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/000077500000000000000000000000001225366607500261215ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/000077500000000000000000000000001225366607500267175ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/000077500000000000000000000000001225366607500300315ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/Regex.java000066400000000000000000000006601225366607500317500ustar00rootroot00000000000000package com.thaiopensource.datatype.xsd.regex; /** * A regular expression that can be matched against a string. * @see RegexEngine */ public interface Regex { /** * Tests whether this regular expression matches a string. * * @param str the String to be tested * @return true if str matches this regular expression, * false otherwise */ boolean matches(String str); } jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/RegexEngine.java000066400000000000000000000011541225366607500330750ustar00rootroot00000000000000package com.thaiopensource.datatype.xsd.regex; /** * A provider of a regular expression matching capability. */ public interface RegexEngine { /** * Compiles a string containing a regular expression into a Regex object. * The Regex object can be used to test whether a string matches the regular * expression. * * @param str a String containing a regular expression * @return a Regex for str * @throws RegexSyntaxException if str is not a valid regular expression */ Regex compile(String str) throws RegexSyntaxException; } RegexSyntaxException.java000066400000000000000000000016231225366607500347570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regexpackage com.thaiopensource.datatype.xsd.regex; /** * Thrown when an syntactically incorrect regular expression is detected. */ public class RegexSyntaxException extends Exception { private final int position; /** * Represents an unknown position within a string containing a regular expression. */ static public final int UNKNOWN_POSITION = -1; public RegexSyntaxException(String detail) { this(detail, UNKNOWN_POSITION); } public RegexSyntaxException(String detail, int position) { super(detail); this.position = position; } /** * Returns the index into the regular expression where the error was detected * or UNKNOWN_POSITION if this is unknown. * * @return the index into the regular expression where the error was detected, * or UNKNOWNN_POSITION if this is unknown */ public int getPosition() { return position; } } jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/java/000077500000000000000000000000001225366607500307525ustar00rootroot00000000000000RegexEngineImpl.java000066400000000000000000000017101225366607500345570ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/javapackage com.thaiopensource.datatype.xsd.regex.java; import com.thaiopensource.datatype.xsd.regex.Regex; import com.thaiopensource.datatype.xsd.regex.RegexEngine; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import java.util.regex.Pattern; /** * An implementation of RegexEngine using the JDK >= 1.4 java.util.regex * package. */ public class RegexEngineImpl implements RegexEngine { public RegexEngineImpl() { // Force a linkage error on instantiation if JDK >= 1.4 is not available. boolean b = RegexFeatures.SURROGATES_DIRECT; } public Regex compile(String str) throws RegexSyntaxException { // Don't catch PatternSyntaxException // The Translator should detect all syntax errors final Pattern pattern = Pattern.compile(Translator.translate(str)); return new Regex() { public boolean matches(String str) { return pattern.matcher(str).matches(); } }; } } RegexFeatures.java000066400000000000000000000010421225366607500343040ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/javapackage com.thaiopensource.datatype.xsd.regex.java; import com.thaiopensource.util.Utf16; import java.util.regex.Pattern; class RegexFeatures { static private final int EXAMPLE_NON_BMP_CHAR = 0x10000; static private final String EXAMPLE_SURROGATE_PAIR = new String(new char[] { Utf16.surrogate1(EXAMPLE_NON_BMP_CHAR), Utf16.surrogate2(EXAMPLE_NON_BMP_CHAR) }); static final boolean SURROGATES_DIRECT = Pattern.compile("[^x]").matcher(EXAMPLE_SURROGATE_PAIR).matches(); private RegexFeatures() { } } Translator.java000066400000000000000000001116711225366607500336760ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/javapackage com.thaiopensource.datatype.xsd.regex.java; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.Utf16; import java.math.BigDecimal; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Vector; /** * Translates XML Schema regexes into java.util.regex regexes. * * @see java.util.regex.Pattern * @see XML Schema Part 2 */ public class Translator { private final String regExp; private int pos = 0; private final int length; private char curChar; private boolean eos = false; private final StringBuffer result = new StringBuffer(); static private final boolean surrogatesDirect = RegexFeatures.SURROGATES_DIRECT; static private final String categories = "LMNPZSC"; static private final CharClass[] categoryCharClasses = new CharClass[categories.length()]; static private final String subCategories = "LuLlLtLmLoMnMcMeNdNlNoPcPdPsPePiPfPoZsZlZpSmScSkSoCcCfCoCn"; static private final CharClass[] subCategoryCharClasses = new CharClass[subCategories.length() / 2]; static private final int NONBMP_MIN = 0x10000; static private final int NONBMP_MAX = 0x10FFFF; static private final char SURROGATE2_MIN = '\uDC00'; static private final char SURROGATE2_MAX = '\uDFFF'; static final Localizer localizer = new Localizer(Translator.class); static private final String[] blockNames = { "BasicLatin", "Latin-1Supplement", "LatinExtended-A", "LatinExtended-B", "IPAExtensions", "SpacingModifierLetters", "CombiningDiacriticalMarks", "Greek", "Cyrillic", "Armenian", "Hebrew", "Arabic", "Syriac", "Thaana", "Devanagari", "Bengali", "Gurmukhi", "Gujarati", "Oriya", "Tamil", "Telugu", "Kannada", "Malayalam", "Sinhala", "Thai", "Lao", "Tibetan", "Myanmar", "Georgian", "HangulJamo", "Ethiopic", "Cherokee", "UnifiedCanadianAboriginalSyllabics", "Ogham", "Runic", "Khmer", "Mongolian", "LatinExtendedAdditional", "GreekExtended", "GeneralPunctuation", "SuperscriptsandSubscripts", "CurrencySymbols", "CombiningMarksforSymbols", "LetterlikeSymbols", "NumberForms", "Arrows", "MathematicalOperators", "MiscellaneousTechnical", "ControlPictures", "OpticalCharacterRecognition", "EnclosedAlphanumerics", "BoxDrawing", "BlockElements", "GeometricShapes", "MiscellaneousSymbols", "Dingbats", "BraillePatterns", "CJKRadicalsSupplement", "KangxiRadicals", "IdeographicDescriptionCharacters", "CJKSymbolsandPunctuation", "Hiragana", "Katakana", "Bopomofo", "HangulCompatibilityJamo", "Kanbun", "BopomofoExtended", "EnclosedCJKLettersandMonths", "CJKCompatibility", "CJKUnifiedIdeographsExtensionA", "CJKUnifiedIdeographs", "YiSyllables", "YiRadicals", "HangulSyllables", // surrogates excluded because there are never any *characters* with codes in surrogate range // "PrivateUse", excluded because 3.1 adds non-BMP ranges "CJKCompatibilityIdeographs", "AlphabeticPresentationForms", "ArabicPresentationForms-A", "CombiningHalfMarks", "CJKCompatibilityForms", "SmallFormVariants", "ArabicPresentationForms-B", "Specials", "HalfwidthandFullwidthForms", "Specials" }; /** * Names of blocks including ranges outside the BMP. */ static private final String[] specialBlockNames = { "OldItalic", "Gothic", "Deseret", "ByzantineMusicalSymbols", "MusicalSymbols", "MathematicalAlphanumericSymbols", "CJKUnifiedIdeographsExtensionB", "CJKCompatibilityIdeographsSupplement", "Tags", "PrivateUse" }; /** * CharClass for each block name in specialBlockNames. */ static private final CharClass[] specialBlockCharClasses = { new CharRange(0x10300, 0x1032F), new CharRange(0x10330, 0x1034F), new CharRange(0x10400, 0x1044F), new CharRange(0x1D000, 0x1D0FF), new CharRange(0x1D100, 0x1D1FF), new CharRange(0x1D400, 0x1D7FF), new CharRange(0x20000, 0x2A6D6), new CharRange(0x2F800, 0x2FA1F), new CharRange(0xE0000, 0xE007F), new Union(new CharClass[] { new CharRange(0xE000, 0xF8FF), new CharRange(0xF0000, 0xFFFFD), new CharRange(0x100000, 0x10FFFD) }) }; static private final CharClass DOT = new Complement(new Union(new CharClass[] { new SingleChar('\n'), new SingleChar('\r') })); static private final CharClass ESC_d = new Property("Nd"); static private final CharClass ESC_D = new Complement(ESC_d); static private final CharClass ESC_W = new Union(new CharClass[] {new Property("P"), new Property("Z"), new Property("C")}); static private final CharClass ESC_w = new Complement(ESC_W); static private final CharClass ESC_s = new Union(new CharClass[] { new SingleChar(' '), new SingleChar('\n'), new SingleChar('\r'), new SingleChar('\t') }); static private final CharClass ESC_S = new Complement(ESC_s); static private final CharClass ESC_i = makeCharClass(NamingExceptions.NMSTRT_CATEGORIES, NamingExceptions.NMSTRT_INCLUDES, NamingExceptions.NMSTRT_EXCLUDE_RANGES); static private final CharClass ESC_I = new Complement(ESC_i); static private final CharClass ESC_c = makeCharClass(NamingExceptions.NMCHAR_CATEGORIES, NamingExceptions.NMCHAR_INCLUDES, NamingExceptions.NMCHAR_EXCLUDE_RANGES); static private final CharClass ESC_C = new Complement(ESC_c); static private final char EOS = '\0'; private Translator(String regExp) { this.regExp = regExp; this.length = regExp.length(); advance(); } /** * Translates a regular expression in the syntax of XML Schemas Part 2 into a regular * expression in the syntax of java.util.regex.Pattern. The translation * assumes that the string to be matched against the regex uses surrogate pairs correctly. * If the string comes from XML content, a conforming XML parser will automatically * check this; if the string comes from elsewhere, it may be necessary to check * surrogate usage before matching. * * @param regexp a String containing a regular expression in the syntax of XML Schemas Part 2 * @return a String containing a regular expression in the syntax of java.util.regex.Pattern * @throws RegexSyntaxException if regexp is not a regular expression in the * syntax of XML Schemas Part 2 * @see java.util.regex.Pattern * @see XML Schema Part 2 */ static public String translate(String regexp) throws RegexSyntaxException { Translator tr = new Translator(regexp); tr.translateTop(); return tr.result.toString(); } private void advance() { if (pos < length) curChar = regExp.charAt(pos++); else { pos++; curChar = EOS; eos = true; } } private void translateTop() throws RegexSyntaxException { translateRegExp(); if (!eos) throw makeException("expected_eos"); } private void translateRegExp() throws RegexSyntaxException { translateBranch(); while (curChar == '|') { copyCurChar(); translateBranch(); } } private void translateBranch() throws RegexSyntaxException { while (translateAtom()) translateQuantifier(); } private void translateQuantifier() throws RegexSyntaxException { switch (curChar) { case '*': case '?': case '+': copyCurChar(); return; case '{': copyCurChar(); translateQuantity(); expect('}'); copyCurChar(); } } private void translateQuantity() throws RegexSyntaxException { String lower = parseQuantExact(); int lowerValue = -1; try { lowerValue = Integer.parseInt(lower); result.append(lower); } catch (NumberFormatException e) { // JDK 1.4 cannot handle ranges bigger than this result.append(Integer.MAX_VALUE); } if (curChar == ',') { copyCurChar(); if (curChar != '}') { String upper = parseQuantExact(); try { int upperValue = Integer.parseInt(upper); result.append(upper); if (lowerValue < 0 || upperValue < lowerValue) throw makeException("invalid_quantity_range"); } catch (NumberFormatException e) { result.append(Integer.MAX_VALUE); if (lowerValue < 0 && new BigDecimal(lower).compareTo(new BigDecimal(upper)) > 0) throw makeException("invalid_quantity_range"); } } } } private String parseQuantExact() throws RegexSyntaxException { StringBuffer buf = new StringBuffer(); do { if ("0123456789".indexOf(curChar) < 0) throw makeException("expected_digit"); buf.append(curChar); advance(); } while (curChar != ',' && curChar != '}'); return buf.toString(); } private void copyCurChar() { result.append(curChar); advance(); } static final int NONE = -1; static final int SOME = 0; static final int ALL = 1; static final String SURROGATES1_CLASS = "[\uD800-\uDBFF]"; static final String SURROGATES2_CLASS = "[\uDC00-\uDFFF]"; static final String NOT_ALLOWED_CLASS = "[\u0000&&[^\u0000]]"; static final class Range implements Comparable { private final int min; private final int max; Range(int min, int max) { this.min = min; this.max = max; } int getMin() { return min; } int getMax() { return max; } public int compareTo(Object o) { Range other = (Range)o; if (this.min < other.min) return -1; if (this.min > other.min) return 1; if (this.max > other.max) return -1; if (this.max < other.max) return 1; return 0; } } static abstract class CharClass { private final int containsBmp; // if it contains ALL and containsBmp != NONE, then the generated class for containsBmp must // contain all the high surrogates private final int containsNonBmp; protected CharClass(int containsBmp, int containsNonBmp) { this.containsBmp = containsBmp; this.containsNonBmp = containsNonBmp; } int getContainsBmp() { return containsBmp; } int getContainsNonBmp() { return containsNonBmp; } final void output(StringBuffer buf) { if (surrogatesDirect) outputDirect(buf); else outputMungeSurrogates(buf); } final void outputMungeSurrogates(StringBuffer buf) { switch (containsNonBmp) { case NONE: if (containsBmp == NONE) buf.append(NOT_ALLOWED_CLASS); else outputDirect(buf); break; case ALL: buf.append('('); if (containsBmp == NONE) { buf.append(SURROGATES1_CLASS); buf.append(SURROGATES2_CLASS); } else { outputDirect(buf); buf.append(SURROGATES2_CLASS); buf.append('?'); } buf.append(')'); break; case SOME: buf.append('('); boolean needSep = false; if (containsBmp != NONE) { needSep = true; outputDirect(buf); } List ranges = new Vector(); addNonBmpRanges(ranges); sortRangeList(ranges); String hi = highSurrogateRanges(ranges); if (hi.length() > 0) { if (needSep) buf.append('|'); else needSep = true; buf.append('['); for (int i = 0, len = hi.length(); i < len; i += 2) { char min = hi.charAt(i); char max = hi.charAt(i + 1); if (min == max) buf.append(min); else { buf.append(min); buf.append('-'); buf.append(max); } } buf.append(']'); buf.append(SURROGATES2_CLASS); } String lo = lowSurrogateRanges(ranges); for (int i = 0, len = lo.length(); i < len; i += 3) { if (needSep) buf.append('|'); else needSep = true; buf.append(lo.charAt(i)); char min = lo.charAt(i + 1); char max = lo.charAt(i + 2); if (min == max && (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i))) buf.append(min); else { buf.append('['); for (;;) { if (min == max) buf.append(min); else { buf.append(min); buf.append('-'); buf.append(max); } if (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i)) break; i += 3; min = lo.charAt(i + 1); max = lo.charAt(i + 2); } buf.append(']'); } } if (!needSep) buf.append(NOT_ALLOWED_CLASS); buf.append(')'); break; } } static String highSurrogateRanges(List ranges) { StringBuffer highRanges = new StringBuffer(); for (int i = 0, len = ranges.size(); i < len; i++) { Range r = (Range)ranges.get(i); char min1 = Utf16.surrogate1(r.getMin()); char min2 = Utf16.surrogate2(r.getMin()); char max1 = Utf16.surrogate1(r.getMax()); char max2 = Utf16.surrogate2(r.getMax()); if (min2 != SURROGATE2_MIN) min1++; if (max2 != SURROGATE2_MAX) max1--; if (max1 >= min1) { highRanges.append(min1); highRanges.append(max1); } } return highRanges.toString(); } static String lowSurrogateRanges(List ranges) { StringBuffer lowRanges = new StringBuffer(); for (int i = 0, len = ranges.size(); i < len; i++) { Range r = (Range)ranges.get(i); char min1 = Utf16.surrogate1(r.getMin()); char min2 = Utf16.surrogate2(r.getMin()); char max1 = Utf16.surrogate1(r.getMax()); char max2 = Utf16.surrogate2(r.getMax()); if (min1 == max1) { if (min2 != SURROGATE2_MIN || max2 != SURROGATE2_MAX) { lowRanges.append(min1); lowRanges.append(min2); lowRanges.append(max2); } } else { if (min2 != SURROGATE2_MIN) { lowRanges.append(min1); lowRanges.append(min2); lowRanges.append(SURROGATE2_MAX); } if (max2 != SURROGATE2_MAX) { lowRanges.append(max1); lowRanges.append(SURROGATE2_MIN); lowRanges.append(max2); } } } return lowRanges.toString(); } abstract void outputDirect(StringBuffer buf); abstract void outputComplementDirect(StringBuffer buf); int singleChar() { return -1; } void addNonBmpRanges(List ranges) { } static void sortRangeList(List ranges) { Collections.sort(ranges); int toIndex = 0; int fromIndex = 0; int len = ranges.size(); while (fromIndex < len) { Range r = (Range)ranges.get(fromIndex); int min = r.getMin(); int max = r.getMax(); while (++fromIndex < len) { Range r2 = (Range)ranges.get(fromIndex); if (r2.getMin() > max + 1) break; if (r2.getMax() > max) max = r2.getMax(); } if (max != r.getMax()) r = new Range(min, max); ranges.set(toIndex++, r); } while (len > toIndex) ranges.remove(--len); } } static abstract class SimpleCharClass extends CharClass { SimpleCharClass(int containsBmp, int containsNonBmp) { super(containsBmp, containsNonBmp); } void outputDirect(StringBuffer buf) { buf.append('['); inClassOutputDirect(buf); buf.append(']'); } // must not call if containsBmp == ALL && !surrogatesDirect void outputComplementDirect(StringBuffer buf) { if (!surrogatesDirect && getContainsBmp() == NONE) buf.append("[\u0000-\uFFFF]"); else { buf.append("[^"); inClassOutputDirect(buf); buf.append(']'); } } abstract void inClassOutputDirect(StringBuffer buf); static void outputWide(StringBuffer buf, int c) { buf.append(Utf16.surrogate1(c)); buf.append(Utf16.surrogate2(c)); } } static class SingleChar extends SimpleCharClass { private final char c; SingleChar(char c) { super(SOME, NONE); this.c = c; } int singleChar() { return c; } void outputDirect(StringBuffer buf) { inClassOutputDirect(buf); } void inClassOutputDirect(StringBuffer buf) { if (isJavaMetaChar(c)) buf.append('\\'); buf.append(c); } } static class WideSingleChar extends SimpleCharClass { private final int c; WideSingleChar(int c) { super(NONE, SOME); this.c = c; } void inClassOutputDirect(StringBuffer buf) { if (!surrogatesDirect) throw new RuntimeException("BMP output botch"); outputWide(buf, c); } int singleChar() { return c; } void addNonBmpRanges(List ranges) { ranges.add(new Range(c, c)); } } static class CharRange extends SimpleCharClass { private final int lower; private final int upper; CharRange(int lower, int upper) { super(lower < NONBMP_MIN ? SOME : NONE, // don't use ALL here, because that requires that the BMP class contains high surrogates upper >= NONBMP_MIN ? SOME : NONE); this.lower = lower; this.upper = upper; } void inClassOutputDirect(StringBuffer buf) { if (lower < NONBMP_MIN) { if (isJavaMetaChar((char)lower)) buf.append('\\'); buf.append((char)lower); } else if (surrogatesDirect) outputWide(buf, lower); else throw new RuntimeException("BMP output botch"); buf.append('-'); if (upper < NONBMP_MIN) { if (isJavaMetaChar((char)upper)) buf.append('\\'); buf.append((char)upper); } else if (surrogatesDirect) outputWide(buf, upper); else buf.append('\uFFFF'); } void addNonBmpRanges(List ranges) { if (upper >= NONBMP_MIN) ranges.add(new Range(lower < NONBMP_MIN ? NONBMP_MIN : lower, upper)); } } static class Property extends SimpleCharClass { private final String name; Property(String name) { super(SOME, NONE); this.name = name; } void outputDirect(StringBuffer buf) { inClassOutputDirect(buf); } void inClassOutputDirect(StringBuffer buf) { buf.append("\\p{"); buf.append(name); buf.append('}'); } void outputComplementDirect(StringBuffer buf) { buf.append("\\P{"); buf.append(name); buf.append('}'); } } static class Subtraction extends CharClass { private final CharClass cc1; private final CharClass cc2; Subtraction(CharClass cc1, CharClass cc2) { // min corresponds to intersection // complement corresponds to negation super(Math.min(cc1.getContainsBmp(), -cc2.getContainsBmp()), Math.min(cc1.getContainsNonBmp(), -cc2.getContainsNonBmp())); this.cc1 = cc1; this.cc2 = cc2; } void outputDirect(StringBuffer buf) { buf.append('['); cc1.outputDirect(buf); buf.append("&&"); cc2.outputComplementDirect(buf); buf.append(']'); } void outputComplementDirect(StringBuffer buf) { buf.append('['); cc1.outputComplementDirect(buf); cc2.outputDirect(buf); buf.append(']'); } void addNonBmpRanges(List ranges) { List posList = new Vector(); cc1.addNonBmpRanges(posList); List negList = new Vector(); cc2.addNonBmpRanges(negList); sortRangeList(posList); sortRangeList(negList); Iterator negIter = negList.iterator(); Range negRange; if (negIter.hasNext()) negRange = (Range)negIter.next(); else negRange = null; for (int i = 0, len = posList.size(); i < len; i++) { Range posRange = (Range)posList.get(i); while (negRange != null && negRange.getMax() < posRange.getMin()) { if (negIter.hasNext()) negRange = (Range)negIter.next(); else negRange = null; } // if negRange != null, negRange.max >= posRange.min int min = posRange.getMin(); while (negRange != null && negRange.getMin() <= posRange.getMax()) { if (min < negRange.getMin()) { ranges.add(new Range(min, negRange.getMin() - 1)); } min = negRange.getMax() + 1; if (min > posRange.getMax()) break; if (negIter.hasNext()) negRange = (Range)negIter.next(); else negRange = null; } if (min <= posRange.getMax()) ranges.add(new Range(min, posRange.getMax())); } } } static class Union extends CharClass { private final List members; Union(CharClass[] v) { this(toList(v)); } static private List toList(CharClass[] v) { List members = new Vector(); for (int i = 0; i < v.length; i++) members.add(v[i]); return members; } Union(List members) { super(computeContainsBmp(members), computeContainsNonBmp(members)); this.members = members; } void outputDirect(StringBuffer buf) { buf.append('['); for (int i = 0, len = members.size(); i < len; i++) { CharClass cc = (CharClass)members.get(i); if (surrogatesDirect || cc.getContainsBmp() != NONE) { if (cc instanceof SimpleCharClass) ((SimpleCharClass)cc).inClassOutputDirect(buf); else cc.outputDirect(buf); } } buf.append(']'); } void outputComplementDirect(StringBuffer buf) { boolean first = true; int len = members.size(); for (int i = 0; i < len; i++) { CharClass cc = (CharClass)members.get(i); if ((surrogatesDirect || cc.getContainsBmp() != NONE) && cc instanceof SimpleCharClass) { if (first) { buf.append("[^"); first = false; } ((SimpleCharClass)cc).inClassOutputDirect(buf); } } for (int i = 0; i < len; i++) { CharClass cc = (CharClass)members.get(i); if ((surrogatesDirect || cc.getContainsBmp() != NONE) && !(cc instanceof SimpleCharClass)) { if (first) { buf.append('['); first = false; } else buf.append("&&"); // can't have any members that are ALL, because that would make this ALL, which violates // the precondition for outputComplementDirect cc.outputComplementDirect(buf); } } if (first) // all members are NONE, so this is NONE, so complement is everything buf.append("[\u0000-\uFFFF]"); else buf.append(']'); } void addNonBmpRanges(List ranges) { for (int i = 0, len = members.size(); i < len; i++) ((CharClass)members.get(i)).addNonBmpRanges(ranges); } private static int computeContainsBmp(List members) { int ret = NONE; for (int i = 0, len = members.size(); i < len; i++) ret = Math.max(ret, ((CharClass)members.get(i)).getContainsBmp()); return ret; } private static int computeContainsNonBmp(List members) { int ret = NONE; for (int i = 0, len = members.size(); i < len; i++) ret = Math.max(ret, ((CharClass)members.get(i)).getContainsNonBmp()); return ret; } } static class Complement extends CharClass { private final CharClass cc; Complement(CharClass cc) { super(-cc.getContainsBmp(), -cc.getContainsNonBmp()); this.cc = cc; } void outputDirect(StringBuffer buf) { cc.outputComplementDirect(buf); } void outputComplementDirect(StringBuffer buf) { cc.outputDirect(buf); } void addNonBmpRanges(List ranges) { List tem = new Vector(); cc.addNonBmpRanges(tem); sortRangeList(tem); int c = NONBMP_MIN; for (int i = 0, len = tem.size(); i < len; i++) { Range r = (Range)tem.get(i); if (r.getMin() > c) ranges.add(new Range(c, r.getMin() - 1)); c = r.getMax() + 1; } if (c != NONBMP_MAX + 1) ranges.add(new Range(c, NONBMP_MAX)); } } private boolean translateAtom() throws RegexSyntaxException { switch (curChar) { case EOS: if (!eos) break; // fall through case '?': case '*': case '+': case ')': case '{': case '}': case '|': case ']': return false; case '(': copyCurChar(); translateRegExp(); expect(')'); copyCurChar(); return true; case '\\': advance(); parseEsc().output(result); return true; case '[': advance(); parseCharClassExpr().output(result); return true; case '.': DOT.output(result); advance(); return true; case '$': case '^': result.append('\\'); break; } copyCurChar(); return true; } static private CharClass makeCharClass(String categories, String includes, String excludeRanges) { List includeList = new Vector(); for (int i = 0, len = categories.length(); i < len; i += 2) includeList.add(new Property(categories.substring(i, i + 2))); for (int i = 0, len = includes.length(); i < len; i++) { int j = i + 1; for (; j < len && includes.charAt(j) - includes.charAt(i) == j - i; j++) ; --j; if (i == j - 1) --j; if (i == j) includeList.add(new SingleChar(includes.charAt(i))); else includeList.add(new CharRange(includes.charAt(i), includes.charAt(j))); i = j; } List excludeList = new Vector(); for (int i = 0, len = excludeRanges.length(); i < len; i += 2) { char min = excludeRanges.charAt(i); char max = excludeRanges.charAt(i + 1); if (min == max) excludeList.add(new SingleChar(min)); else if (min == max - 1) { excludeList.add(new SingleChar(min)); excludeList.add(new SingleChar(max)); } else excludeList.add(new CharRange(min, max)); } if (surrogatesDirect) excludeList.add(new CharRange(NONBMP_MIN, NONBMP_MAX)); // Unicode 4.0 adds some non-BMP letters return new Subtraction(new Union(includeList), new Union(excludeList)); } private CharClass parseEsc() throws RegexSyntaxException { switch (curChar) { case 'n': advance(); return new SingleChar('\n'); case 'r': advance(); return new SingleChar('\r'); case 't': advance(); return new SingleChar('\t'); case '\\': case '|': case '.': case '-': case '^': case '?': case '*': case '+': case '(': case ')': case '{': case '}': case '[': case ']': break; case 's': advance(); return ESC_s; case 'S': advance(); return ESC_S; case 'i': advance(); return ESC_i; case 'I': advance(); return ESC_I; case 'c': advance(); return ESC_c; case 'C': advance(); return ESC_C; case 'd': advance(); return ESC_d; case 'D': advance(); return ESC_D; case 'w': advance(); return ESC_w; case 'W': advance(); return ESC_W; case 'p': advance(); return parseProp(); case 'P': advance(); return new Complement(parseProp()); default: throw makeException("bad_escape"); } CharClass tem = new SingleChar(curChar); advance(); return tem; } private CharClass parseProp() throws RegexSyntaxException { expect('{'); int start = pos; for (;;) { advance(); if (curChar == '}') break; if (!isAsciiAlnum(curChar) && curChar != '-') expect('}'); } String propertyName = regExp.substring(start, pos - 1); advance(); switch (propertyName.length()) { case 0: throw makeException("empty_property_name"); case 2: int sci = subCategories.indexOf(propertyName); if (sci < 0 || sci % 2 == 1) throw makeException("bad_category"); return getSubCategoryCharClass(sci / 2); case 1: int ci = categories.indexOf(propertyName.charAt(0)); if (ci < 0) throw makeException("bad_category", propertyName); return getCategoryCharClass(ci); default: if (!propertyName.startsWith("Is")) break; String blockName = propertyName.substring(2); for (int i = 0; i < specialBlockNames.length; i++) if (blockName.equals(specialBlockNames[i])) return specialBlockCharClasses[i]; if (!isBlock(blockName)) throw makeException("bad_block_name", blockName); return new Property( "In" + blockName); } throw makeException("bad_property_name", propertyName); } static private boolean isBlock(String name) { for (int i = 0; i < blockNames.length; i++) if (name.equals(blockNames[i])) return true; return false; } static private boolean isAsciiAlnum(char c) { if ('a' <= c && c <= 'z') return true; if ('A' <= c && c <= 'Z') return true; if ('0' <= c && c <= '9') return true; return false; } private void expect(char c) throws RegexSyntaxException { if (curChar != c) throw makeException("expected", new String(new char[]{c})); } private CharClass parseCharClassExpr() throws RegexSyntaxException { boolean compl; if (curChar == '^') { advance(); compl = true; } else compl = false; List members = new Vector(); do { CharClass lower = parseCharClassEscOrXmlChar(); members.add(lower); if (curChar == '-') { advance(); if (curChar == '[') break; CharClass upper = parseCharClassEscOrXmlChar(); if (lower.singleChar() < 0 || upper.singleChar() < 0) throw makeException("multi_range"); if (lower.singleChar() > upper.singleChar()) throw makeException("invalid_range"); members.set(members.size() - 1, new CharRange(lower.singleChar(), upper.singleChar())); if (curChar == '-') { advance(); expect('['); break; } } } while (curChar != ']'); CharClass result; if (members.size() == 1) result = (CharClass)members.get(0); else result = new Union(members); if (compl) result = new Complement(result); if (curChar == '[') { advance(); result = new Subtraction(result, parseCharClassExpr()); expect(']'); } advance(); return result; } private CharClass parseCharClassEscOrXmlChar() throws RegexSyntaxException { switch (curChar) { case EOS: if (eos) expect(']'); break; case '\\': advance(); return parseEsc(); case '[': case ']': case '-': throw makeException("should_quote", new String(new char[]{curChar})); } CharClass tem; if (Utf16.isSurrogate(curChar)) { if (!Utf16.isSurrogate1(curChar)) throw makeException("invalid_surrogate"); char c1 = curChar; advance(); if (!Utf16.isSurrogate2(curChar)) throw makeException("invalid_surrogate"); tem = new WideSingleChar(Utf16.scalarValue(c1, curChar)); } else tem = new SingleChar(curChar); advance(); return tem; } private RegexSyntaxException makeException(String key) { return new RegexSyntaxException(localizer.message(key), pos - 1); } private RegexSyntaxException makeException(String key, String arg) { return new RegexSyntaxException(localizer.message(key, arg), pos - 1); } static private boolean isJavaMetaChar(char c) { switch (c) { case '\\': case '^': case '?': case '*': case '+': case '(': case ')': case '{': case '}': case '|': case '[': case ']': case '-': case '&': case '$': case '.': return true; } return false; } static private synchronized CharClass getCategoryCharClass(int ci) { if (categoryCharClasses[ci] == null) categoryCharClasses[ci] = computeCategoryCharClass(categories.charAt(ci)); return categoryCharClasses[ci]; } static private synchronized CharClass getSubCategoryCharClass(int sci) { if (subCategoryCharClasses[sci] == null) subCategoryCharClasses[sci] = computeSubCategoryCharClass(subCategories.substring(sci * 2, (sci + 1) * 2)); return subCategoryCharClasses[sci]; } static private final char UNICODE_3_1_ADD_Lu = '\u03F4'; // added in 3.1 static private final char UNICODE_3_1_ADD_Ll = '\u03F5'; // added in 3.1 // 3 characters changed from No to Nl between 3.0 and 3.1 static private final char UNICODE_3_1_CHANGE_No_to_Nl_MIN = '\u16EE'; static private final char UNICODE_3_1_CHANGE_No_to_Nl_MAX = '\u16F0'; static private final String CATEGORY_Pi = "\u00AB\u2018\u201B\u201C\u201F\u2039"; // Java doesn't know about category Pi static private final String CATEGORY_Pf = "\u00BB\u2019\u201D\u203A"; // Java doesn't know about category Pf static private CharClass computeCategoryCharClass(char code) { List classes = new Vector(); classes.add(new Property(new String(new char[] { code }))); if (!surrogatesDirect) { for (int ci = Categories.CATEGORY_NAMES.indexOf(code); ci >= 0; ci = Categories.CATEGORY_NAMES.indexOf(code, ci + 1)) { int[] addRanges = Categories.CATEGORY_RANGES[ci/2]; for (int i = 0; i < addRanges.length; i += 2) classes.add(new CharRange(addRanges[i], addRanges[i + 1])); } } if (code == 'P') classes.add(makeCharClass(CATEGORY_Pi + CATEGORY_Pf)); if (code == 'L') { classes.add(new SingleChar(UNICODE_3_1_ADD_Ll)); classes.add(new SingleChar(UNICODE_3_1_ADD_Lu)); } if (code == 'C') classes.add(computeSubCategoryCharClass("Cn")); // JDK 1.4 leaves Cn out of C? if (classes.size() == 1) return (CharClass)classes.get(0); return new Union(classes); } static private CharClass computeSubCategoryCharClass(String name) { if (name.equals("Pi")) return makeCharClass(CATEGORY_Pi); if (name.equals("Pf")) return makeCharClass(CATEGORY_Pf); CharClass base = new Property(name); if (name.equals("Cn")) { // Unassigned List assignedRanges = new Vector(); assignedRanges.add(new SingleChar(UNICODE_3_1_ADD_Lu)); assignedRanges.add(new SingleChar(UNICODE_3_1_ADD_Ll)); if (!surrogatesDirect) { for (int i = 0; i < Categories.CATEGORY_RANGES.length; i++) for (int j = 0; j < Categories.CATEGORY_RANGES[i].length; j += 2) assignedRanges.add(new CharRange(Categories.CATEGORY_RANGES[i][j], Categories.CATEGORY_RANGES[i][j + 1])); base = new Union(new CharClass[] { base, new CharRange(NONBMP_MIN, NONBMP_MAX) }); } return new Subtraction(base, new Union(assignedRanges)); } List classes = new Vector(); classes.add(base); if (!surrogatesDirect) { int sci = Categories.CATEGORY_NAMES.indexOf(name); if (sci >= 0) { int[] addRanges = Categories.CATEGORY_RANGES[sci/2]; for (int i = 0; i < addRanges.length; i += 2) classes.add(new CharRange(addRanges[i], addRanges[i + 1])); } } if (name.equals("Lu")) classes.add(new SingleChar(UNICODE_3_1_ADD_Lu)); else if (name.equals("Ll")) classes.add(new SingleChar(UNICODE_3_1_ADD_Ll)); else if (name.equals("Nl")) classes.add(new CharRange(UNICODE_3_1_CHANGE_No_to_Nl_MIN, UNICODE_3_1_CHANGE_No_to_Nl_MAX)); else if (name.equals("No")) return new Subtraction(new Union(classes), new CharRange(UNICODE_3_1_CHANGE_No_to_Nl_MIN, UNICODE_3_1_CHANGE_No_to_Nl_MAX)); if (classes.size() == 1) return base; return new Union(classes); } private static CharClass makeCharClass(String members) { List list = new Vector(); for (int i = 0, len = members.length(); i < len; i++) list.add(new SingleChar(members.charAt(i))); return new Union(list); } public static void main(String[] args) throws RegexSyntaxException { String s = translate(args[0]); for (int i = 0, len = s.length(); i < len; i++) { char c = s.charAt(i); if (c >= 0x20 && c <= 0x7e) System.err.print(c); else { System.err.print("\\u"); for (int shift = 12; shift >= 0; shift -= 4) System.err.print("0123456789ABCDEF".charAt((c >> shift) & 0xF)); } } System.err.println(); } } jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/java/resources/000077500000000000000000000000001225366607500327645ustar00rootroot00000000000000Messages.properties000066400000000000000000000012601225366607500365710ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/java/resourcesbad_block_name=unrecognized Unicode block name \"{0}\" bad_category=unrecognized Unicode category \"{0}\" bad_escape=illegal escape bad_property_name=bad property name \"{0}\" empty_property_name=property name must not be empty expected=expected \"{0}\" expected_digit=expected a digit expected_eos=character is not allowed in this context invalid_range=lower bound of range must not have Unicode code point greater than upper bound invalid_surrogate=illegal surrogate pair multi_range=bounds of range must be single characters should_quote=character \"{0}\" must be escaped with \"\\\" in ths context invalid_quantity_range=lower bound of quantifier must not be greater than upper bound jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/xerces2/000077500000000000000000000000001225366607500314045ustar00rootroot00000000000000RegexEngineImpl.java000066400000000000000000000021261225366607500352130ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/main/com/thaiopensource/datatype/xsd/regex/xerces2package com.thaiopensource.datatype.xsd.regex.xerces2; import com.thaiopensource.datatype.xsd.regex.RegexEngine; import com.thaiopensource.datatype.xsd.regex.Regex; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import org.apache.xerces.impl.xpath.regex.RegularExpression; import org.apache.xerces.impl.xpath.regex.ParseException; /** * An implementation of RegexEngine using the Xerces 2 regular expression * implementation. */ public class RegexEngineImpl implements RegexEngine { public RegexEngineImpl() { // Force a linkage error on instantiation if the Xerces classes // are not available. try { new RegularExpression("", "X"); } catch (ParseException e) { } } public Regex compile(String expr) throws RegexSyntaxException { try { final RegularExpression re = new RegularExpression(expr, "X"); return new Regex() { public boolean matches(String str) { return re.matches(str); } }; } catch (ParseException e) { throw new RegexSyntaxException(e.getMessage(), e.getLocation()); } } } jing-trang-20131210+dfsg+1/mod/regex/src/test/000077500000000000000000000000001225366607500205335ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/000077500000000000000000000000001225366607500213115ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/000077500000000000000000000000001225366607500243415ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/000077500000000000000000000000001225366607500261545ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/000077500000000000000000000000001225366607500267525ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/regex/000077500000000000000000000000001225366607500300645ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/regex/test/000077500000000000000000000000001225366607500310435ustar00rootroot00000000000000CategoryTest.java000066400000000000000000000107011225366607500342430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/regex/testpackage com.thaiopensource.datatype.xsd.regex.test; import com.thaiopensource.datatype.xsd.regex.Regex; import com.thaiopensource.datatype.xsd.regex.RegexEngine; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import com.thaiopensource.util.Utf16; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class CategoryTest { static private final String categories = "LMNPZSC"; static private final String subCategories = "LuLlLtLmLoMnMcMeNdNlNoPcPdPsPePiPfPoZsZlZpSmScSkSoCcCfCoCn"; private final Regex[] categoryPosRegexes = new Regex[categories.length()]; private final Regex[] categoryNegRegexes = new Regex[categories.length()]; private final Regex[] subCategoryPosRegexes = new Regex[subCategories.length()/2]; private final Regex[] subCategoryNegRegexes = new Regex[subCategories.length()/2]; static public void main(String[] args) throws IOException, RegexSyntaxException, ClassNotFoundException, IllegalAccessException, InstantiationException { if (args.length != 2) { System.err.println("usage: " + CategoryTest.class.getName() + " engineClass UnicodeData"); System.exit(2); } BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(args[1]))); Class cls = CategoryTest.class.getClassLoader().loadClass(args[0]); RegexEngine engine = (RegexEngine)cls.newInstance(); int nFail = new CategoryTest(engine).testAll(r); System.err.println(nFail + " tests failed"); System.exit(nFail > 0 ? 1 : 0); } CategoryTest(RegexEngine engine) throws RegexSyntaxException { for (int i = 0, len = categories.length(); i < len; i++) { String ch = categories.substring(i, i + 1); categoryPosRegexes[i] = engine.compile("\\p{" + ch + "}"); categoryNegRegexes[i] = engine.compile("\\P{" + ch + "}"); } for (int i = 0, len = subCategories.length(); i < len; i += 2) { String name = subCategories.substring(i, i + 2); subCategoryPosRegexes[i/2] = engine.compile("\\p{" + name + "}"); subCategoryNegRegexes[i/2] = engine.compile("\\P{" + name + "}"); } } int testAll(BufferedReader r) throws IOException { int lastCode = -1; for (;;) { String line = r.readLine(); if (line == null) break; int semi = line.indexOf(';'); if (semi < 0) continue; int code = Integer.parseInt(line.substring(0, semi), 16); int semi2 = line.indexOf(';', semi + 1); String name = line.substring(semi, semi2); String category = line.substring(semi2 + 1, semi2 + 3); if (lastCode + 1 != code) { String missingCategory = name.endsWith(", Last>") ? category : "Cn"; for (int i = lastCode + 1; i < code; i++) test(i, missingCategory); } test(code, category); lastCode = code; } for (++lastCode; lastCode < 0x110000; lastCode++) test(lastCode, "Cn"); return nFail; } void test(int ch, String category) { if (!isXmlChar(ch)) return; if (subCategories.indexOf(category) < 0) { System.err.println("Missing category: " + category); System.exit(2); } for (int i = 0, len = categories.length(); i < len; i++) check(ch, categoryPosRegexes[i], categoryNegRegexes[i], category.charAt(0) == categories.charAt(i), categories.substring(i, i + 1)); for (int i = 0, len = subCategories.length(); i < len; i += 2) check(ch, subCategoryPosRegexes[i/2], subCategoryNegRegexes[i/2], category.equals(subCategories.substring(i, i + 2)), subCategories.substring(i, i + 2)); } void check(int ch, Regex pos, Regex neg, boolean inPos, String cat) { String str; if (ch > 0xFFFF) str = new String(new char[]{ Utf16.surrogate1(ch), Utf16.surrogate2(ch) }); else str = new String(new char[]{ (char)ch }); if (pos.matches(str) != inPos ) fail(ch, cat); if (neg.matches(str) != !inPos) fail(ch, "-" + cat); } int nFail = 0; void fail(int ch, String cat) { nFail++; System.err.println("Failed: " + Integer.toHexString(ch) + "/" + cat); } static boolean isXmlChar(int code) { switch (code) { case '\r': case '\n': case '\t': return true; case 0xFFFE: case 0xFFFF: return false; default: if (code < 0x20) return false; if (code >= 0xD800 && code < 0xE000) return false; return true; } } } NameTest.java000066400000000000000000000040611225366607500333500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/regex/testpackage com.thaiopensource.datatype.xsd.regex.test; import com.thaiopensource.datatype.xsd.regex.Regex; import com.thaiopensource.datatype.xsd.regex.RegexEngine; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import com.thaiopensource.util.Utf16; import com.thaiopensource.xml.util.Naming; public class NameTest { private Regex nameRegex; private Regex nameStartRegex; public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, RegexSyntaxException { if (args.length != 1) { System.err.println("usage: " + NameTest.class.getName() + " engineClass"); System.exit(2); } Class cls = NameTest.class.getClassLoader().loadClass(args[0]); RegexEngine engine = (RegexEngine)cls.newInstance(); int nFail = new NameTest(engine).run(); System.err.println(nFail + " tests failed"); System.exit(nFail > 0 ? 1 : 0); } NameTest(RegexEngine engine) throws RegexSyntaxException { nameStartRegex = engine.compile("\\i"); nameRegex = engine.compile("\\c"); } int run() { int nFail = 0; for (int i = 0; i < 0x10000; i++) { String s = new String(new char[]{(char)i}); if (nameRegex.matches(s) != Naming.isNmtoken(s)) { System.out.println("Failed for " + Integer.toHexString(i) + "; expected name == " + Naming.isNmtoken(s)); nFail++; } if (nameStartRegex.matches(s) != Naming.isName(s)) { System.out.println("Failed for " + Integer.toHexString(i) + "; expected nameStart == " + Naming.isName(s)); nFail++; } } for (int i = 0x10000; i < 0x110000; i++) { String s = new String(new char[] {Utf16.surrogate1(i), Utf16.surrogate2(i)}); if (nameRegex.matches(s)) { System.out.println("Failed for " + Integer.toHexString(i) + "; expected name == false"); nFail++; } if (nameStartRegex.matches(s)) { System.out.println("Failed for " + Integer.toHexString(i) + "; expected nameStart == false"); nFail++; } } return nFail; } } TestDriver.java000066400000000000000000000110021225366607500337140ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/src/test/com/thaiopensource/datatype/xsd/regex/testpackage com.thaiopensource.datatype.xsd.regex.test; import com.thaiopensource.datatype.xsd.regex.Regex; import com.thaiopensource.datatype.xsd.regex.RegexEngine; import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; import com.thaiopensource.util.UriOrFile; import com.thaiopensource.util.Utf16; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; public class TestDriver extends DefaultHandler { private final StringBuffer buf = new StringBuffer(); private Regex regex; private int nFail = 0; private int nTests = 0; private Locator loc; private final RegexEngine engine; static public void main(String[] args) throws SAXException, IOException, ParserConfigurationException, ClassNotFoundException, IllegalAccessException, InstantiationException { if (args.length != 2) { System.err.println("usage: TestDriver class testfile"); System.exit(2); } SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); XMLReader xr = factory.newSAXParser().getXMLReader(); Class cls = TestDriver.class.getClassLoader().loadClass(args[0]); RegexEngine engine = (RegexEngine)cls.newInstance(); TestDriver tester = new TestDriver(engine); xr.setContentHandler(tester); InputSource in = new InputSource(UriOrFile.fileToUri(args[1])); xr.parse(in); System.err.println(tester.nTests + " tests performed"); System.err.println(tester.nFail + " failures"); if (tester.nFail > 0) System.exit(1); } public TestDriver(RegexEngine engine) { this.engine = engine; } public void setDocumentLocator(Locator locator) { this.loc = locator; } public void characters(char ch[], int start, int length) throws SAXException { buf.append(ch, start, length); } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { buf.append(ch, start, length); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { buf.setLength(0); } public void endElement(String uri, String localName, String qName) throws SAXException { if (localName.equals("valid")) valid(buf.toString()); else if (localName.equals("invalid")) invalid(buf.toString()); else if (localName.equals("correct")) correct(buf.toString()); else if (localName.equals("incorrect")) incorrect(buf.toString()); } private void correct(String str) { nTests++; regex = null; try { regex = engine.compile(str); } catch (RegexSyntaxException e) { error("unexpected error: " + e.getMessage() + ": " + display(str, e.getPosition())); } } private void incorrect(String str) { nTests++; regex = null; try { engine.compile(str); error("failed to detect error in regex: " + display(str, -1)); } catch (RegexSyntaxException e) { } } private void valid(String str) { if (regex == null) return; nTests++; if (!regex.matches(str)) error("match failed for string: " + display(str, -1)); } private void invalid(String str) { if (regex == null) return; nTests++; if (regex.matches(str)) error("match incorrectly succeeded for string: " + display(str, -1)); } private void error(String str) { int line = -1; if (loc != null) line = loc.getLineNumber(); if (line >= 0) System.err.print("Line " + line + ": "); System.err.println(str); nFail++; } static final private String ERROR_MARKER = ">>>>"; static String display(String str, int pos) { StringBuffer buf = new StringBuffer(); for (int i = 0, len = str.length(); i < len; i++) { if (i == pos) buf.append(ERROR_MARKER); char c = str.charAt(i); if (Utf16.isSurrogate1(c)) buf.append("&#x" + Integer.toHexString(Utf16.scalarValue(c, str.charAt(++i))) + ";"); else if (c < ' ' || c >= 0x7F) buf.append("&#x" + Integer.toHexString(c) + ";"); else if (c == '&') buf.append("&"); else buf.append(c); } if (str.length() == pos) buf.append(ERROR_MARKER); return buf.toString(); } } jing-trang-20131210+dfsg+1/mod/regex/test/000077500000000000000000000000001225366607500177445ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/regex/test/hardtest.xml000066400000000000000000000005541225366607500223100ustar00rootroot00000000000000 ) x{2147483648} x x{2147483649,2147483648} x{0,2147483648} x jing-trang-20131210+dfsg+1/mod/regex/test/regextest.xml000066400000000000000000000100101225366607500224700ustar00rootroot00000000000000 xyzzy xyzzy xyzz xyzzyy xxyzzy XYZZY xyzzy \i j : 𐀀 𐐀 𐐨 a?? \P{IsGothic} 𐌰 𐌿 𐍏 X 𐌯 𠌰 𰌰 𐍐 \p{IsGothic} 𐌰 𐌿 𐍏 X 𐌯 𠌰 𰌰 𐍐 $ $ a|b [x-y] [\p{Nd}-[a-z]] [\p{Nd}-[\p{IsThai}]] \p{IsThai} \i\c* ~!@#$%\^&\*\(\)_\+`\-=\{\}\[\]\|\\:;"',\.<>/\? ~!@#$%^&*()_+`-={}[]|\:;"',.<>/? [f&&g] f & g ^ ^ \ ? * + ( [ ] - - | | . . .. 𐌰 [^] [] []] [[] [\] [^^] x ^ [?+*(){}|.] ? + * ( ) { } | . x x x{2,1} x{1,1} x x{1, 2} x{ 2} x{2 } x{-0,1} x{+2} [a-z-[c-y]] a b z c y d [abc-[a-a]] b c a d [a-[a]-[a]] \pL \p{IsHighSurrogates} \p{IsHighPrivateUseSurrogates} \p{IsLowSurrogates} a[𐌰-[𐌰]]*b ab a𐌰b jing-trang-20131210+dfsg+1/mod/resolver/000077500000000000000000000000001225366607500175145ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/mod.xml000066400000000000000000000000451225366607500210140ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/resolver/src/000077500000000000000000000000001225366607500203035ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/000077500000000000000000000000001225366607500212275ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/000077500000000000000000000000001225366607500220055ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/000077500000000000000000000000001225366607500250355ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/000077500000000000000000000000001225366607500266765ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/AbstractResolver.java000066400000000000000000000005231225366607500330260ustar00rootroot00000000000000package com.thaiopensource.resolver; import java.io.IOException; /** * */ public class AbstractResolver implements Resolver { public void resolve(Identifier id, Input input) throws IOException, ResolverException { // do nothing } public void open(Input input) throws IOException, ResolverException { // do nothing } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/BasicResolver.java000066400000000000000000000030531225366607500323050ustar00rootroot00000000000000package com.thaiopensource.resolver; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.io.IOException; /** * */ public class BasicResolver implements Resolver { static private final BasicResolver theInstance = new BasicResolver(); protected BasicResolver() { } public static BasicResolver getInstance() { return theInstance; } public void resolve(Identifier id, Input input) throws IOException, ResolverException { if (!input.isResolved()) input.setUri(resolveUri(id)); } public void open(Input input) throws IOException, ResolverException { if (!input.isUriDefinitive()) return; URI uri; try { uri = new URI(input.getUri()); } catch (URISyntaxException e) { throw new ResolverException(e); } if (!uri.isAbsolute()) throw new ResolverException("cannot open relative URI: " + uri); URL url = new URL(uri.toASCIIString()); // XXX should set the encoding properly // XXX if this is HTTP and we've been redirected, should do input.setURI with the new URI input.setByteStream(url.openStream()); } public static String resolveUri(Identifier id) throws ResolverException { try { final String uriRef = id.getUriReference(); URI uri = new URI(uriRef); if (!uri.isAbsolute()) { String base = id.getBase(); if (base != null) return new URI(base).resolve(uri).toString(); } return uriRef; } catch (URISyntaxException e) { throw new ResolverException(e); } } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/Identifier.java000066400000000000000000000012641225366607500316260ustar00rootroot00000000000000package com.thaiopensource.resolver; /** * */ public class Identifier { private final String href; private final String base; public Identifier(String href, String base) { if (href == null) throw new NullPointerException(); this.href = href; this.base = base; } public Identifier(String href) { this(href, null); } /** * Must return non-null * @return */ public String getUriReference() { return href; } /** * * @return maybe null */ public String getBase() { return base; } /** * Return a canonical media type for what's expected. Never null. */ public String getMediaType() { return "*/*"; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/Input.java000066400000000000000000000021241225366607500306370ustar00rootroot00000000000000package com.thaiopensource.resolver; import java.io.InputStream; import java.io.Reader; /** * */ public class Input { private String uri; private String encoding; private InputStream byteStream; private Reader characterStream; // XXX add media type public Input() { } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public InputStream getByteStream() { return byteStream; } public void setByteStream(InputStream byteStream) { this.byteStream = byteStream; } public Reader getCharacterStream() { return characterStream; } public void setCharacterStream(Reader charStream) { this.characterStream = charStream; } public boolean isResolved() { return isOpen() || uri != null; } public boolean isOpen() { return byteStream != null || characterStream != null; } public boolean isUriDefinitive() { return !isOpen() && uri != null; } } MediaTypedIdentifier.java000066400000000000000000000005201225366607500335070ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolverpackage com.thaiopensource.resolver; /** * */ public class MediaTypedIdentifier extends Identifier { private final String mediaType; public MediaTypedIdentifier(String href, String base, String mediaType) { super(href, base); this.mediaType = mediaType; } public String getMediaType() { return mediaType; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/Resolver.java000066400000000000000000000003631225366607500313440ustar00rootroot00000000000000package com.thaiopensource.resolver; import java.io.IOException; public interface Resolver { void resolve(Identifier id, Input input) throws IOException, ResolverException; void open(Input input) throws IOException, ResolverException; } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/ResolverException.java000066400000000000000000000006101225366607500332160ustar00rootroot00000000000000package com.thaiopensource.resolver; /** * */ public class ResolverException extends Exception { public ResolverException(Throwable t) { super(t); } public ResolverException(String message) { super(message); } public Throwable unwrap() { if (getMessage() == null) { Throwable t = getCause(); if (t != null) return t; } return this; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/SequenceResolver.java000066400000000000000000000010471225366607500330350ustar00rootroot00000000000000package com.thaiopensource.resolver; import java.io.IOException; /** * */ public class SequenceResolver implements Resolver { private final Resolver r1; private final Resolver r2; public SequenceResolver(Resolver r1, Resolver r2) { this.r1 = r1; this.r2 = r2; } public void resolve(Identifier id, Input input) throws IOException, ResolverException { r1.resolve(id, input); r2.resolve(id, input); } public void open(Input input) throws IOException, ResolverException { r1.open(input); r2.open(input); } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/load/000077500000000000000000000000001225366607500276155ustar00rootroot00000000000000ResolverLoadException.java000066400000000000000000000004011225366607500346540ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/loadpackage com.thaiopensource.resolver.load; /** * */ public class ResolverLoadException extends Exception { public ResolverLoadException(String message) { super(message); } public ResolverLoadException(Throwable cause) { super(cause); } } ResolverLoader.java000066400000000000000000000033761225366607500333420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/loadpackage com.thaiopensource.resolver.load; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.SequenceResolver; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.transform.Transform; import org.xml.sax.EntityResolver; import javax.xml.transform.URIResolver; /** * XXX maybe get rid of this */ public class ResolverLoader { public static Resolver loadResolver(String className, ClassLoader loader) throws ResolverLoadException { Object obj; try { if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { loader = ClassLoader.getSystemClassLoader(); if (loader == null) throw new ResolverLoadException("no class loader"); } } obj = loader.loadClass(className).newInstance(); } catch (Exception e) { throw new ResolverLoadException(e); } if (obj instanceof Resolver) return (Resolver)obj; Resolver entityResolver = null; Resolver uriResolver = null; if (obj instanceof URIResolver) uriResolver = Transform.createResolver((URIResolver)obj); if (obj instanceof EntityResolver) entityResolver = SAX.createResolver((EntityResolver)obj, uriResolver == null); if (uriResolver == null) { if (entityResolver == null) throw new ResolverLoadException(className + " not an instance of javax.xml.transform.URIResolver or org.xml.sax.EntityResolver"); return entityResolver; } if (entityResolver == null) return uriResolver; // do the entityResolver first so that it has first go at ExternalIdentifier return new SequenceResolver(entityResolver, uriResolver); } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/000077500000000000000000000000001225366607500274765ustar00rootroot00000000000000ExternalDTDSubsetIdentifier.java000066400000000000000000000006211225366607500355700ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xmlpackage com.thaiopensource.resolver.xml; /** * */ public class ExternalDTDSubsetIdentifier extends ExternalIdentifier { private final String doctypeName; public ExternalDTDSubsetIdentifier(String href, String base, String publicId, String doctypeName) { super(href, base, publicId); this.doctypeName = doctypeName; } public String getDoctypeName() { return doctypeName; } } ExternalEntityIdentifier.java000066400000000000000000000010431225366607500352420ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xmlpackage com.thaiopensource.resolver.xml; /** * */ public class ExternalEntityIdentifier extends ExternalIdentifier { private final String entityName; /** * * @param href * @param base * @param publicId maybe null * @param entityName starts with a % for a parameter entity, may be null */ public ExternalEntityIdentifier(String href, String base, String publicId, String entityName) { super(href, base, publicId); this.entityName = entityName; } public String getEntityName() { return entityName; } } ExternalIdentifier.java000066400000000000000000000005721225366607500340530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xmlpackage com.thaiopensource.resolver.xml; import com.thaiopensource.resolver.Identifier; /** * */ public class ExternalIdentifier extends Identifier { private final String publicId; public ExternalIdentifier(String href, String base, String publicId) { super(href, base); this.publicId = publicId; } public String getPublicId() { return publicId; } } TargetNamespaceIdentifier.java000066400000000000000000000006521225366607500353330ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xmlpackage com.thaiopensource.resolver.xml; /** * Derived classes of Identifier should implement this when they have a "target namespace". * For example, when you are looking for a schema for a particular namespace, that namespace * would be your target namespace, which is distinct from the namespace of root element * of the schema. */ public interface TargetNamespaceIdentifier { public String getTargetNamespace(); } XMLDocumentIdentifier.java000066400000000000000000000015731225366607500344320ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xmlpackage com.thaiopensource.resolver.xml; import com.thaiopensource.resolver.Identifier; /** * An Identifier for an XML document. */ public class XMLDocumentIdentifier extends Identifier { private final String namespaceUri; public static final String MEDIA_TYPE = "application/xml"; /** * * @param href * @param base * @param namespaceUri the expected namespace URI of the root element of the XML document */ public XMLDocumentIdentifier(String href, String base, String namespaceUri) { super(href, base); this.namespaceUri = namespaceUri; } /** * * @return the expected namespace name of root element; "" if no namespace is expected; * null if no information is available about the expected namespace name. */ public String getNamespaceUri() { return namespaceUri; } public String getMediaType() { return MEDIA_TYPE; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/ls/000077500000000000000000000000001225366607500301145ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/ls/LS.java000066400000000000000000000052701225366607500313010ustar00rootroot00000000000000package com.thaiopensource.resolver.xml.ls; import com.thaiopensource.resolver.AbstractResolver; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalIdentifier; import com.thaiopensource.resolver.xml.TargetNamespaceIdentifier; import com.thaiopensource.resolver.xml.XMLDocumentIdentifier; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; /** * */ public class LS { private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml"; private static final String IANA_MEDIA_TYPE_URI = "http://www.iana.org/assignments/media-types/"; private LS() { } public static Resolver createResolver(final LSResourceResolver resourceResolver) { return new AbstractResolver() { public void resolve(Identifier id, Input input) throws IOException, ResolverException { if (input.isResolved()) return; String base = id.getBase(); String publicId = null; String type = null; if (id instanceof ExternalIdentifier) { publicId = ((ExternalIdentifier)id).getPublicId(); type = XML_TYPE; } else if (id instanceof XMLDocumentIdentifier) type = ((XMLDocumentIdentifier)id).getNamespaceUri(); if (type == null) { String mediaType = id.getMediaType(); if (mediaType.indexOf('*') < 0) type = IANA_MEDIA_TYPE_URI + mediaType; } String targetNamespace = null; if (id instanceof TargetNamespaceIdentifier) targetNamespace = ((TargetNamespaceIdentifier)id).getTargetNamespace(); LSInput lsInput = resourceResolver.resolveResource(type, targetNamespace, publicId, id.getUriReference(), base); if (lsInput == null) return; input.setEncoding(lsInput.getEncoding()); input.setUri(lsInput.getSystemId()); final Reader characterStream = lsInput.getCharacterStream(); if (characterStream != null) { input.setCharacterStream(characterStream); return; } final InputStream byteStream = lsInput.getByteStream(); if (byteStream != null) { input.setByteStream(byteStream); return; } final String stringData = lsInput.getStringData(); if (stringData != null) { input.setCharacterStream(new StringReader(stringData)); return; } // we don't support redirecting to a public ID } }; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/sax/000077500000000000000000000000001225366607500302715ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/sax/SAX.java000066400000000000000000000163771225366607500316050ustar00rootroot00000000000000package com.thaiopensource.resolver.xml.sax; import com.thaiopensource.resolver.AbstractResolver; import com.thaiopensource.resolver.BasicResolver; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.ExternalDTDSubsetIdentifier; import com.thaiopensource.resolver.xml.ExternalEntityIdentifier; import com.thaiopensource.resolver.xml.ExternalIdentifier; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.ext.EntityResolver2; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; /** * */ public class SAX { private SAX() { } private static final class EntityResolverWrapper extends AbstractResolver { private final EntityResolver entityResolver; private final EntityResolver2 entityResolver2; private final boolean promiscuous; private EntityResolverWrapper(EntityResolver entityResolver, boolean promiscuous) { this.entityResolver = entityResolver; if (entityResolver instanceof EntityResolver2) entityResolver2 = (EntityResolver2)entityResolver; else entityResolver2 = null; this.promiscuous = promiscuous; } public void open(Input input) throws IOException, ResolverException { if (!input.isUriDefinitive()) return; URI uri; try { uri = new URI(input.getUri()); } catch (URISyntaxException e) { throw new ResolverException(e); } if (!uri.isAbsolute()) throw new ResolverException("cannot open relative URI: " + uri); URL url = new URL(uri.toASCIIString()); // XXX should set the encoding properly // XXX if this is HTTP and we've been redirected, should do input.setURI with the new URI input.setByteStream(url.openStream()); } public void resolve(Identifier id, Input input) throws IOException, ResolverException { if (input.isResolved()) return; String publicId; String entityName = null; if (id instanceof ExternalIdentifier) { publicId = ((ExternalIdentifier)id).getPublicId(); if (id instanceof ExternalEntityIdentifier) entityName = ((ExternalEntityIdentifier)id).getEntityName(); else if (id instanceof ExternalDTDSubsetIdentifier) entityName = "[dtd]"; } else { if (!promiscuous) return; publicId = null; } try { InputSource inputSource; if (entityName != null && entityResolver2 != null) inputSource = entityResolver2.resolveEntity(entityName, publicId, id.getBase(), id.getUriReference()); else inputSource = entityResolver.resolveEntity(publicId, getSystemId(id)); if (inputSource != null) setInput(input, inputSource); } catch (SAXException e) { throw toResolverException(e); } } } public static Resolver createResolver(final EntityResolver entityResolver, boolean promiscuous) { return new EntityResolverWrapper(entityResolver, promiscuous); } public static EntityResolver2 createEntityResolver(Resolver resolver) { if (resolver == null) throw new NullPointerException(); return new EntityResolverImpl(resolver); } public static Input createInput(InputSource inputSource) { Input input = new Input(); setInput(input, inputSource); return input; } // public because needed by transform package public static void setInput(Input input, InputSource inputSource) { input.setByteStream(inputSource.getByteStream()); input.setCharacterStream(inputSource.getCharacterStream()); input.setUri(inputSource.getSystemId()); input.setEncoding(inputSource.getEncoding()); } public static Exception getWrappedException(SAXException e) { // not purely a wrapper if (e.getMessage() != null) return null; return e.getException(); } public static ResolverException toResolverException(SAXException e) { Exception wrapped = getWrappedException(e); if (wrapped != null) { if (wrapped instanceof ResolverException) return (ResolverException)wrapped; return new ResolverException(wrapped); } return new ResolverException(e); } public static SAXException toSAXException(ResolverException e) { Throwable cause = e.getCause(); if (cause != null && cause instanceof SAXException) return (SAXException)cause; return new SAXException(e); } static InputSource createInputSource(Input input) { InputSource inputSource = new InputSource(); inputSource.setByteStream(input.getByteStream()); inputSource.setCharacterStream(input.getCharacterStream()); inputSource.setEncoding(input.getEncoding()); inputSource.setSystemId(input.getUri()); return inputSource; } static String getSystemId(Identifier id) { try { return BasicResolver.resolveUri(id); } catch (ResolverException e) { } return id.getUriReference(); } // precondition: input.isResolved() static InputSource createInputSource(Identifier id, Input input) { InputSource inputSource = createInputSource(input); if (id instanceof ExternalIdentifier) inputSource.setPublicId(((ExternalIdentifier)id).getPublicId()); if (inputSource.getSystemId() == null) inputSource.setSystemId(getSystemId(id)); return inputSource; } static private class EntityResolverImpl implements EntityResolver2 { private final Resolver resolver; private EntityResolverImpl(Resolver resolver) { this.resolver = resolver; } public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId == null) return null; ExternalIdentifier id = new ExternalIdentifier(systemId, null, publicId); Input input = new Input(); try { resolver.resolve(id, input); } catch (ResolverException e) { throw toSAXException(e); } if (input.isResolved()) return createInputSource(id, input); return null; } public InputSource resolveEntity(String name, String publicId, String base, String systemId) throws SAXException, IOException { if (systemId == null) return null; ExternalIdentifier id; if ("[doc]".equals(name)) id = new ExternalDTDSubsetIdentifier(systemId, base, publicId, null); else if (name == null || name.indexOf('[') >= 0 || name.indexOf('#') >= 0) id = new ExternalIdentifier(systemId, base, publicId); else id = new ExternalEntityIdentifier(systemId, base, publicId, name); Input input = new Input(); try { resolver.resolve(id, input); } catch (ResolverException e) { throw toSAXException(e); } if (input.isResolved()) return createInputSource(id, input); return null; } public InputSource getExternalSubset(String name, String base) throws SAXException, IOException { return null; } } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/sax/SAXInput.java000066400000000000000000000005201225366607500326040ustar00rootroot00000000000000package com.thaiopensource.resolver.xml.sax; import com.thaiopensource.resolver.Input; import org.xml.sax.XMLReader; /** * */ public class SAXInput extends Input { private XMLReader reader; public XMLReader getXMLReader() { return reader; } public void setXMLReader(XMLReader reader) { this.reader = reader; } } SAXResolver.java000066400000000000000000000065041225366607500332370ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/saxpackage com.thaiopensource.resolver.xml.sax; import com.thaiopensource.resolver.BasicResolver; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.SequenceResolver; import com.thaiopensource.resolver.xml.XMLDocumentIdentifier; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.sax.SAXSource; import java.io.IOException; /** * */ public class SAXResolver { private final Resolver resolver; private final SAXParserFactory parserFactory; public SAXResolver(Resolver resolver) { Resolver tem = BasicResolver.getInstance(); if (resolver != null) tem = new SequenceResolver(resolver, tem); this.resolver = tem; parserFactory = SAXParserFactory.newInstance(); parserFactory.setNamespaceAware(true); parserFactory.setValidating(false); } public SAXResolver() { this(null); } public Resolver getResolver() { return resolver; } public SAXSource resolve(String href, String base) throws SAXException, IOException { return resolve(new Identifier(href, base)); } public SAXSource resolve(String href, String base, String rootNamespaceUri) throws SAXException, IOException { return resolve(new XMLDocumentIdentifier(href, base, rootNamespaceUri)); } public SAXSource resolve(Identifier id) throws SAXException, IOException { SAXInput input = new SAXInput(); try { resolver.resolve(id, input); if (!input.isResolved()) input.setUri(BasicResolver.resolveUri(id)); InputSource inputSource = SAX.createInputSource(id, input); XMLReader xr = input.getXMLReader(); if (xr == null) xr = createXMLReader(); return new SAXSource(xr, inputSource); } catch (ResolverException e) { throw SAX.toSAXException(e); } } public SAXSource createSAXSource(Input input) throws SAXException { InputSource inputSource = SAX.createInputSource(input); XMLReader xr = null; if (input instanceof SAXInput) xr = ((SAXInput)input).getXMLReader(); if (xr == null) xr = createXMLReader(); return new SAXSource(xr, inputSource); } public XMLReader createXMLReader() throws SAXException { XMLReader xr = createXMLReaderWithoutResolver(); xr.setEntityResolver(SAX.createEntityResolver(resolver)); return xr; } protected XMLReader createXMLReaderWithoutResolver() throws SAXException { try { return parserFactory.newSAXParser().getXMLReader(); } catch (ParserConfigurationException e) { throw new SAXException(e); } } public InputSource open(InputSource inputSource) throws SAXException, IOException { if (inputSource.getByteStream() != null || inputSource.getCharacterStream() != null) return inputSource; Input input = SAX.createInput(inputSource); try { resolver.open(input); } catch (ResolverException e) { throw SAX.toSAXException(e); } String publicId = inputSource.getPublicId(); inputSource = SAX.createInputSource(input); inputSource.setPublicId(publicId); return inputSource; } } jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/transform/000077500000000000000000000000001225366607500315115ustar00rootroot00000000000000Transform.java000066400000000000000000000071341225366607500342550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/resolver/src/main/com/thaiopensource/resolver/xml/transformpackage com.thaiopensource.resolver.xml.transform; import com.thaiopensource.resolver.AbstractResolver; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.sax.SAXInput; import com.thaiopensource.resolver.xml.sax.SAXResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXSource; import java.io.IOException; /** * */ public class Transform { private Transform() { } /** * Creates a URIResolver that returns a SAXSource. * @param resolver * @return */ public static URIResolver createSAXURIResolver(Resolver resolver) { final SAXResolver saxResolver = new SAXResolver(resolver); return new URIResolver() { public Source resolve(String href, String base) throws TransformerException { try { return saxResolver.resolve(href, base); } catch (SAXException e) { throw toTransformerException(e); } catch (IOException e) { throw new TransformerException(e); } } }; } public static Resolver createResolver(final URIResolver uriResolver) { return new AbstractResolver() { public void resolve(Identifier id, Input input) throws IOException, ResolverException { if (input.isResolved()) return; Source source; try { source = uriResolver.resolve(id.getUriReference(), id.getBase()); } catch (TransformerException e) { throw toResolverException(e); } if (source == null) return; if (source instanceof SAXSource) { setInput(input, (SAXSource)source); return; } InputSource in = SAXSource.sourceToInputSource(source); if (in != null) { SAX.setInput(input, in); return; } // XXX handle StAXSource throw new ResolverException("URIResolver returned unsupported subclass of Source"); } }; } private static void setInput(Input input, SAXSource source) { XMLReader reader = source.getXMLReader(); if (reader != null) { if (input instanceof SAXInput) ((SAXInput)input).setXMLReader(reader); } InputSource in = source.getInputSource(); if (in != null) SAX.setInput(input, in); } private static TransformerException toTransformerException(SAXException e) { Exception wrapped = SAX.getWrappedException(e); if (wrapped != null) { if (wrapped instanceof TransformerException) return (TransformerException)wrapped; return new TransformerException(wrapped); } return new TransformerException(e); } private static ResolverException toResolverException(TransformerException e) { Throwable wrapped = getWrappedException(e); if (wrapped != null) { if (wrapped instanceof ResolverException) return (ResolverException)wrapped; return new ResolverException(wrapped); } return new ResolverException(e); } private static Throwable getWrappedException(TransformerException e) { Throwable wrapped = e.getException(); if (wrapped == null) return null; String message = e.getMessage(); if (message != null && !message.equals(wrapped.getMessage())) return null; return wrapped; } } jing-trang-20131210+dfsg+1/mod/rng-jarv/000077500000000000000000000000001225366607500174015ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/mod.xml000066400000000000000000000005661225366607500207110ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/rng-jarv/src/000077500000000000000000000000001225366607500201705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/000077500000000000000000000000001225366607500211145ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/000077500000000000000000000000001225366607500216725ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/000077500000000000000000000000001225366607500247225ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500263625ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarv/000077500000000000000000000000001225366607500273245ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarv/SchemaImpl.java000066400000000000000000000013311225366607500322070ustar00rootroot00000000000000package com.thaiopensource.relaxng.jarv; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import org.iso_relax.verifier.Schema; import org.iso_relax.verifier.Verifier; import org.iso_relax.verifier.VerifierConfigurationException; class SchemaImpl implements Schema { private final SchemaPatternBuilder spb; private final Pattern start; SchemaImpl(Pattern start, SchemaPatternBuilder spb) { this.start = start; this.spb = spb; } public Verifier newVerifier() throws VerifierConfigurationException { return new VerifierImpl(start, new ValidatorPatternBuilder(spb)); } } VerifierFactoryImpl.java000066400000000000000000000050001225366607500340300ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarvpackage com.thaiopensource.relaxng.jarv; import com.thaiopensource.datatype.DatatypeLibraryLoader; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.sax.SAXParseable; import com.thaiopensource.relaxng.pattern.SchemaBuilderImpl; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.xml.sax.DraconianErrorHandler; import com.thaiopensource.util.VoidValue; import org.iso_relax.verifier.Schema; import org.iso_relax.verifier.VerifierFactory; import org.relaxng.datatype.DatatypeLibraryFactory; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; import java.io.IOException; public class VerifierFactoryImpl extends VerifierFactory { private final DatatypeLibraryFactory dlf = new DatatypeLibraryLoader(); private final ErrorHandler eh = new DraconianErrorHandler(); public VerifierFactoryImpl() { } public Schema compileSchema(InputSource inputSource) throws SAXException, IOException { SchemaPatternBuilder spb = new SchemaPatternBuilder(); Resolver resolver = null; EntityResolver entityResolver = getEntityResolver(); if (entityResolver != null) resolver = SAX.createResolver(entityResolver, true); SAXResolver saxResolver = new SAXResolver(resolver); Parseable parseable = new SAXParseable(new SAXSource(saxResolver.createXMLReader(), inputSource), saxResolver, eh); try { return new SchemaImpl(SchemaBuilderImpl.parse(parseable, eh, dlf, spb, false), spb); } catch (IllegalSchemaException e) { throw new SAXException("unreported schema error"); } } } VerifierFactoryLoaderImpl.java000066400000000000000000000010201225366607500351550ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarvpackage com.thaiopensource.relaxng.jarv; import org.iso_relax.verifier.VerifierFactory; import org.iso_relax.verifier.VerifierFactoryLoader; import com.thaiopensource.xml.util.WellKnownNamespaces; public class VerifierFactoryLoaderImpl implements VerifierFactoryLoader { public VerifierFactory createFactory(String schemaLanguage) { if (schemaLanguage.equals(WellKnownNamespaces.RELAX_NG) || schemaLanguage.equals(WellKnownNamespaces.RELAX_NG_0_9)) return new VerifierFactoryImpl(); return null; } } VerifierHandlerImpl.java000066400000000000000000000021601225366607500340020ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarvpackage com.thaiopensource.relaxng.jarv; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.sax.PatternValidator; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.xml.sax.CountingErrorHandler; import org.iso_relax.verifier.VerifierHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; class VerifierHandlerImpl extends PatternValidator implements VerifierHandler { private boolean complete = false; private final CountingErrorHandler ceh; VerifierHandlerImpl(Pattern pattern, ValidatorPatternBuilder builder, CountingErrorHandler ceh) { super(pattern, builder, ceh); this.ceh = ceh; } public void endDocument() throws SAXException { super.endDocument(); complete = true; } public boolean isValid() throws IllegalStateException { if (!complete) throw new IllegalStateException(); return !ceh.getHadErrorOrFatalError(); } void setErrorHandler(ErrorHandler eh) { ceh.setErrorHandler(eh); } public void reset() { super.reset(); if (ceh != null) ceh.reset(); } } jing-trang-20131210+dfsg+1/mod/rng-jarv/src/main/com/thaiopensource/relaxng/jarv/VerifierImpl.java000066400000000000000000000021101225366607500325560ustar00rootroot00000000000000package com.thaiopensource.relaxng.jarv; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.xml.sax.CountingErrorHandler; import org.iso_relax.verifier.VerifierConfigurationException; import org.iso_relax.verifier.VerifierHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; class VerifierImpl extends org.iso_relax.verifier.impl.VerifierImpl { private final VerifierHandlerImpl vhi; private boolean needReset = false; VerifierImpl(Pattern start, ValidatorPatternBuilder builder) throws VerifierConfigurationException { vhi = new VerifierHandlerImpl(start, builder, new CountingErrorHandler(errorHandler)); reader.setDTDHandler(vhi); } public VerifierHandler getVerifierHandler() throws SAXException { if (needReset) vhi.reset(); else needReset = true; return vhi; } public void setErrorHandler(ErrorHandler handler) { vhi.setErrorHandler(handler); super.setErrorHandler(handler); } } jing-trang-20131210+dfsg+1/mod/rng-jaxp/000077500000000000000000000000001225366607500174015ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/mod.xml000066400000000000000000000005001225366607500206750ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/000077500000000000000000000000001225366607500201705ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/000077500000000000000000000000001225366607500211145ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/000077500000000000000000000000001225366607500216725ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/000077500000000000000000000000001225366607500247225ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500263625ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxp/000077500000000000000000000000001225366607500273245ustar00rootroot00000000000000CompactSyntaxSchemaFactory.java000066400000000000000000000036521225366607500353640ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.compact.CompactParseable; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.xml.sax.SAX; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.validation.Constants; import com.thaiopensource.util.VoidValue; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; /** * A SchemaFactory that supports RELAX NG Compact Syntax. */ public class CompactSyntaxSchemaFactory extends SchemaFactoryImpl { /** * The String that is used to identify the schema language, when the schema language is RELAX NG Compact Syntax. * Usually XML schema languages use an XML syntax, and the schema language can be identified by the namespace URI, * but this is not the case with RELAX NG Compact Syntax. RELAX NG Compact syntax has a registered MIME type, * which is application/relax-ng-compact-syntax, so we use the URI corresponding to that. * @see javax.xml.validation.SchemaFactory#isSchemaLanguageSupported * @see javax.xml.validation.SchemaFactory#newInstance(String) */ static final public String SCHEMA_LANGUAGE = Constants.RELAXNG_COMPACT_URI; public boolean isSchemaLanguageSupported(String schemaLanguage) { return schemaLanguage.equals(SCHEMA_LANGUAGE); } protected Parseable createParseable(SAXSource source, SAXResolver saxResolver, ErrorHandler eh) { return new CompactParseable(SAX.createInput(source.getInputSource()), saxResolver.getResolver(), eh); } } SchemaFactoryImpl.java000066400000000000000000000124741225366607500334720ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.datatype.xsd.DatatypeLibraryFactoryImpl; import com.thaiopensource.datatype.xsd.regex.java.RegexEngineImpl; import com.thaiopensource.relaxng.parse.IllegalSchemaException; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.pattern.SchemaBuilderImpl; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.xml.ls.LS; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.validation.Schema2; import com.thaiopensource.validation.SchemaFactory2; import com.thaiopensource.xml.sax.DraconianErrorHandler; import com.thaiopensource.util.VoidValue; import org.relaxng.datatype.DatatypeLibraryFactory; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; import java.io.IOException; /** * A SchemaFactory that supports RELAX NG. * This class is abstract: it has two concrete subclasses, one that supports the XML syntax * and one that supports the compact syntax. * @see XMLSyntaxSchemaFactory * @see CompactSyntaxSchemaFactory */ public abstract class SchemaFactoryImpl extends SchemaFactory2 { private DatatypeLibraryFactory datatypeLibraryFactory = null; /* If this is true, then logically datatypeLibraryFactory is an instance of DatatypeLibraryLoader, but we create it lazily, so that we don't need to create it if the user specifies their own. */ private boolean defaultDatatypeLibraryFactory = true; /** * The name of the property that can be used to specify a DatatypeLibraryFactory. * The value of the property must implement org.relaxng.datatype.DatatypeLibraryFactory. * By default, a datatype library factory that supports XML Schema Datatypes is used. * If the value of this property is set to null, then only the built-in datatypes will be * supported. By default, datatype libraries will not be discovered dynamically; in order * to enable this, the value can be set to an instance of * org.relaxng.datatype.helpers.DatatypeLibraryLoader. * @see DatatypeLibraryFactory * @see org.relaxng.datatype.helpers.DatatypeLibraryLoader * @see #setProperty * @see #getProperty */ static final public String PROPERTY_DATATYPE_LIBRARY_FACTORY = "http://relaxng.org/properties/datatype-library-factory"; protected SchemaFactoryImpl() { } public Schema2 newSchema(SAXSource source) throws SAXException { Resolver resolver = null; LSResourceResolver resourceResolver = getResourceResolver(); if (resourceResolver != null) resolver = LS.createResolver(resourceResolver); SAXResolver saxResolver = new SAXResolver(resolver); ErrorHandler eh = getErrorHandler(); if (eh == null) eh = new DraconianErrorHandler(); Parseable parseable = createParseable(source, saxResolver, eh); SchemaPatternBuilder spb = new SchemaPatternBuilder(); try { return new SchemaImpl(this, spb, SchemaBuilderImpl.parse(parseable, eh, getDatatypeLibraryFactory(), spb, false)); } catch (IOException io) { // this is a truly bizarre API; why can't we just throw the IOException SAXParseException e = new SAXParseException(io.getMessage(), null, io); eh.fatalError(e); throw e; } catch (IllegalSchemaException e) { // we have already reported something for this error, so don't give it to the error handler throw new SAXException("invalid schema"); } } public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException { if (PROPERTY_DATATYPE_LIBRARY_FACTORY.equals(name)) { if (object instanceof DatatypeLibraryFactory) { datatypeLibraryFactory = (DatatypeLibraryFactory)object; defaultDatatypeLibraryFactory = false; } else throw new SAXNotSupportedException("value of \"" + PROPERTY_DATATYPE_LIBRARY_FACTORY + "\" property does not implement org.relaxng.datatype.DatatypeLibraryFactory"); } else super.setProperty(name, object); } public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (PROPERTY_DATATYPE_LIBRARY_FACTORY.equals(name)) return getDatatypeLibraryFactory(); return super.getProperty(name); } private DatatypeLibraryFactory getDatatypeLibraryFactory() { if (defaultDatatypeLibraryFactory) { datatypeLibraryFactory = new DatatypeLibraryFactoryImpl(new RegexEngineImpl()); defaultDatatypeLibraryFactory = false; } return datatypeLibraryFactory; } abstract protected Parseable createParseable(SAXSource source, SAXResolver resolver, ErrorHandler eh) throws SAXException; } jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxp/SchemaImpl.java000066400000000000000000000014211225366607500322070ustar00rootroot00000000000000package com.thaiopensource.relaxng.jaxp; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.SchemaPatternBuilder; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.validation.Schema2; import com.thaiopensource.validation.ValidatorHandler2; class SchemaImpl extends Schema2 { private final SchemaFactoryImpl factory; private final SchemaPatternBuilder spb; private final Pattern start; SchemaImpl(SchemaFactoryImpl factory, SchemaPatternBuilder spb, Pattern start) { this.factory = factory; this.spb = spb; this.start = start; } public ValidatorHandler2 newValidatorHandler() { return new ValidatorHandlerImpl(factory, start, new ValidatorPatternBuilder(spb)); } } ValidatorHandlerImpl.java000066400000000000000000000170231225366607500341600ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.relaxng.match.Matcher; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.PatternMatcher; import com.thaiopensource.relaxng.pattern.ValidatorPatternBuilder; import com.thaiopensource.relaxng.sax.Context; import com.thaiopensource.validation.ValidatorHandler2; import com.thaiopensource.xml.sax.DraconianErrorHandler; import com.thaiopensource.xml.util.Name; import org.w3c.dom.ls.LSResourceResolver; 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.SAXNotSupportedException; import org.xml.sax.SAXParseException; import javax.xml.XMLConstants; import javax.xml.validation.TypeInfoProvider; class ValidatorHandlerImpl extends ValidatorHandler2 { private Matcher matcher; static private final ErrorHandler defaultErrorHandler = new DraconianErrorHandler(); private ErrorHandler specifiedErrorHandler = null; private ErrorHandler actualErrorHandler = defaultErrorHandler; private boolean bufferingCharacters = false; private final StringBuffer charBuf = new StringBuffer(); private Locator locator = null; private final Context context; private ContentHandler contentHandler = null; private DTDHandler dtdHandler; private LSResourceResolver resourceResolver = null; private boolean secureProcessing; ValidatorHandlerImpl(SchemaFactoryImpl factory, Pattern pattern, ValidatorPatternBuilder builder) { matcher = new PatternMatcher(pattern, builder); context = new Context(); // the docs say it gets the properties of its factory, not the features secureProcessing = false; } public void reset() { bufferingCharacters = false; locator = null; matcher = matcher.start(); context.reset(); } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (bufferingCharacters) { bufferingCharacters = false; check(matcher.matchTextBeforeStartTag(charBuf.toString(), context)); } Name name = new Name(namespaceURI, localName); check(matcher.matchStartTagOpen(name, qName, context)); int len = atts.getLength(); for (int i = 0; i < len; i++) { Name attName = new Name(atts.getURI(i), atts.getLocalName(i)); String attQName = atts.getQName(i); check(matcher.matchAttributeName(attName, attQName, context)); check(matcher.matchAttributeValue(atts.getValue(i), attName, attQName, context)); } check(matcher.matchStartTagClose(name, qName, context)); if (matcher.isTextTyped()) { bufferingCharacters = true; charBuf.setLength(0); } if (contentHandler != null) contentHandler.startElement(namespaceURI, localName, qName, atts); } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (bufferingCharacters) { bufferingCharacters = false; if (charBuf.length() > 0) check(matcher.matchTextBeforeEndTag(charBuf.toString(), new Name(namespaceURI, localName), qName, context)); } check(matcher.matchEndTag(new Name(namespaceURI, localName), qName, context)); if (contentHandler != null) contentHandler.endElement(namespaceURI, localName, qName); } public void characters(char ch[], int start, int length) throws SAXException { if (bufferingCharacters) { charBuf.append(ch, start, length); return; } for (int i = 0; i < length; i++) { switch (ch[start + i]) { case ' ': case '\r': case '\t': case '\n': break; default: check(matcher.matchUntypedText(context)); return; } } } public void endDocument() throws SAXException { check(matcher.matchEndDocument()); if (contentHandler != null) contentHandler.endDocument(); } public void setDocumentLocator(Locator locator) { this.locator = locator; if (contentHandler != null) contentHandler.setDocumentLocator(locator); } public void startDocument() throws SAXException { check(matcher.matchStartDocument()); if (contentHandler != null) contentHandler.startDocument(); } public void processingInstruction(String target, String data) throws SAXException { if (contentHandler != null) contentHandler.processingInstruction(target, data); } public void skippedEntity(String name) throws SAXException { if (contentHandler != null) contentHandler.skippedEntity(name); } public void ignorableWhitespace(char[] ch, int start, int len) throws SAXException { if (contentHandler != null) contentHandler.ignorableWhitespace(ch, start, len); } private void check(boolean ok) throws SAXException { if (!ok) actualErrorHandler.error(new SAXParseException(matcher.getErrorMessage(), locator)); } public void setContentHandler(ContentHandler delegate) { this.contentHandler = delegate; } public ContentHandler getContentHandler() { return contentHandler; } public void setDTDHandler(DTDHandler dtdHandler) { this.dtdHandler = dtdHandler; } public DTDHandler getDTDHandler() { return dtdHandler; } public TypeInfoProvider getTypeInfoProvider() { return null; } public void setErrorHandler(ErrorHandler errorHandler) { this.specifiedErrorHandler = errorHandler; this.actualErrorHandler = errorHandler == null ? defaultErrorHandler : errorHandler; } public ErrorHandler getErrorHandler() { return specifiedErrorHandler; } public void setResourceResolver(LSResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } public LSResourceResolver getResourceResolver() { return resourceResolver; } public void startPrefixMapping(String prefix, String uri) throws SAXException { // namespace declarations on the start-tag shouldn't apply to the characters before the start-tag if (bufferingCharacters) { bufferingCharacters = false; check(matcher.matchTextBeforeStartTag(charBuf.toString(), context)); } context.startPrefixMapping(prefix, uri); if (contentHandler != null) contentHandler.startPrefixMapping(prefix, uri); } public void endPrefixMapping(String prefix) throws SAXException { context.endPrefixMapping(prefix); if (contentHandler != null) contentHandler.endPrefixMapping(prefix); } public void notationDecl(String name, String publicId, String systemId) throws SAXException { context.notationDecl(name, publicId, systemId); if (dtdHandler != null) dtdHandler.notationDecl(name, publicId, systemId); } public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { context.unparsedEntityDecl(name, publicId, systemId, notationName); if (dtdHandler != null) dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName); } public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) secureProcessing = value; else super.setFeature(name, value); } public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) return secureProcessing; return super.getFeature(name); } } XMLSyntaxSchemaFactory.java000066400000000000000000000031611225366607500344310ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/main/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.relaxng.parse.Parseable; import com.thaiopensource.relaxng.parse.sax.SAXParseable; import com.thaiopensource.relaxng.pattern.Pattern; import com.thaiopensource.relaxng.pattern.NameClass; import com.thaiopensource.relaxng.pattern.CommentListImpl; import com.thaiopensource.relaxng.pattern.AnnotationsImpl; import com.thaiopensource.resolver.xml.sax.SAXResolver; import com.thaiopensource.validation.Constants; import com.thaiopensource.util.VoidValue; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.Locator; import javax.xml.transform.sax.SAXSource; /** * A SchemaFactory that supports RELAX NG with the original XML syntax. */ public class XMLSyntaxSchemaFactory extends SchemaFactoryImpl { /** * The String that is used to identify the schema language, when the schema language is RELAX NG with the original * XML syntax. The String is the namespace URI for RELAX NG schemas. */ static final public String SCHEMA_LANGUAGE = Constants.RELAXNG_XML_URI; protected Parseable createParseable(SAXSource source, SAXResolver resolver, ErrorHandler eh) throws SAXException { if (source.getXMLReader() == null) source = new SAXSource(resolver.createXMLReader(), source.getInputSource()); return new SAXParseable(source, resolver, eh); } public boolean isSchemaLanguageSupported(String schemaLanguage) { return schemaLanguage.equals(SCHEMA_LANGUAGE); } } jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/000077500000000000000000000000001225366607500211475ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/000077500000000000000000000000001225366607500217255ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/000077500000000000000000000000001225366607500247555ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500264155ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/relaxng/jaxp/000077500000000000000000000000001225366607500273575ustar00rootroot00000000000000CompactSyntaxSchemaFactoryTest.java000066400000000000000000000025021225366607500362500ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import org.testng.Assert; import org.testng.annotations.Test; /** * Tests CompactSyntaxSchemaFactory. */ public class CompactSyntaxSchemaFactoryTest extends SchemaFactoryImplTest { public CompactSyntaxSchemaFactoryTest() { super(CompactSyntaxSchemaFactory.class); } @Test public void testIsSchemaLanguageSupported() { Assert.assertFalse(factory().isSchemaLanguageSupported(XMLSyntaxSchemaFactory.SCHEMA_LANGUAGE)); Assert.assertTrue(factory().isSchemaLanguageSupported(CompactSyntaxSchemaFactory.SCHEMA_LANGUAGE)); } protected String element(String name, String[] contentPatterns) { StringBuilder builder = new StringBuilder(); builder.append("element ") .append(name) .append(" {"); for (int i = 0; i < contentPatterns.length; i++) { if (i > 0) builder.append(", "); builder.append(contentPatterns[i]); } if (contentPatterns.length == 0) builder.append("empty"); builder.append("}"); return builder.toString(); } protected String attribute(String name) { return "attribute " + name + " { text }"; } protected String externalRef(String uri) { return "external \"" + uri + "\""; } protected String getLSType() { return CompactSyntaxSchemaFactory.SCHEMA_LANGUAGE; } } SchemaFactoryImplTest.java000066400000000000000000000244501225366607500343620ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.validation.LSInputImpl; import com.thaiopensource.validation.SchemaFactory2; import com.thaiopensource.xml.sax.DraconianErrorHandler; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import javax.xml.validation.ValidatorHandler; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.Writer; /** * Test SchemaFactoryImpl. */ public abstract class SchemaFactoryImplTest { protected final Class factoryClass; private static int filenameIndex = 0; protected SchemaFactoryImplTest(Class factoryClass) { this.factoryClass = factoryClass; } protected SchemaFactory2 factory() { try { return factoryClass.newInstance(); } catch (InstantiationException e) { } catch (IllegalAccessException e) { } throw new AssertionError(); } @Test(dataProvider = "valid") public void testValidCharStream(String schemaString, String docString) throws SAXException, IOException { factory().newSchema(charStreamSource(schemaString)).newValidator().validate(charStreamSource(docString)); } @Test(dataProvider = "valid") public void testValidFile(String schemaString, String docString) throws SAXException, IOException { factory().newSchema(fileSource(schemaString)).newValidator().validate(fileSource(docString)); } @DataProvider(name = "valid") protected Object[][] valid() { return new Object[][] { { createSchema("doc"), "" }, { element("doc", new String[] { attribute("att") }), "" } }; } private static SAXSource charStreamSource(String s) { return new SAXSource(new InputSource(new StringReader(s))); } private static synchronized Source fileSource(String s) throws IOException { final File file = new File("t" + filenameIndex++); Writer w = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); w.write(s); w.close(); return new StreamSource(file); } static private class CountErrorHandler extends DraconianErrorHandler { int errorCount = 0; public void error(SAXParseException e) throws SAXException { ++errorCount; } } @Test public void testErrorHandlerNoThrow() throws SAXException, IOException { SchemaFactory f = factory(); Validator v = f.newSchema(charStreamSource(createSchema("doc"))).newValidator(); CountErrorHandler eh = new CountErrorHandler() { public void error(SAXParseException e) throws SAXException { if (errorCount == 0) Assert.assertEquals(e.getLineNumber(), 2); super.error(e); } }; v.setErrorHandler(eh); Assert.assertSame(v.getErrorHandler(), eh); v.validate(charStreamSource("\n")); Assert.assertTrue(eh.errorCount > 0); } @Test(expectedExceptions = { RuntimeException.class }) public void testErrorHandlerThrowRuntime() throws SAXException, IOException { SchemaFactory f = factory(); Validator v = f.newSchema(charStreamSource(createSchema("doc"))).newValidator(); v.setErrorHandler(new DraconianErrorHandler() { public void error(SAXParseException e) throws SAXException { Assert.assertEquals(e.getLineNumber(), 2); throw new RuntimeException(); } }); v.validate(charStreamSource("\n")); throw new AssertionError(); } static class MySAXException extends SAXException { } @Test(expectedExceptions = { MySAXException.class }) public void testErrorHandlerThrowSAX() throws SAXException, IOException { SchemaFactory f = factory(); Validator v = f.newSchema(charStreamSource(createSchema("doc"))).newValidator(); v.setErrorHandler(new DraconianErrorHandler() { public void error(SAXParseException e) throws SAXException { Assert.assertEquals(e.getLineNumber(), 2); throw new MySAXException(); } }); v.validate(charStreamSource("\n")); throw new AssertionError(); } @Test public void testInstanceResourceResolver() throws SAXException, IOException { SchemaFactory f = factory(); Validator v = f.newSchema(charStreamSource(element("doc", element("inner")))).newValidator(); Assert.assertNull(v.getResourceResolver()); LSResourceResolver rr = new LSResourceResolver() { public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { // In Java 5 Xerces absolutized the systemId relative to the current directory int slashIndex = systemId.lastIndexOf('/'); if (slashIndex >= 0) systemId = systemId.substring(slashIndex + 1); Assert.assertEquals(systemId, "e.xml"); Assert.assertEquals(type, "http://www.w3.org/TR/REC-xml"); LSInput in = new LSInputImpl(); in.setStringData(""); return in; } }; v.setResourceResolver(rr); Assert.assertSame(v.getResourceResolver(), rr); v.validate(charStreamSource(" ]>&e;")); } @Test public void testSchemaResourceResolver() throws SAXException, IOException { SchemaFactory f = factory(); Assert.assertNull(f.getResourceResolver()); LSResourceResolver rr = new LSResourceResolver() { public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { Assert.assertEquals(systemId, "myschema"); Assert.assertEquals(type, getLSType()); Assert.assertNull(baseURI); Assert.assertNull(namespaceURI); Assert.assertNull(publicId); LSInput in = new LSInputImpl(); in.setStringData(createSchema("doc")); return in; } }; f.setResourceResolver(rr); Assert.assertSame(f.getResourceResolver(), rr); Validator v = f.newSchema(charStreamSource(externalRef("myschema"))).newValidator(); v.validate(charStreamSource("")); } @Test(expectedExceptions = { UnsupportedOperationException.class }) public void testNewSchemaNoArgs() throws SAXException { factory().newSchema(); } @DataProvider(name = "supportedFeatures") Object[][] createSupportedFeatures() { return new Object[][] { { XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.FALSE } }; } @Test(dataProvider = "supportedFeatures") public void testSupportedFeatures(String feature, Boolean defaultValueObj) throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); boolean defaultValue = defaultValueObj; Assert.assertEquals(f.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING), defaultValue); f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !defaultValue); Assert.assertEquals(f.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING), !defaultValue); } @Test(dataProvider = "supportedFeatures") public void testFeatureInheritance(String feature, Boolean defaultValueObj) throws SAXException, SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); boolean defaultValue = defaultValueObj; Assert.assertEquals(f.getFeature(feature), defaultValue); f.setFeature(feature, !defaultValue); ValidatorHandler vh = f.newSchema(charStreamSource(createSchema("doc"))).newValidatorHandler(); // the docs say that only properties are inherited by the ValidatorHandler Assert.assertEquals(vh.getFeature(feature), defaultValue); } @Test(expectedExceptions = { SAXNotRecognizedException.class }) public void testUnrecognizedGetFeature() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.getFeature("http://thaiopensource.com/features/no-such-feature"); throw new AssertionError(); } @Test(expectedExceptions = { SAXNotRecognizedException.class }) public void testUnrecognizedSetFeature() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.setFeature("http://thaiopensource.com/features/no-such-feature", false); throw new AssertionError(); } @Test(expectedExceptions = { NullPointerException.class }) public void testNullGetFeature() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.getFeature(null); throw new AssertionError(); } @Test(expectedExceptions = { NullPointerException.class }) public void testNullSetFeature() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.setFeature(null, true); throw new AssertionError(); } @Test(expectedExceptions = { SAXNotRecognizedException.class }) public void testUnrecognizedSetProperty() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.setProperty("http://thaiopensource.com/properties-no-such-property", null); throw new AssertionError(); } @Test(expectedExceptions = { SAXNotRecognizedException.class }) public void testUnrecognizedGetProperty() throws SAXNotRecognizedException, SAXNotSupportedException { SchemaFactory f = factory(); f.getProperty("http://thaiopensource.com/properties/no-such-property"); throw new AssertionError(); } private String createSchema(String rootElement) { return element(rootElement); } private String element(String name) { return element(name, new String[] { }); } private String element(String name, String contentPattern) { return element(name, new String[] { contentPattern }); } abstract protected String element(String name, String[] contentPatterns); abstract protected String attribute(String name); abstract protected String externalRef(String uri); abstract protected String getLSType(); } XMLSyntaxSchemaFactoryTest.java000066400000000000000000000030521225366607500353230ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-jaxp/src/test/com/thaiopensource/relaxng/jaxppackage com.thaiopensource.relaxng.jaxp; import com.thaiopensource.xml.util.WellKnownNamespaces; import org.testng.Assert; import org.testng.annotations.Test; import javax.xml.XMLConstants; /** * */ public class XMLSyntaxSchemaFactoryTest extends SchemaFactoryImplTest { private static final String NS = XMLConstants.RELAXNG_NS_URI; public XMLSyntaxSchemaFactoryTest() { super(XMLSyntaxSchemaFactory.class); } @Test public void testIsSchemaLanguageSupported() { Assert.assertTrue(factory().isSchemaLanguageSupported(NS)); Assert.assertTrue(factory().isSchemaLanguageSupported(XMLSyntaxSchemaFactory.SCHEMA_LANGUAGE)); Assert.assertTrue(factory().isSchemaLanguageSupported(WellKnownNamespaces.RELAX_NG)); Assert.assertFalse(factory().isSchemaLanguageSupported(CompactSyntaxSchemaFactory.SCHEMA_LANGUAGE)); } protected String element(String name, String[] contentPatterns) { StringBuilder builder = new StringBuilder(); builder.append(""); for (int i = 0; i < contentPatterns.length; i++) builder.append(contentPatterns[i]); if (contentPatterns.length == 0) builder.append(""); builder.append(""); return builder.toString(); } protected String attribute(String name) { return ""; } protected String externalRef(String uri) { return ""; } protected String getLSType() { return NS; } } jing-trang-20131210+dfsg+1/mod/rng-parse/000077500000000000000000000000001225366607500175515ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/mod.xml000066400000000000000000000016651225366607500210620ustar00rootroot00000000000000 jing-trang-20131210+dfsg+1/mod/rng-parse/src/000077500000000000000000000000001225366607500203405ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/000077500000000000000000000000001225366607500212645ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/000077500000000000000000000000001225366607500220425ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/000077500000000000000000000000001225366607500250725ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/000077500000000000000000000000001225366607500265325ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/000077500000000000000000000000001225366607500276445ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Annotations.java000066400000000000000000000010511225366607500330010ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; /** * Includes attributes and child elements before any RELAX NG element. */ public interface Annotations> { void addAttribute(String ns, String localName, String prefix, String value, L loc) throws BuildException; void addElement(EA ea) throws BuildException; /* * Adds comments following the last initial child element annotation. */ void addComment(CL comments) throws BuildException; void addLeadingComment(CL comments) throws BuildException; } BuildException.java000066400000000000000000000017161225366607500333530ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; import com.thaiopensource.resolver.ResolverException; import org.xml.sax.SAXException; public class BuildException extends RuntimeException { private final Throwable cause; public BuildException(Throwable cause) { if (cause == null) throw new NullPointerException("null cause"); this.cause = cause; } public Throwable getCause() { return cause; } public static BuildException fromSAXException(SAXException e) { Exception inner = e.getException(); if (inner instanceof BuildException) return (BuildException)inner; return new BuildException(e); } public static BuildException fromResolverException(ResolverException e) { if (e.getMessage() == null) { Throwable t = e.unwrap(); if (t != null) { if (t instanceof BuildException) throw (BuildException)t; throw new BuildException(t); } } throw new BuildException(e); } } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/CommentList.java000066400000000000000000000002151225366607500327430ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface CommentList { void addComment(String value, L loc) throws BuildException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Context.java000066400000000000000000000003251225366607500321330ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; import org.relaxng.datatype.ValidationContext; import java.util.Set; public interface Context extends ValidationContext { Set prefixes(); Context copy(); } DataPatternBuilder.java000066400000000000000000000006431225366607500341510ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public interface DataPatternBuilder, A extends Annotations> { void addParam(String name, String value, Context context, String ns, L loc, A anno) throws BuildException; void annotation(EA ea); P makePattern(L loc, A anno) throws BuildException; P makePattern(P except, L loc, A anno) throws BuildException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Div.java000066400000000000000000000003571225366607500312360ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface Div, A extends Annotations> extends GrammarSection { void endDiv(L loc, A anno) throws BuildException; } ElementAnnotationBuilder.java000066400000000000000000000004261225366607500353650ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public interface ElementAnnotationBuilder> extends Annotations { void addText(String value, L loc, CL comments) throws BuildException; EA makeElementAnnotation() throws BuildException; } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Grammar.java000066400000000000000000000004141225366607500320740ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface Grammar, A extends Annotations> extends GrammarSection, Scope { P endGrammar(L loc, A anno) throws BuildException; } GrammarSection.java000066400000000000000000000015401225366607500333430ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public interface GrammarSection, A extends Annotations> { static final class Combine { private final String name; private Combine(String name) { this.name = name; } final public String toString() { return name; } } static final Combine COMBINE_CHOICE = new Combine("choice"); static final Combine COMBINE_INTERLEAVE = new Combine("interleave"); static final String START = "#start"; void define(String name, Combine combine, P pattern, L loc, A anno) throws BuildException; void topLevelAnnotation(EA ea) throws BuildException; void topLevelComment(CL comments) throws BuildException; Div makeDiv(); /* * Returns null if already in an include. */ Include makeInclude(); } IllegalSchemaException.java000066400000000000000000000001451225366607500350010ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public class IllegalSchemaException extends Exception { } jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parse/Include.java000066400000000000000000000004761225366607500321010ustar00rootroot00000000000000package com.thaiopensource.relaxng.parse; public interface Include, A extends Annotations> extends GrammarSection { void endInclude(String href, String base, String ns, L loc, A anno) throws BuildException, IllegalSchemaException; } IncludedGrammar.java000066400000000000000000000004341225366607500334670ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; public interface IncludedGrammar, A extends Annotations> extends GrammarSection, Scope { P endIncludedGrammar(L loc, A anno) throws BuildException; } ParseReceiver.java000066400000000000000000000010001225366607500331560ustar00rootroot00000000000000jing-trang-20131210+dfsg+1/mod/rng-parse/src/main/com/thaiopensource/relaxng/parsepackage com.thaiopensource.relaxng.parse; import org.xml.sax.XMLReader; import org.xml.sax.SAXException; public interface ParseReceiver, A extends Annotations> extends SubParser { ParsedPatternFuture