Commits

Anonymous committed 35fa6be Draft

added validation to semanticDocument

Comments (0)

Files changed (20)

 		<dependency>
 			<groupId>xom</groupId>
 			<artifactId>xom</artifactId>
-			<version>1.1</version>
+			<version>1.2.5</version>
 		</dependency>
 		<dependency>
 			<groupId>batik</groupId>

src/main/java/org/xmlcml/graphics/misc/LSQ_Circle.html

+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<meta name="Least Squares Circle" content="Least Squares Approximation">
+<title>Least Squares Circle</title>
+</head>
+<body>
+<p>
+</p><h1>Least Squares Circle</h1>
+<p>
+</p><h3>Approximation without constraints</h3>
+<p>
+We want to find a circle that fits the given set of points best in a sense of 
+least squares approximation. Let a circle be represented as
+<br>
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+x<sup>2</sup>+y<sup>2</sup>+2Ax+2By+C=0.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+Then, the center of the circle is (<font face="symbol">-</font>A,<font face="symbol">-</font>B) and the radius is
+<br>
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+r=</td><td align="center" nowrap="nowrap">
+</td><td align="left" nowrap="nowrap">&nbsp;&nbsp;_______<br><font size="+1">
+<font face="symbol">�</font></font>A<sup>2</sup>+B<sup>2</sup><font face="symbol">-
+</font>C<br>&nbsp;<br></td><td align="center" nowrap="nowrap">
+.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+Assume this circle is used to approximate the given set of points <b>p</b><sub>i</sub> 
+(i=1,2,<font face="symbol">�</font>,n).
+Then, the squared error with respect to <b>p</b><sub>i</sub>=(x<sub>i</sub>,y<sub>i</sub>) is 
+(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2Ax<sub>i</sub>+2By<sub>i</sub>+C)<sup>2</sup>.
+Accordingly, the total squared error is given by
+<br>
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+<font face="symbol">f</font> = </td><td align="center" nowrap="nowrap">
+<font face="symbol" size="+3">�<br></font>
+</td><td nowrap="nowrap">(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2Ax<sub>i</sub>+2By<sub>i</sub>+C)<sup>2</sup>.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+We thus want to find A,B,C such that <font face="symbol">f</font> is minimized, which is equivalent to solving the 
+following system of linear equations:
+<br>
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+</td><td align="center" nowrap="nowrap">
+<font face="symbol">�</font><font face="symbol">f</font><hr noshade="noshade"><font face="symbol">�</font>A<br></td><td align="center" nowrap="nowrap">
+,&nbsp;&nbsp;&nbsp; </td><td align="center" nowrap="nowrap">
+<font face="symbol">�</font><font face="symbol">f</font><hr noshade="noshade"><font face="symbol">�</font>B<br></td><td align="center" nowrap="nowrap">
+,&nbsp;&nbsp;&nbsp;</td><td align="center" nowrap="nowrap">
+<font face="symbol">�</font><font face="symbol">f</font><hr noshade="noshade"><font face="symbol">�</font>C<br></td><td align="center" nowrap="nowrap">
+.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+Explicitly, we need to solve
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<font face="symbol">�</font>x<sub>i</sub><sup>2</sup> A+2<font face="symbol">�</font>x<sub>i</sub>y<sub>i</sub> B+<font face="symbol">�</font>x<sub>i</sub> C+<font face="symbol">�</font>(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>)x<sub>i</sub>=0
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<font face="symbol">�</font>x<sub>i</sub>y<sub>i</sub> A+2<font face="symbol">�</font>y<sub>i</sub><sup>2</sup> B+<font face="symbol">�</font>y<sub>i</sub> C+<font face="symbol">�</font>(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>)y<sub>i</sub>=0
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<font face="symbol">�</font>x<sub>i</sub> A+2<font face="symbol">�</font>y<sub>i</sub> B+n C+<font face="symbol">�</font>(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>)=0
+
+</p><p>
+</p><h3>Approximation with two constraints</h3>
+<p>
+We want to find a circle
+<br>
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+x<sup>2</sup>+y<sup>2</sup>+2Ax+2By+C=0 </td></tr></tbody></table></td>
+<td width="15%"> (2<font face="symbol">-</font>1)</td></tr></tbody></table>
+
+
+such that it interpolates two points (x<sub>1</sub>, y<sub>1</sub>) and (x<sub>2</sub>, y<sub>2</sub>) and approximates the 
+remaining given points in a sense of least squares approximation.
+By substituting (x<sub>1</sub>, y<sub>1</sub>) and (x<sub>2</sub>, y<sub>2</sub>) into the above equation, we have
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+x<sub>1</sub><sup>2</sup>+y<sub>1</sub><sup>2</sup>+2x<sub>1</sub>A+2y<sub>1</sub>B+C=0</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+x<sub>2</sub><sup>2</sup>+y<sub>2</sub><sup>2</sup>+2x<sub>2</sub>A+2y<sub>2</sub>B+C=0</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+Subtracting the first from the second equation gives
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+2(x<sub>1</sub><font face="symbol">-</font>x<sub>2</sub>)A+2(y<sub>1</sub><font face="symbol">-</font>y<sub>2</sub>)B+x<sub>1</sub><sup>2</sup>+y<sub>1</sub><sup>2</sup><font face="symbol">-</font>x<sub>2</sub><sup>2</sup><font face="symbol">-</font>y<sub>2</sub><sup>2</sup>=0.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+Assume that <font face="symbol">|</font>x<sub>1</sub><font face="symbol">-</font>x<sub>2</sub><font face="symbol">|</font> &gt; <font face="symbol">|</font>y<sub>1</sub><font face="symbol">-</font>y<sub>2</sub><font face="symbol">|</font>. Then, we may express A in terms of B to reduce numerical 
+noise, i.e.,
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+A=</td><td align="center" nowrap="nowrap">
+y<sub>1</sub><font face="symbol">-</font>y<sub>2</sub><hr noshade="noshade">x<sub>2</sub><font face="symbol">-</font>x<sub>1</sub><br></td><td align="center" nowrap="nowrap">
+B+</td><td align="center" nowrap="nowrap">
+x<sub>1</sub><sup>2</sup>+y<sub>1</sub><sup>2</sup><font face="symbol">-</font>x<sub>2</sub><sup>2</sup><font face="symbol">-</font>y<sub>2</sub><sup>2</sup><hr noshade="noshade">2(x<sub>2</sub><font face="symbol">-</font>x<sub>1</sub>)<br></td><td align="center" nowrap="nowrap">
+=<font face="symbol">a</font>B +<font face="symbol">b</font>.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+Replacing A in (2<font face="symbol">-</font>1) gives
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+f(B,C,x,y)=2(x<font face="symbol">a</font>+y)B+C+x<sup>2</sup>+y<sup>2</sup>+2x<font face="symbol">b</font> = 0.</td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+Let <font face="symbol">f</font>(B,C,x<sub>i</sub>,y<sub>i</sub>)=<font face="symbol">�</font>f<sup>2</sup>(B,C,x<sub>i</sub>,y<sub>i</sub>). We then want to find B and C such that 
+<font face="symbol">f</font> is minimized, which is equivalent to solving the following equations:
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[(<font face="symbol">d</font><font face="symbol">f</font>)/(<font face="symbol">d</font>B)]=2<font face="symbol">�</font>[2(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>)B+C+x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2x<sub>i</sub><font face="symbol">b</font>]2(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>)=0
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[(<font face="symbol">d</font><font face="symbol">f</font>)/(<font face="symbol">d</font>C)]=2<font face="symbol">�</font>[2(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>)B+C+x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2x<sub>i</sub><font face="symbol">b</font>]=0
+
+</p><p>
+Let 
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a<sub>00</sub>=4<font face="symbol">�</font>(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>)<sup>2</sup>,
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a<sub>01</sub>=a<sub>10</sub>=2<font face="symbol">�</font>(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>), 
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a<sub>11</sub>=n, 
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b<sub>0</sub>=<font face="symbol">-</font>2<font face="symbol">�</font>(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2x<sub>i</sub><font face="symbol">b</font>)(x<sub>i</sub><font face="symbol">a</font>+y<sub>i</sub>), and 
+
+</p><p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b<sub>1</sub>=<font face="symbol">-</font><font face="symbol">�</font>(x<sub>i</sub><sup>2</sup>+y<sub>i</sub><sup>2</sup>+2x<sub>i</sub><font face="symbol">b</font>).
+
+</p><p>
+Then, the above system of equations can be written as
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+a<sub>00</sub>B+a<sub>01</sub>C=b<sub>0</sub></td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+
+</p><p>
+
+<table border="0" width="100%"><tbody><tr><td>
+<table align="center"><tbody><tr><td align="center" nowrap="nowrap">
+a<sub>10</sub>B+a<sub>11</sub>C=b<sub>1</sub></td></tr></tbody></table>
+</td></tr></tbody></table>
+
+
+Solving the above equations gives a circle whose center is (<font face="symbol">-</font>A,<font face="symbol">-</font>B) and radius 
+<font face="symbol">�</font>[(A<sup>2</sup>+B<sup>2</sup>+C)].
+
+</p><p>
+In the case where <font face="symbol">|</font>x<sub>1</sub><font face="symbol">-</font>x<sub>2</sub><font face="symbol">|</font> &lt; <font face="symbol">|</font>y<sub>1</sub><font face="symbol">-</font>y<sub>2</sub><font face="symbol">|</font>, we may express B in terms A and obtain the 
+circle similarly.
+</p><p>
+</p><center><a href="http://infogoaround.org/BookSite.html">RETURN</a>
+
+
+
+</center></body></html>

src/main/java/org/xmlcml/graphics/misc/LeastSquaresFitting.pdf

Binary file added.

src/main/java/org/xmlcml/graphics/misc/circle_fit.pdf

Binary file added.

src/main/java/org/xmlcml/graphics/misc/gander.pdf

Binary file added.

src/main/java/org/xmlcml/graphics/misc/leastSquaresCircle.txt

+Least Squares Circle
+
+Approximation without constraints
+We want to find a circle that fits the given set of points best in a sense of least squares approximation. Let a circle be represented as 
+x2+y2+2Ax+2By+C=0. 
+ 
+Then, the center of the circle is (-A,-B) and the radius is 
+r=    _______
+�A2+B2- C
+ 
+ . 
+ 
+Assume this circle is used to approximate the given set of points pi (i=1,2,�,n). Then, the squared error with respect to pi=(xi,yi) is (xi2+yi2+2Axi+2Byi+C)2. Accordingly, the total squared error is given by 
+f =  �
+ (xi2+yi2+2Axi+2Byi+C)2. 
+ 
+We thus want to find A,B,C such that f is minimized, which is equivalent to solving the following system of linear equations: 
+ �f
+--------------------------------------------------------------------------------
+�A
+ ,     �f
+--------------------------------------------------------------------------------
+�B
+ ,    �f
+--------------------------------------------------------------------------------
+�C
+ . 
+ 
+Explicitly, we need to solve 
+
+       2�xi2 A+2�xiyi B+�xi C+�(xi2+yi2)xi=0 
+
+       2�xiyi A+2�yi2 B+�yi C+�(xi2+yi2)yi=0 
+
+       2�xi A+2�yi B+n C+�(xi2+yi2)=0 
+
+
+Approximation with two constraints
+We want to find a circle 
+x2+y2+2Ax+2By+C=0  
+ (2-1) 
+such that it interpolates two points (x1, y1) and (x2, y2) and approximates the remaining given points in a sense of least squares approximation. By substituting (x1, y1) and (x2, y2) into the above equation, we have 
+
+x12+y12+2x1A+2y1B+C=0 
+ 
+
+
+x22+y22+2x2A+2y2B+C=0 
+ 
+Subtracting the first from the second equation gives 
+
+2(x1-x2)A+2(y1-y2)B+x12+y12-x22-y22=0. 
+ 
+Assume that |x1-x2| > |y1-y2|. Then, we may express A in terms of B to reduce numerical noise, i.e., 
+
+A= y1-y2
+--------------------------------------------------------------------------------
+x2-x1
+ B+ x12+y12-x22-y22
+--------------------------------------------------------------------------------
+2(x2-x1)
+ =aB +b. 
+ 
+Replacing A in (2-1) gives 
+
+f(B,C,x,y)=2(xa+y)B+C+x2+y2+2xb = 0. 
+ 
+Let f(B,C,xi,yi)=�f2(B,C,xi,yi). We then want to find B and C such that f is minimized, which is equivalent to solving the following equations: 
+
+       [(df)/(dB)]=2�[2(xia+yi)B+C+xi2+yi2+2xib]2(xia+yi)=0 
+
+       [(df)/(dC)]=2�[2(xia+yi)B+C+xi2+yi2+2xib]=0 
+
+Let 
+
+       a00=4�(xia+yi)2, 
+
+       a01=a10=2�(xia+yi), 
+
+       a11=n, 
+
+       b0=-2�(xi2+yi2+2xib)(xia+yi), and 
+
+       b1=-�(xi2+yi2+2xib). 
+
+Then, the above system of equations can be written as 
+
+a00B+a01C=b0 
+ 
+
+
+a10B+a11C=b1 
+ 
+Solving the above equations gives a circle whose center is (-A,-B) and radius �[(A2+B2+C)]. 
+
+In the case where |x1-x2| < |y1-y2|, we may express B in terms A and obtain the circle similarly. 
+
+
+RETURN 

src/main/java/org/xmlcml/graphics/paths/PathAnalyzer.java

 import org.xmlcml.cml.base.CMLConstants;
 import org.xmlcml.cml.base.CMLUtil;
 import org.xmlcml.euclid.Axis.Axis2;
-import org.xmlcml.euclid.Point2;
 import org.xmlcml.euclid.Real2;
+import org.xmlcml.euclid.Real2Array;
 import org.xmlcml.euclid.Real2Range;
+import org.xmlcml.euclid.RealArray;
 import org.xmlcml.euclid.RealArray.Monotonicity;
 import org.xmlcml.euclid.RealRange;
 import org.xmlcml.graphics.control.page.Chunk;
 import org.xmlcml.graphics.pdf2svg.BoundingBoxManager.BoxEdge;
 import org.xmlcml.graphics.pdf2svg.PDF2SVGUtil;
 import org.xmlcml.graphics.pdf2svg.StyleManager;
-import org.xmlcml.graphics.svg.LinePrimitive;
 import org.xmlcml.graphics.svg.MovePrimitive;
 import org.xmlcml.graphics.svg.SVGCircle;
 import org.xmlcml.graphics.svg.SVGElement;
 			}
 		}
 	}
+
+	public static SVGCircle findCircleFromPoints(Real2Array r2a, double eps) {
+		SVGCircle circle = null;
+		if (r2a == null || r2a.size() < 3) {
+			//
+		} else if (r2a.size() == 3) {
+			circle = findCircleFrom3Points(r2a.get(0), r2a.get(1), r2a.get(2), eps);
+		} else {
+			RealArray x2y2Array = new RealArray();
+			RealArray xArray = new RealArray();
+			RealArray yArray = new RealArray();
+			for (int i = 0; i < r2a.size(); i++) {
+				Real2 point = r2a.get(i);
+				double x = point.x;
+				double y = point.y;
+				x2y2Array.addElement(x * x + y * y);
+				xArray.addElement(x);
+				yArray.addElement(y);
+			}
+			Real2Range bbox =r2a.getRange2();
+			// check if scatter in both directions
+			if (bbox.getXRange().getRange() > eps && bbox.getYRange().getRange() > eps) {
+				// don't lnow the distribution and can't afford to find all triplets
+				// so find the extreme points
+				Real2 minXPoint = r2a.getPointWithMinimumX();
+				Real2 maxXPoint = r2a.getPointWithMaximumX();
+				Real2 minYPoint = r2a.getPointWithMinimumY();
+				Real2 maxYPoint = r2a.getPointWithMaximumY();
+			}
+		}
+		return circle;
+	}
 }

src/main/java/org/xmlcml/graphics/pdf2svg/DocumentValidator.java

+package org.xmlcml.graphics.pdf2svg;
+
+import java.io.File;
+import java.io.InputStream;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.xml.utils.DefaultErrorHandler;
+import org.junit.Assert;
+
+/** validates semantic document
+ * (or possibly other XML files)
+ * @author pm286
+ *
+ */
+public class DocumentValidator {
+
+	public static String SCHEMA_PATH = "semanticDocument.xsd";
+	
+	public static void validateDocument(String schemaResourcePath, File semanticDocumentFile) {
+		try {
+			InputStream SCHEMA_STREAM = DocumentValidator.class.getResourceAsStream(SCHEMA_PATH);
+			StreamSource SCHEMA_SOURCE = new StreamSource(SCHEMA_STREAM);
+			
+			final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+			factory.setNamespaceAware(true);
+			SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+			Schema schema = sf.newSchema(SCHEMA_SOURCE);
+			factory.setSchema(schema);
+			DocumentBuilder builder = factory.newDocumentBuilder();
+			builder.setErrorHandler(new DefaultErrorHandler());	
+			builder.parse(semanticDocumentFile);
+		} catch (Exception e) {
+			throw new RuntimeException("Cannot validate: "+semanticDocumentFile, e);
+		}
+	}
+}

src/main/resources/org/xmlcml/graphics/pdf2svg/semanticDocument.xsd

+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="unqualified" 
+	xmlns="http://www.xml-cml.org/schema/ami2"
+	targetNamespace="http://www.xml-cml.org/schema/ami2">
+
+	<xsd:element name="semanticDocument">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element ref="fontManager" minOccurs="0"/>
+				<xsd:element ref="documentIterator" />
+			</xsd:sequence>
+			<xsd:attribute name="debug" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="fontManager">
+		<xsd:complexType>
+			<xsd:attribute name="name" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="filename" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="documentIterator">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element ref="documentActionList" />
+			</xsd:sequence>
+			<xsd:attribute name="max" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="skipIfExists" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="documentActionList">
+		<xsd:complexType>
+		    <xsd:sequence>
+		      <xsd:element ref="documentReader" minOccurs="0"/>
+		      <xsd:element ref="pageIterator" minOccurs="0"/>
+		      <xsd:element ref="documentWriter" minOccurs="0"/>
+			</xsd:sequence>
+			<xsd:attribute name="outDir" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="skipIfExists" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!-- 
+      <documentReader filename="${d.rawDirectory}" format="svgPages"/>
+ -->
+	<xsd:element name="documentReader">
+		<xsd:complexType>
+		    <xsd:sequence>
+			</xsd:sequence>
+			<xsd:attribute name="filename" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="format" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+	
+<!-- 
+      <documentWriter filename="${d.outDir}" format="htmlMenu" regex="((.*chunk.*\.xml)|(.*figure.*\.svg))"/>
+ -->	
+	<xsd:element name="documentWriter">
+		<xsd:complexType>
+		    <xsd:sequence>
+			</xsd:sequence>
+			<xsd:attribute name="filename" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="format" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="regex" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+	
+	<xsd:element name="pageIterator">
+		<xsd:complexType>
+		    <xsd:sequence>
+		      <xsd:element ref="pageAnalyzer"/>
+			</xsd:sequence>
+			<xsd:attribute name="timeout" type="xsd:double"></xsd:attribute>
+			<xsd:attribute name="maxByte" type="xsd:double"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="pageAnalyzer">
+		<xsd:complexType>
+		    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+		        <xsd:element ref="pageWriter" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="pageVariable" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="pageNormalizer" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="pageStyleProcessor" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="pathNormalizer" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="whitespaceChunker" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="deleteNodes" minOccurs="0" maxOccurs="unbounded"/>
+		        <xsd:element ref="chunkAnalyzer" minOccurs="0" maxOccurs="unbounded"/>
+			</xsd:choice>
+			<xsd:attribute name="timeout" type="xsd:double"></xsd:attribute>
+			<xsd:attribute name="maxMbyte" type="xsd:double"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!-- 
+          <pageWriter filename="${p.root}start.svg"/>
+ -->
+	<xsd:element name="pageWriter">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="filename" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!-- 
+          <pageVariable name="p.root" value="${d.outDir}/${p.page}"/>
+ -->
+	<xsd:element name="pageVariable">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="name" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="value" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!--
+           <pageNormalizer 
+              normalizeHighCodePoints="true"
+              denormalizeFontSizes="true"
+              removeUnwantedAttributes="true" 
+              applyAndRemoveCumulativeTransforms="true"
+              removeImageData="true"
+              cleanSVGStyles="true"
+              canRotateLandscape="true"
+              removeUnitTransforms="true"
+              formatDecimalPlaces="3"/>
+ -->
+	<xsd:element name="pageNormalizer">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="normalizeHighCodePoints" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="denormalizeFontSizes" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeUnwantedAttributes" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="applyAndRemoveCumulativeTransforms" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeImageData" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="cleanSVGStyles" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="canRotateLandscape" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeUnitTransforms" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="formatDecimalPlaces" type="xsd:integer"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!-- 
+          <pageStyleProcessor translateClipPathsToPhysicalStyles="true" removeDefs="true"/> 
+          I suspect this is obsolete
+ -->
+	<xsd:element name="pageStyleProcessor">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="translateClipPathsToPhysicalStyles" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeDefs" type="xsd:boolean"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+<!-- 
+          <pathNormalizer 
+              removeDuplicatePaths="true" 
+              createHigherPrimitives="true" 
+              removeEmptySVGG="true" 
+              minLinesInPolyline="8"
+              joinPolylines="true" 
+              enforceVisibility="true"
+              />
+              -->
+	<xsd:element name="pathNormalizer">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="removeDuplicatePaths" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="createHigherPrimitives" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeEmptySVGG" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="minLinesInPolyline" type="xsd:integer"></xsd:attribute>
+			<xsd:attribute name="joinPolylines" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="enforceVisibility" type="xsd:boolean"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+              <!-- 
+          <whitespaceChunker depth="3"/>
+          -->
+	<xsd:element name="whitespaceChunker">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="depth" type="xsd:integer"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+          <!-- 
+          <deleteNodes xpath="//svg:rect[@title='leafNodes']"/>
+          -->
+	<xsd:element name="deleteNodes">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="xpath" type="xsd:string"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+          <!-- 
+          <chunkAnalyzer xpath="//svg:g[@LEAF]" 
+              subSup="true" 
+              removeNumericTSpans="true"
+              splitAtSpaces="true"/>
+              -->
+	<xsd:element name="chunkAnalyzer">
+		<xsd:complexType>
+		    <xsd:sequence>
+		    </xsd:sequence>
+			<xsd:attribute name="xpath" type="xsd:string"></xsd:attribute>
+			<xsd:attribute name="subSup" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="removeNumericTSpans" type="xsd:boolean"></xsd:attribute>
+			<xsd:attribute name="splitAtSpaces" type="xsd:boolean"></xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+</xsd:schema>

src/main/resources/org/xmlcml/graphics/styles/basic.xml

-<semanticDocument debug="true">
+<semanticDocument debug="true" xmlns="http://www.xml-cml.org/schema/ami2">
+  <fontManager name="simpleFont" filename="src/main/resources/org/xmlcml/graphics/font/simpleFont.xml"/>
   <documentIterator max="999" skipIfExists="raw">
     <documentActionList outDir="${d.rawDirectory}/../out" skipIfExists="${d.outDir}">
-      <fontManager name="simpleFont" filename="src/main/resources/org/xmlcml/graphics/font/simpleFont.xml"/>
       <documentReader filename="${d.rawDirectory}" format="svgPages"/>
-      <pageSelector/>
       <pageIterator>
         <pageAnalyzer timeout="15000" maxMbyte="5.0">
           <pageVariable name="p.root" value="${d.outDir}/${p.page}"/>
           <pageWriter filename="${p.root}start.svg"/>
           <pageNormalizer 
-              denormalizeG="true"
               normalizeHighCodePoints="true"
               denormalizeFontSizes="true"
               removeUnwantedAttributes="true" 
           <pageWriter filename="target/textChunker99.svg"/>              
           <chunkAnalyzer xpath="//svg:g[@LEAF]" 
               subSup="true" 
-              removeNumericTSpans="true"/>
+              removeNumericTSpans="true"
               splitAtSpaces="true"/>
           <pageWriter filename="target/subSup.svg"/>
           <deleteNodes xpath="//@*[local-name()='oldFontSize' or local-name()='physicalStyle']"/>

src/test/java/org/xmlcml/graphics/font/TestEquivalence.java

+package org.xmlcml.graphics.font;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import nu.xom.Builder;
+import nu.xom.Element;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TestEquivalence {
+
+	private static final String EQUIVALENCE1 = FontManager.packageBase+"/"+"outlineFonts/font1/equivalences1.xml";
+	private static final String FONT1ITALIC = FontManager.packageBase+"/"+"outlineFonts/font1/italic.xml";
+	private FontManager fontManager;
+	private String equivalenceS;
+	private Equivalence equiv;
+
+//	@Before
+//	@Ignore
+//	public void setUp() {
+//		fontManager = new FontManager();
+//		equivalenceS = "" +
+//				"<equivalence id='italic1'>" +
+//				"  <text fontName='font1-italic'>Ra</text>" +
+//				"  <pathList>" +
+//				"    <path d='M327.397 218.898 L328.024 215.899 L329.074 215.899 C329.433 215.899 329.693 215.936 329.854 216.008 C330.012 216.08 330.168 216.232 330.322 216.461 C330.546 216.793 330.745 217.186 330.92 217.64 L331.404 218.898 L332.413 218.898 L331.898 217.626 C331.725 217.202 331.497 216.793 331.215 216.397 C331.089 216.222 330.903 216.044 330.657 215.863 C331.46 215.755 332.039 215.52 332.4 215.158 C332.759 214.796 332.938 214.341 332.938 213.791 C332.938 213.397 332.856 213.072 332.692 212.814 C332.527 212.557 332.301 212.381 332.013 212.287 C331.724 212.192 331.3 212.146 330.741 212.146 L327.908 212.146 L326.494 218.898 L327.397 218.898 ZM328.654 212.888 L330.857 212.888 C331.203 212.888 331.448 212.914 331.593 212.967 C331.737 213.018 331.855 213.117 331.942 213.264 C332.032 213.41 332.075 213.58 332.075 213.776 C332.075 214.011 332.017 214.228 331.898 214.431 C331.779 214.634 331.609 214.794 331.39 214.914 C331.171 215.034 330.893 215.111 330.552 215.145 C330.376 215.16 330 215.168 329.424 215.168 L328.176 215.168 L328.654 212.888' style='clip-path:url(#clipPath1); stroke:none;'/>" +
+//				"    <path d='M336.571 218.898 L337.414 218.898 C337.347 218.609 337.313 218.389 337.313 218.235 C337.313 217.993 337.356 217.678 337.443 217.291 L337.714 216.075 C337.79 215.731 337.827 215.429 337.827 215.168 C337.827 214.824 337.694 214.544 337.423 214.329 C337.07 214.04 336.591 213.896 335.987 213.896 C335.419 213.896 334.948 214.025 334.573 214.283 C334.202 214.541 333.93 214.913 333.758 215.398 L334.601 215.471 C334.702 215.186 334.863 214.965 335.086 214.811 C335.308 214.656 335.595 214.578 335.945 214.578 C336.317 214.578 336.599 214.654 336.791 214.808 C336.933 214.919 337.003 215.07 337.003 215.264 C337.003 215.415 336.972 215.603 336.907 215.83 C336.682 215.92 336.305 215.975 335.781 215.996 C335.259 216.019 334.904 216.048 334.715 216.084 C334.417 216.14 334.165 216.231 333.959 216.358 C333.754 216.485 333.589 216.654 333.465 216.865 C333.341 217.075 333.279 217.317 333.279 217.59 C333.279 218.005 333.417 218.345 333.693 218.61 C333.969 218.875 334.332 219.008 334.783 219.008 C335.089 219.008 335.373 218.951 335.643 218.835 C335.908 218.721 336.185 218.538 336.475 218.29 C336.493 218.536 336.526 218.738 336.571 218.898 M336.439 217.535 C336.29 217.795 336.09 217.999 335.836 218.145 C335.579 218.291 335.314 218.364 335.038 218.364 C334.74 218.364 334.511 218.289 334.35 218.138 C334.189 217.988 334.109 217.795 334.109 217.562 C334.109 217.387 334.157 217.227 334.259 217.083 C334.36 216.939 334.512 216.835 334.71 216.768 C334.91 216.702 335.254 216.647 335.737 216.604 C336.051 216.577 336.275 216.551 336.407 216.526 C336.541 216.501 336.667 216.467 336.784 216.42 C336.701 216.902 336.585 217.274 336.439 217.535' style='clip-path:url(#clipPath1); stroke:none;'/> "+
+//				"  </pathList>" +
+//				"</equivalence>";
+//		try {
+//			Element elem = new Builder().build(new StringReader(equivalenceS)).getRootElement();
+//			equiv = Equivalence.createEquivalence(elem);
+//		} catch (Exception e) {
+//			throw new RuntimeException("bad test equivalence", e);
+//		}
+//
+//	}
+	
+	@Test
+	public void dummy() {
+		
+	}
+	
+	@Test
+	@Ignore
+	public void testProcessEquivalence1() throws Exception {
+		InputStream inputStream = TestOutlineFont.class.getClassLoader().getResourceAsStream(EQUIVALENCE1);
+		Element equivalence1 = new Builder().build(inputStream).getRootElement().getChildElements().get(0);
+		Equivalence equiv = Equivalence.createEquivalence(equivalence1);
+		OutlineFont font1Italic = OutlineFont.readAndCreateFont(FONT1ITALIC);
+		font1Italic.processEquivalence(equiv);
+//		font1Italic.debug("altered font");
+	}
+}

src/test/java/org/xmlcml/graphics/font/TestFontManager.java

+package org.xmlcml.graphics.font;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TestFontManager {
+
+	@Test
+	public void dummy() {
+		
+	}
+	@Test
+	@Ignore
+	public void testGetFonts() {
+		FontManager fontManager = new FontManager();
+		List<OutlineFont> fontList = fontManager.getLocalFonts();
+		Assert.assertEquals("font list size", 3, fontList.size());
+	}
+	
+	@Test
+	@Ignore
+	public void testGetFontByName() throws Exception {
+		FontManager fontManager = new FontManager();
+		OutlineFont font = fontManager.getFontForName("font1-italic");
+		Assert.assertNotNull("font", font);
+	}
+}

src/test/java/org/xmlcml/graphics/font/TestOutlineFont.java

+package org.xmlcml.graphics.font;
+
+import java.io.InputStream;
+
+import nu.xom.Builder;
+import nu.xom.Element;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TestOutlineFont {
+
+	private static final String FONT1 = FontManager.packageBase+"/"+"outlineFonts/font1/equivalences.xml";
+	private FontManager fontManager;
+
+//	@Before
+//	public void setUp() {
+//		fontManager = new FontManager();
+//	}
+	
+	@Test
+	public void dummy() {
+		
+	}
+	@Test
+	@Ignore
+	public void testProcessEquivalence0() throws Exception {
+		InputStream inputStream = TestOutlineFont.class.getClassLoader().getResourceAsStream(FONT1);
+		Element equivalence1 = new Builder().build(inputStream).getRootElement().getChildElements().get(0);
+		String fontName = equivalence1.getChildElements("text").get(0).getAttributeValue(OutlineFont.FONT_NAME);
+		OutlineFont font = fontManager.getFontForName(fontName);
+		Assert.assertNotNull("font", font);
+	}
+
+}

src/test/java/org/xmlcml/graphics/misc/SchemaTest.java

 	  }
 	
 	@Test
-	@Ignore
+//	@Ignore
 	public void testValidatingParser() {
 		try {
-			String SCHEMA_PATH = "test1.xsd";
-			String SCHEMA_FILE = "src/test/resources/org/xmlcml/graphics/misc/test1.xsd";
+			String SCHEMA_PATH = "test1a.xsd";
+			String SCHEMA_FILE = "src/test/resources/org/xmlcml/graphics/misc/test1a.xsd";
 			InputStream SCHEMA_STREAM = getClass().getResourceAsStream(SCHEMA_PATH);
 			StreamSource SCHEMA_SOURCE = new StreamSource(SCHEMA_STREAM);
 			File xmlFile = new File("src/test/resources/org/xmlcml/graphics/misc/test1.xml");

src/test/java/org/xmlcml/graphics/misc/note.xsd

Empty file added.

src/test/java/org/xmlcml/graphics/misc/pdf/TestPDFBox2SVGElement.java

+package org.xmlcml.graphics.misc.pdf;
+
+import nu.xom.Builder;
+import nu.xom.Element;
+import nu.xom.Nodes;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.xmlcml.graphics.svg.SVGElement;
+import org.xmlcml.graphics.svg.SVGPath;
+
+public class TestPDFBox2SVGElement {
+
+	
+	private static final String PDF_BASE = "org/xmlcml/graphics/pdf";
+
+	@Test
+	public void testMini() {
+		Element element = parseElement("test4.mini.svg");
+		Nodes paths = element.query("./*[local-name()='g']/*[local-name()='path']");
+		Assert.assertEquals("paths", 71, paths.size());
+	}
+
+	@Test
+	// this also helps to build the fo
+	public void testGetSigs() {
+		Element element = parseElement("test4.mini.svg");
+		Nodes paths = element.query("./*[local-name()='g']/*[local-name()='path']");
+		for (int i = 0; i < paths.size(); i++) {
+			SVGPath svgPath = (SVGPath) SVGElement.readAndCreateSVG((Element) paths.get(i));
+			svgPath.normalizeOrigin();
+			System.out.println(">> "+svgPath.toXML());
+			try {
+				String sig = svgPath.getSignature();
+				System.out.println("> "+sig);
+			} catch (Exception e) {
+				System.out.println("ERROR "+e);
+			}
+		}
+	}
+
+	private Element parseElement(String filename) {
+		Element element = null;
+		try {
+			element = new Builder().build(this.getClass().getClassLoader().getResourceAsStream(PDF_BASE+"/"+filename)).getRootElement();
+		} catch (Exception e) {
+			throw new RuntimeException("cannot parse: "+filename, e);
+		}
+		return element;
+	}
+}

src/test/java/org/xmlcml/graphics/paths/PathAnalyzerTest.java

 
 import junit.framework.Assert;
 
-
 import org.junit.Test;
 import org.xmlcml.euclid.Real2;
-//import org.xmlcml.euclid.testutil.Real2TestUtil;
+import org.xmlcml.euclid.Real2Array;
 import org.xmlcml.graphics.svg.SVGCircle;
 
 public class PathAnalyzerTest {
 
-	static double EPS = 1E-8;
+	static double EPS = 1E-6;
+	static double EPS1 = 0.01;
 	@Test
 	public void testFindCircleFrom3Points() {
 		
 		SVGCircle circle = PathAnalyzer.findCircleFrom3Points(p1, p2, p3, 1e-10);
 		Assert.assertNotNull(circle);
 		Assert.assertEquals("rad", 1.0, circle.getRad(), EPS);
-//		Real2TestUtil.assertEquals("center", new Real2(0., 0.), circle.getCXY(), EPS);
+		Assert.assertEquals("x", 0.0, circle.getCX(), EPS);
+		Assert.assertEquals("y", 0.0, circle.getCY(), EPS);
+	}
+	@Test
+	public void testFindCircleFrom3Points1() {
+		
+		Real2 p1 = new Real2(2.,1.);
+		Real2 p2 = new Real2(5.,3);
+		Real2 p3 = new Real2(-1., 7.);
+		SVGCircle circle = PathAnalyzer.findCircleFrom3Points(p1, p2, p3, 1e-10);
+		Assert.assertNotNull(circle);
+		double r = circle.getRad();
+		Real2 center = circle.getCXY();
+		Assert.assertEquals("p1", 3.6336104, center.getDistance(p1), EPS);
+		Assert.assertEquals("p2", 3.6336104, center.getDistance(p2), EPS);
+		Assert.assertEquals("p3", 3.6336104, center.getDistance(p3), EPS);
+	}
+	
+	@Test
+	public void testFindCircleFrom3Points2() {
+		
+		Real2 p1 = new Real2(2.,0.);
+		Real2 p2 = new Real2(1.,1.);
+		Real2 p3 = new Real2(0.,2.);
+		SVGCircle circle = PathAnalyzer.findCircleFrom3Points(p1, p2, p3, 1e-10);
+		Assert.assertNull(circle);
+	}
+	
+	
+	@Test
+	public void testFindCircleFromManyPoints() {
+		
+		Real2 p1 = new Real2(3.,1.);
+		Real2 p2 = new Real2(2.71, 1.71);
+		Real2 p3 = new Real2(2.,2.);
+		Real2Array r2a = new Real2Array();
+		r2a.add(new Real2(3.,1.));
+		r2a.add(new Real2(2.71, 1.71));
+		r2a.add(new Real2(2.,2.));
+		SVGCircle circle = PathAnalyzer.findCircleFromPoints(r2a, 1e-10);
+		Assert.assertNotNull(circle);
+		Assert.assertEquals("rad", 1.0, circle.getRad(), EPS1);
+		Assert.assertEquals("x", 2.0, circle.getCX(), EPS1);
+		Assert.assertEquals("y", 1.0, circle.getCY(), EPS1);
 	}
 }

src/test/java/org/xmlcml/graphics/pdf2svg/DocumentValidatorTest.java

+package org.xmlcml.graphics.pdf2svg;
+
+import java.io.File;
+
+import org.junit.Test;
+import org.xmlcml.graphics.pdf2svg.DocumentValidator;
+
+public class DocumentValidatorTest {
+
+	@Test
+	public void testValidateSemanticDocument() {
+		DocumentValidator.validateDocument(DocumentValidator.SCHEMA_PATH, new File("src/main/resources/org/xmlcml/graphics/styles/basic.xml"));
+	}
+
+}

src/test/resources/org/xmlcml/graphics/misc/test1.xml

 <?xml version="1.0" encoding="UTF-8"?>
-<p:customers 
-    xmlns:p="http://www.xml-cml.org/schema/ami2" 
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-  xsi:schemaLocation="http://www.xml-cml.org/schema/ami2 src/test/resources/org/xmlcml/graphics/misc/test1.xsd">
-  <p:customer>
-    <p:name salutation="Mr."/>
-    <p:age>25</p:age>
-    <p:discount>6</p:discount>
-  </p:customer>
-  <p:customer>
-    <p:name salutation="Ms."/>
-    <p:age>35</p:age>
-    <p:discount>10</p:discount>
-  </p:customer>
-</p:customers>
+<a:semanticDocument
+    xmlns:a="http://www.xml-cml.org/schema/ami2" 
+  foo="bar"></a:semanticDocument>  

src/test/resources/org/xmlcml/graphics/misc/test1a.xsd

 <xs:schema 
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
-	elementFormDefault="qualified" 
 	targetNamespace="http://www.xml-cml.org/schema/ami2"
-	xmlns:p="http://www.xml-cml.org/schema/ami2"
 	>
 
-	<xs:complexType name="customerName">
-		<xs:attribute name="salutation" type="xs:string" default="Mr."></xs:attribute>
+  <xs:element name="semanticDocument">
+	<xs:complexType>
+		<xs:attribute name="foo" type="xs:string" ></xs:attribute>
 	</xs:complexType>
+  </xs:element>
 
-	<xs:simpleType name="customerAge">
-		<xs:restriction base="xs:integer">
-			<xs:minInclusive value="18"></xs:minInclusive>
-			<xs:maxInclusive value="60"></xs:maxInclusive>
-		</xs:restriction>
-	</xs:simpleType>
-
-	<xs:simpleType name="customerdiscount">
-		<xs:restriction base="xs:integer">
-			<xs:minInclusive value="5"></xs:minInclusive>
-			<xs:maxInclusive value="30"></xs:maxInclusive>
-		</xs:restriction>
-	</xs:simpleType>
-
-	<xs:complexType name="customer">
-		<xs:sequence>
-			<xs:element name="name" type="p:customerName"></xs:element>
-			<xs:element name="age" type="p:customerAge"></xs:element>
-			<xs:element name="discount" type="p:customerdiscount"></xs:element>
-		</xs:sequence>
-	</xs:complexType>
-
-	<xs:element name="customers">
-		<xs:complexType>
-			<xs:sequence>
-				<xs:element name="customer" type="p:customer"></xs:element>
-				<xs:element name="customer" type="p:customer"></xs:element>
-				<xs:element name="customer" type="p:customer"></xs:element>
-			</xs:sequence>
-		</xs:complexType>
-	</xs:element>
--->
 	
 </xs:schema>