├── data ├── bad │ ├── zero.kml │ ├── nokml.kmz │ ├── reallyKmz.kml │ ├── bad-too-large.kmz │ ├── bad.xml │ ├── notKmz.kmz │ ├── reallyHtml.kmz │ ├── badColor.kml │ └── readme.txt ├── kmz │ ├── big.kmz │ └── nested.kmz ├── kml │ ├── nonkmlroot.kml │ ├── no-namespace.kml │ ├── placemark.kml │ ├── earth-google-com-kml-21.kml │ ├── earth-google-com-kml-22.kml │ ├── data-ext-atom.kml │ ├── tessellate21.kml │ ├── tessellate-orig.kml │ └── tessellate22.kml └── xml │ ├── atom.xml │ ├── cot.xml │ ├── xal.xml │ └── mystic_basin_trail.gpx ├── .gitattributes ├── .gitignore ├── gradlew ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .travis.yml ├── src ├── main │ └── java │ │ └── org │ │ └── mitre │ │ └── xml │ │ └── validate │ │ ├── ErrorStatus.java │ │ ├── KmzExplorer.java │ │ ├── UrlResource.java │ │ ├── FileResource.java │ │ └── Resource.java └── test │ └── java │ └── org │ └── mitre │ └── xml │ └── validate │ ├── TestKmzFile.java │ ├── TestFileResource.java │ └── TestXmlValidate.java ├── bin ├── xv.bat ├── kmz22.bat ├── kml22.bat └── kml21.bat ├── LICENSE.txt ├── ns.map ├── run.bat ├── schemas ├── xml.xsd ├── atom-author-link.xsd ├── gpx10.xsd ├── kml22gx.xsd ├── Event.xsd ├── kml.xsd ├── atom.xsd └── gpx11.xsd ├── gradlew.bat ├── README.md ├── README.txt └── README.html /data/bad/zero.kml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | gradlew text eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Package Files # 2 | .gradle/ 3 | build/ 4 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/gradlew -------------------------------------------------------------------------------- /data/kmz/big.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/data/kmz/big.kmz -------------------------------------------------------------------------------- /data/bad/nokml.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/data/bad/nokml.kmz -------------------------------------------------------------------------------- /data/kmz/nested.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/data/kmz/nested.kmz -------------------------------------------------------------------------------- /data/bad/reallyKmz.kml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/data/bad/reallyKmz.kml -------------------------------------------------------------------------------- /data/bad/bad-too-large.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/data/bad/bad-too-large.kmz -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docjason/XmlValidate/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: openjdk8 3 | install: gradle -q assemble 4 | script: gradle test 5 | sudo: false 6 | notifications: 7 | on_success: change 8 | on_failure: change -------------------------------------------------------------------------------- /data/bad/bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Tove 4 | Jani 5 | Reminder 6 | Don't forget me this weekend! 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/org/mitre/xml/validate/ErrorStatus.java: -------------------------------------------------------------------------------- 1 | package org.mitre.xml.validate; 2 | 3 | public interface ErrorStatus { 4 | 5 | void addWarning(String s); 6 | 7 | void addError(String s); 8 | 9 | int getWarnings(); 10 | 11 | int getErrors(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data/bad/notKmz.kmz: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -122,37 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /data/bad/reallyHtml.kmz: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/kml/nonkmlroot.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | My office 4 | This is the location of my office. 5 | 6 | -122.087461,37.422069 7 | 8 | 9 | -------------------------------------------------------------------------------- /data/kml/no-namespace.kml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | no namespace 8 | 9 | -122,37 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /data/kml/placemark.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My office 5 | This is the location of my office. 6 | 7 | -122.087461,37.422069 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /data/kml/earth-google-com-kml-21.kml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Google KML 2.1 8 | 9 | -122,37 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /data/kml/earth-google-com-kml-22.kml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Google KML 2.2 8 | 9 | -122,37 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /bin/xv.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem %~dp0 is expanded pathname of the current script under NT 5 | set XV_HOME=%~dp0.. 6 | 7 | set OPTS=-Xmx64m 8 | if not exist "%XV_HOME%\build\libs\jdom2-2.0.5.jar" goto rungradle 9 | set CLASSPATH=%XV_HOME%\build\libs\* 10 | java %OPTS% -classpath "%CLASSPATH%" org.mitre.xml.validate.XmlValidate -kml "-home=%XV_HOME%" "-map=%XV_HOME%\ns.map" %* 11 | goto end 12 | 13 | :rungradle 14 | echo Must run "gradlew install" from XmlValidate home directory to configure batch file environment 15 | :end -------------------------------------------------------------------------------- /data/bad/badColor.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | styled placemark 5 | 14 | 15 | 48,29 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2009 The MITRE Corporation 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /bin/kmz22.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem %~dp0 is expanded pathname of the current script under NT 5 | set XV_HOME=%~dp0.. 6 | 7 | if not exist "%XV_HOME%\build\libs\jdom2-2.0.5.jar" goto rungradle 8 | set OPTS=-Xmx64m 9 | set SCHEMA=http://www.opengis.net/kml/2.2 10 | set SCHEMALOC=%XV_HOME%\schemas\kml22.xsd 11 | set CLASSPATH=%XV_HOME%\build\libs\* 12 | java %OPTS% -classpath "%CLASSPATH%" org.mitre.xml.validate.XmlValidate -kmz -ns=%SCHEMA% "-schema=%SCHEMALOC%" %* 13 | goto end 14 | 15 | :rungradle 16 | echo Must run "gradlew install" from XmlValidate home directory to configure batch file environment 17 | :end -------------------------------------------------------------------------------- /bin/kml22.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem %~dp0 is expanded pathname of the current script under NT 5 | set XV_HOME=%~dp0.. 6 | 7 | if not exist "%XV_HOME%\build\libs\jdom2-2.0.5.jar" goto rungradle 8 | set OPTS=-Xmx64m 9 | set SCHEMA=http://www.opengis.net/kml/2.2 10 | set SCHEMALOC=%XV_HOME%\schemas\kml22.xsd 11 | set CLASSPATH=%XV_HOME%\build\libs\* 12 | java %OPTS% -classpath "%CLASSPATH%" org.mitre.xml.validate.XmlValidate -kml -ns=%SCHEMA% "-schema=%SCHEMALOC%" %* 13 | goto end 14 | 15 | :rungradle 16 | echo Must run "gradlew install" from XmlValidate home directory to configure batch file environment 17 | :end 18 | -------------------------------------------------------------------------------- /data/xml/atom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example Feed 5 | 6 | 2003-12-13T18:30:02Z 7 | 8 | John Doe 9 | 10 | urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 11 | 12 | 13 | Atom-Powered Robots Run Amok 14 | 15 | urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 16 | 2003-12-13T18:30:02Z 17 | Some text. 18 | 19 | 20 | -------------------------------------------------------------------------------- /data/xml/cot.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | <_flow-tags_ xplane="2008-12-11T18:45:34.00Z"/> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /bin/kml21.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem %~dp0 is expanded pathname of the current script under NT 5 | set XV_HOME=%~dp0.. 6 | 7 | if not exist "%XV_HOME%\build\libs\jdom2-2.0.5.jar" goto rungradle 8 | set OPTS=-Xmx64m 9 | set SCHEMA=http://earth.google.com/kml/2.1 10 | REM set SCHEMALOC=http://code.google.com/apis/kml/schema/kml21.xsd 11 | set SCHEMALOC=%XV_HOME%\schemas\kml21.xsd 12 | set CLASSPATH=%XV_HOME%\build\libs\* 13 | java %OPTS% -classpath "%CLASSPATH%" org.mitre.xml.validate.XmlValidate -kml -ns=%SCHEMA% "-schema=%SCHEMALOC%" %* 14 | goto end 15 | 16 | :rungradle 17 | echo Must run "gradlew install" from XmlValidate home directory to configure batch file environment 18 | :end -------------------------------------------------------------------------------- /ns.map: -------------------------------------------------------------------------------- 1 | # Specify URL or full absolute path if schemas in location 2 | # other than XmlValidate schemas directory. 3 | # 4 | # If XmlValidate is invoked from other than XmlValidate root directory 5 | # then -home option must be passed to XmlValidate with this location 6 | # to resolve the schema locations. 7 | # 8 | http://earth.google.com/kml/2.0=${XV_HOME}/schemas/kml20.xsd 9 | http://earth.google.com/kml/2.1=${XV_HOME}/schemas/kml21.xsd 10 | http://www.opengis.net/kml/2.2=${XV_HOME}/schemas/kml22.xsd 11 | http://www.google.com/kml/ext/2.2=${XV_HOME}/schemas/kml22gx.xsd 12 | http://www.topografix.com/GPX/1/0=${XV_HOME}/schemas/gpx10.xsd 13 | http://www.topografix.com/GPX/1/1=${XV_HOME}/schemas/gpx11.xsd 14 | http://www.w3.org/2005/Atom=${XV_HOME}/schemas/atom.xsd 15 | #http://www.w3.org/1999/xhtml=${XV_HOME}/schemas/xhtml1-strict.xsd 16 | urn:oasis:names:tc:ciq:xsdschema:xAL:2.0=${XV_HOME}/schemas/xAL.xsd 17 | -------------------------------------------------------------------------------- /data/bad/readme.txt: -------------------------------------------------------------------------------- 1 | Note the files in this folder are intentionally bad to test XML validation. 2 | 3 | They all fail validation in one of three ways: 4 | 1) XML file is not well-formed, or 5 | 2) XML is not valid with respect to the declared XML Schema(s), or 6 | 3) in case of KMZ files, the KMZ packaging for the KML is not valid 7 | or root KML file is not present. 8 | 9 | bad-too-large.kmz 10 | -- Zip file entry has invalid file length making this fail to parse. 11 | 12 | bad.xml 13 | -- XML not well-formed. Mismatched start and end tags. 14 | 15 | badColor.kml 16 | -- color value omits alpha component. 17 | 18 | nokml.kmz 19 | -- KMZ file with no root KML file. 20 | 21 | notKmz.kmz 22 | -- File has .kmz file extension but is not a KMZ but a KML file. 23 | XML Validate will identify this error and retry file as KML. 24 | 25 | reallyHtml.kmz 26 | -- File has .kmz extension but is really a HTML file. 27 | 28 | reallyKmz.kml 29 | -- File has .kml extension but is really a KMZ file. 30 | 31 | zero.kml 32 | -- zero length file. Not a XML or KML file. 33 | Zero length files are skipped but indication is logged if in verbose mode. 34 | -------------------------------------------------------------------------------- /data/xml/xal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | US 5 | 6 | CA 7 | 8 | Santa Clara 9 | 10 | Mountain View 11 | 12 | 1600 13 | Amphitheatre Pkwy 14 | 15 | 16 | 94043 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /data/kml/data-ext-atom.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test data 5 | 6 | 7 | Example Feed 8 | 9 | 2003-12-13T18:30:02Z 10 | 11 | John Doe 12 | 13 | urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 14 | 15 | Atom-Powered Robots Run Amok 16 | 17 | urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 18 | 2003-12-13T18:30:02Z 19 | Some text. 20 | 21 | 22 | 23 | 24 | -71.7571,42.953 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | echo This test batch file shows several typical ways 5 | echo to use XmlValidate with the sample XML data 6 | echo located in data directory, schemas in schemas/, 7 | echo and wrapper .bat files in /bin. 8 | echo. 9 | echo ========================================== 10 | echo. 11 | 12 | REM Source XML files are loaded into memory so may need 13 | REM to increase memory limits to validate very large XML. 14 | set OPTS=-Xmx64m 15 | 16 | echo Validate CoT XML document with non-namespace schema 17 | call bin\xv.bat -schema=schemas\Event.xsd -v data/xml/cot.xml 18 | echo. 19 | echo ========================================== 20 | 21 | echo. 22 | echo Validate all KML/KMZ documents as KML 2.1 Schema 23 | call bin\kml21.bat -kmz data\kml\tessellate-orig.kml data/kmz 24 | echo. 25 | echo ========================================== 26 | 27 | echo. 28 | echo Validate all GPX/KML/KMZ documents 29 | call bin\xv.bat -v -kmz -x=gpx data/xml data/kml data/kmz 30 | echo. 31 | echo Notice the tessellate-orig.kml example has the wrong namespace 32 | echo and fails to validate against the specified schema namespace. 33 | echo ========================================== 34 | -------------------------------------------------------------------------------- /data/kml/tessellate21.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | Tessellated paths 19 | 0 20 | 21 | tag has a value of 1, the line will contour 23 | to the underlying terrain 24 | ]]> 25 | 26 | 27 | -112.0822680013139 28 | 36.09825589333556 29 | 0 30 | 2889.145007690472 31 | 62.04855796276328 32 | 103.8120432044965 33 | 34 | 35 | 1 36 | 37 | -112.0814237830345,36.10677870477137,0 38 | -112.0870267752693,36.0905099328766,0 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /data/kml/tessellate-orig.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | Tessellated paths 19 | 0 20 | 21 | tag has a value of 1, the line will contour 23 | to the underlying terrain 24 | ]]> 25 | 26 | 27 | -112.0822680013139 28 | 36.09825589333556 29 | 0 30 | 2889.145007690472 31 | 62.04855796276328 32 | 103.8120432044965 33 | 34 | 35 | 1 36 | 37 | -112.0814237830345,36.10677870477137,0 38 | -112.0870267752693,36.0905099328766,0 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /data/kml/tessellate22.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | Tessellated paths 20 | 0 21 | 22 | tag has a value of 1, the line will contour 24 | to the underlying terrain 25 | ]]> 26 | 27 | 28 | -112.0822680013139 29 | 36.09825589333556 30 | 0 31 | 103.8120432044965 32 | 62.04855796276328 33 | 2889.145007690472 34 | 35 | 36 | 1 37 | 38 | -112.0814237830345,36.10677870477137,0 39 | -112.0870267752693,36.0905099328766,0 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /schemas/xml.xsd: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | See http://www.w3.org/TR/xmlbase/ for 36 | information about this attribute. 37 | 38 | 39 | 40 | 41 | 42 | See http://www.w3.org/TR/xml-id/ for 43 | information about this attribute. 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /schemas/atom-author-link.xsd: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | atom-author-link.xsd 2008-01-23 9 | There is no official atom XSD. This XSD is created based on: 10 | http://atompub.org/2005/08/17/atom.rnc. A subset of Atom as used in the 11 | ogckml22.xsd is defined here. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/test/java/org/mitre/xml/validate/TestKmzFile.java: -------------------------------------------------------------------------------- 1 | package org.mitre.xml.validate; 2 | 3 | import junit.framework.TestCase; 4 | import org.jdom2.Document; 5 | import org.jdom2.JDOMException; 6 | import org.jdom2.input.SAXBuilder; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | /** 12 | * @author Jason Mathews, MITRE Corp. 13 | * Date: 9/29/13 9:11 PM 14 | */ 15 | public class TestKmzFile extends TestCase { 16 | 17 | private final SAXBuilder builder; 18 | 19 | public TestKmzFile() { 20 | builder = new SAXBuilder(); 21 | } 22 | 23 | public void testKmzFiles() throws JDOMException, IOException { 24 | for(File f : new File("data/kmz").listFiles()) { 25 | checkFile(f); 26 | } 27 | } 28 | 29 | public void testKmzMode() { 30 | XmlValidate validator = new XmlValidate(); 31 | validator.setKmzMode(true); 32 | validator.setSummary(true); 33 | validator.setMap(new File("ns.map")); 34 | validator.validate(new File("data/kmz/nested.kmz")); 35 | assertEquals(3, validator.getFileCount()); 36 | assertEquals(0, validator.getErrors()); 37 | assertEquals(0, validator.getWarnings()); 38 | } 39 | 40 | public void testBadKmzFiles() throws JDOMException, IOException { 41 | // test bad KMZ files: bad-too-large.kmz, nokml.kmz, notKmz.kmz, reallyHtml.kmz 42 | for(File f : new File("data/bad").listFiles()) { 43 | if (!f.getName().endsWith(".kmz")) continue; 44 | boolean expectException = ! f.getName().endsWith("notKmz.kmz"); 45 | try { 46 | checkFile(f); 47 | // REVIEW: following is triggered running on linux platform 48 | // presumably due to different version of JRE which no longer 49 | // throws an exception when it opens a bad KMZ file. 50 | //if (expectException) fail("expected exception"); 51 | } catch(Exception e) { 52 | if (!expectException) fail("unexpected exception"); 53 | } 54 | } 55 | } 56 | 57 | private void checkFile(File file) throws JDOMException, IOException { 58 | FileResource res = new FileResource(System.out, file, "http://www.opengis.net/kml/2.2"); 59 | assertNotNull(res.getFile()); 60 | Document doc = res.getDocument(builder); 61 | assertNotNull(doc); 62 | final boolean isNotKmzFile = file.getName().endsWith("notKmz.kmz"); 63 | assertEquals(!isNotKmzFile, res.isKmzFile()); 64 | assertEquals(0, res.getErrors()); 65 | assertEquals(isNotKmzFile ? 1 : 0, res.getWarnings()); 66 | assertEquals(!isNotKmzFile, res.getStats().isEmpty()); 67 | // kml or Placemark 68 | String name = doc.getRootElement().getName(); 69 | if (!name.equals("kml") && !name.equals("Placemark")) 70 | fail("root element expected to be kml or Placemark but instead is " + name); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/org/mitre/xml/validate/KmzExplorer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * KmzExplorer.java 3 | * 4 | * (C) Copyright MITRE Corporation 2014 5 | * 6 | * The program is provided "as is" without any warranty express or implied, including 7 | * the warranty of non-infringement and the implied warranties of merchantability and 8 | * fitness for a particular purpose. The Copyright owner will not be liable for any 9 | * damages suffered by you as a result of using the Program. In no event will the 10 | * Copyright owner be liable for any special, indirect or consequential damages or 11 | * lost profits even if the Copyright owner has been advised of the possibility of 12 | * their occurrence. 13 | * 14 | */ 15 | package org.mitre.xml.validate; 16 | 17 | import org.jdom2.Document; 18 | import org.jdom2.JDOMException; 19 | import org.jdom2.input.SAXBuilder; 20 | 21 | import java.io.Closeable; 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.io.PrintStream; 26 | import java.util.Enumeration; 27 | import java.util.Locale; 28 | import java.util.zip.ZipEntry; 29 | import java.util.zip.ZipFile; 30 | 31 | /** 32 | * @author Jason Mathews, MITRE Corp. 33 | * Created on 6/30/2014. 34 | */ 35 | public class KmzExplorer implements Closeable { 36 | 37 | private final File file; 38 | private final PrintStream out; 39 | private final String schemaNamespace; 40 | private final ErrorStatus status; 41 | private ZipFile zf; 42 | private final Enumeration e; 43 | 44 | public KmzExplorer(PrintStream out, File file, String schemaNamespace, ErrorStatus status) throws IOException { 45 | this.out = out; 46 | this.file = file; 47 | this.schemaNamespace = schemaNamespace; 48 | this.status = status; 49 | zf = new ZipFile(file); 50 | e = zf.entries(); 51 | while (e.hasMoreElements()) { 52 | ZipEntry entry = e.nextElement(); 53 | // skip first/root kml file 54 | if (entry.getName().toLowerCase(Locale.ROOT).endsWith(".kml")) break; 55 | } 56 | } 57 | 58 | public Resource next() { 59 | while (e.hasMoreElements()) { 60 | ZipEntry entry = e.nextElement(); 61 | final String name = entry.getName(); 62 | final String nameLower = name.toLowerCase(Locale.ROOT); 63 | if (nameLower.endsWith(".kml")) { 64 | return new KmzResource(entry); 65 | } else if (nameLower.endsWith(".kmz") || nameLower.endsWith(".zip")) { 66 | // KMZ file cannot reference another KMZ inside itself 67 | status.addWarning("WARN: KMZ file has non-compliant compressed entry: " + name); 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | public void close() { 74 | if (zf != null) { 75 | try { 76 | zf.close(); 77 | } catch (IOException ex) { 78 | // ignore 79 | } 80 | zf = null; 81 | } 82 | } 83 | 84 | private class KmzResource extends Resource { 85 | 86 | private final ZipEntry entry; 87 | 88 | public KmzResource(ZipEntry entry) { 89 | super(KmzExplorer.this.out, 90 | file.toString() + '/' + entry.getName(), schemaNamespace); 91 | this.entry = entry; 92 | } 93 | 94 | @Override 95 | public String getSource() { 96 | return targetFile; 97 | } 98 | 99 | @Override 100 | public Document getDocument(SAXBuilder builder) throws JDOMException, IOException { 101 | if (doc == null) { 102 | InputStream is = null; 103 | try { 104 | is = zf.getInputStream(entry); 105 | doc = builder.build(is, 106 | file.getAbsoluteFile().toURI().toString()); 107 | } finally { 108 | if (is != null) 109 | try { 110 | is.close(); 111 | } catch (IOException ioe) { 112 | // ignore 113 | } 114 | } 115 | } 116 | return doc; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/org/mitre/xml/validate/TestFileResource.java: -------------------------------------------------------------------------------- 1 | package org.mitre.xml.validate; 2 | 3 | import org.jdom2.*; 4 | import org.jdom2.input.SAXBuilder; 5 | import org.jdom2.input.sax.XMLReaders; 6 | import org.junit.After; 7 | import org.junit.AfterClass; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | 11 | import java.io.File; 12 | import java.io.FileWriter; 13 | import java.io.IOException; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | /** 18 | * Created by mathews on 11/2/2014. 19 | */ 20 | public class TestFileResource { 21 | 22 | private static SAXBuilder builder, validatingBuilder; 23 | 24 | @BeforeClass 25 | public static void setUp() throws Exception { 26 | builder = new SAXBuilder(); 27 | 28 | validatingBuilder = new SAXBuilder(XMLReaders.XSDVALIDATING); 29 | validatingBuilder.setFeature(XmlValidate.VALIDATION_FEATURE, true); 30 | validatingBuilder.setFeature(XmlValidate.SCHEMA_VALIDATION_FEATURE, true); 31 | validatingBuilder.setFeature(XmlValidate.SCHEMA_FULL_CHECKING_FEATURE, true); 32 | validatingBuilder.setFeature(XmlValidate.LOAD_DTD_GRAMMAR, false); 33 | validatingBuilder.setFeature(XmlValidate.LOAD_EXTERNAL_DTD, false); 34 | validatingBuilder.setFeature("http://xml.org/sax/features/external-general-entities", false); 35 | validatingBuilder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 36 | } 37 | 38 | @AfterClass 39 | public static void tearDownAfterClass() { 40 | builder = null; 41 | validatingBuilder = null; 42 | } 43 | 44 | @After 45 | public void tearDown() { 46 | if (validatingBuilder != null) { 47 | validatingBuilder.setErrorHandler(null); 48 | } 49 | } 50 | 51 | @Test(expected = JDOMException.class) 52 | public void testBadXml() throws JDOMException, IOException { 53 | File file = new File("data/bad/bad.xml"); 54 | FileResource res = new FileResource(System.out, file, null); 55 | res.getDocument(builder); 56 | } 57 | 58 | @Test 59 | public void testKml() throws JDOMException, IOException { 60 | File file = new File("data/kml/tessellate22.kml"); 61 | FileResource res = getResource(file); 62 | res.setSummary(true); 63 | validatingBuilder.setErrorHandler(res); 64 | Document doc = res.getDocument(validatingBuilder); 65 | assertNotNull(doc); 66 | assertFalse(res.isKmzFile()); 67 | 68 | assertEquals(0, res.getErrors()); 69 | assertEquals(0, res.getWarnings()); 70 | assertEquals(0, res.getStats().size()); 71 | } 72 | 73 | @Test 74 | public void testBadKml() throws JDOMException, IOException { 75 | File file = new File("data/bad/badColor.kml"); 76 | FileResource res = getResource(file); 77 | res.setSummary(true); 78 | validatingBuilder.setErrorHandler(res); 79 | Document doc = res.getDocument(validatingBuilder); 80 | assertNotNull(doc); 81 | assertFalse(res.isKmzFile()); 82 | 83 | assertEquals(14, res.getErrors()); 84 | assertEquals(0, res.getWarnings()); 85 | assertEquals(5, res.getStats().size()); 86 | } 87 | 88 | private FileResource getResource(File file) throws JDOMException, IOException { 89 | FileResource res = new FileResource(System.out, file, "http://www.opengis.net/kml/2.2"); 90 | assertSame(file, res.getFile()); 91 | 92 | // add schema location to root XML element so errors/warnings get generated 93 | Document doc = res.getDocument(builder); 94 | Element root = doc.getRootElement(); 95 | root.setAttribute("schemaLocation", "http://www.opengis.net/kml/2.2 " + 96 | new File("schemas/kml22.xsd").toURI().toString(), XmlValidate.xsiNamespace); 97 | File outFile = new File("build/" + file.getName()); 98 | FileWriter writer = new FileWriter(outFile); 99 | writer.write(res.getXmlContent()); 100 | writer.close(); 101 | return new FileResource(System.out, outFile, "http://www.opengis.net/kml/2.2"); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/org/mitre/xml/validate/TestXmlValidate.java: -------------------------------------------------------------------------------- 1 | package org.mitre.xml.validate; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import java.io.File; 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | import java.util.Set; 9 | 10 | /** 11 | * @author Jason Mathews, MITRE Corp. 12 | * 13 | * Date: 4/27/12 11:10 AM 14 | */ 15 | public class TestXmlValidate extends TestCase { 16 | 17 | public void testUrlResource() throws MalformedURLException { 18 | XmlValidate validator = new XmlValidate(); 19 | validator.setSummary(true); 20 | // add namespace map to validator 21 | validator.setMap(new File("ns.map")); 22 | URL url = new File("data/kmz/big.kmz").toURI().toURL(); 23 | UrlResource resource = new UrlResource(System.out, url, null); 24 | assertNotNull(resource.getSource()); 25 | validator.validate(resource); 26 | url = new File("data/kml/placemark.kml").toURI().toURL(); 27 | resource = new UrlResource(System.out, url, "http://www.opengis.net/kml/2.2"); 28 | validator.validate(resource); 29 | assertEquals(2, validator.getFileCount()); 30 | assertEquals(0, validator.getErrors()); 31 | assertEquals(0, validator.getWarnings()); 32 | } 33 | 34 | public void testBadXml() { 35 | XmlValidate validator = new XmlValidate(); 36 | validator.setSummary(true); 37 | validator.setMap(new File("ns.map")); 38 | validator.validate(new File("data/bad/bad.xml")); 39 | validator.dumpStatus(); 40 | assertEquals(1, validator.getFileCount()); 41 | assertEquals(1, validator.getErrors()); 42 | assertEquals(0, validator.getWarnings()); 43 | } 44 | 45 | public void testBadKml() { 46 | XmlValidate validator = new XmlValidate(); 47 | validator.setMap(new File("ns.map")); 48 | validator.setKmlMode(true); 49 | validator.setDumpLevel(1); 50 | validator.validate(new File("data/bad/badColor.kml")); 51 | validator.dumpStatus(); 52 | assertEquals(1, validator.getFileCount()); 53 | assertTrue(validator.getErrors() != 0); 54 | assertEquals(0, validator.getWarnings()); 55 | } 56 | 57 | public void testCotXml() { 58 | // Test XML document with no namespace 59 | // this will force adding xsi:noNamespaceSchemaLocation attribute to root element for validation 60 | XmlValidate validator = new XmlValidate(); 61 | validator.setSchema(new File("schemas/Event.xsd")); 62 | validator.setVerbose(true); 63 | validator.setDebug(true); 64 | validator.setHomeDir("."); 65 | validator.setDumpLevel(2); 66 | validator.validate(new File("data/xml/cot.xml")); 67 | //validator.setSummary(true); 68 | validator.dumpStatus(); 69 | assertEquals(1, validator.getFileCount()); 70 | assertEquals(0, validator.getErrors()); 71 | assertEquals(0, validator.getWarnings()); 72 | } 73 | 74 | public void testKmlDirRecurse() { 75 | // Validate all KML and KMZ documents using KML 2.1 Schema 76 | XmlValidate validator = new XmlValidate(); 77 | Set extensionSet = validator.getExtensionSet(); 78 | extensionSet.clear(); 79 | extensionSet.add("kml"); 80 | extensionSet.add("kmz"); 81 | 82 | // http://code.google.com/apis/kml/schema/kml21.xsd 83 | validator.setSchema(new File("schemas/kml21.xsd")); 84 | validator.setNamespace("http://earth.google.com/kml/2.1"); 85 | validator.setSummary(true); 86 | validator.setKmlMode(true); 87 | 88 | //validator.setVerbose(); 89 | validator.validate(new File("data/kml")); 90 | validator.validate(new File("data/bad/zero.kml")); 91 | //validator.validate(new File("data/kmz")); 92 | validator.dumpStatus(); 93 | 94 | assertEquals(9, validator.getFileCount()); 95 | // assertEquals(2, validator.getErrors()); 96 | // assertTrue(validator.getErrors() != 0); 97 | assertEquals(0, validator.getWarnings()); 98 | } 99 | 100 | public void testGpxFile() { 101 | // Validate all GPX/KML/KMZ documents against the declared namespace 102 | XmlValidate validator = new XmlValidate(); 103 | validator.setSummary(true); 104 | validator.setKmlMode(true); 105 | Set extensionSet = validator.getExtensionSet(); 106 | // add namespace map to validator 107 | validator.setMap(new File("ns.map")); 108 | extensionSet.clear(); 109 | extensionSet.add("kml"); 110 | extensionSet.add("kmz"); 111 | extensionSet.add("gpx"); 112 | validator.validate(new File("data")); 113 | assertEquals(18, validator.getFileCount()); 114 | assertTrue(validator.getErrors() != 0); 115 | assertEquals(1, validator.getWarnings()); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/mitre/xml/validate/UrlResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * UrlResource.java 3 | * 4 | * (C) Copyright MITRE Corporation 2009 5 | * 6 | * The program is provided "as is" without any warranty express or implied, including 7 | * the warranty of non-infringement and the implied warranties of merchantibility and 8 | * fitness for a particular purpose. The Copyright owner will not be liable for any 9 | * damages suffered by you as a result of using the Program. In no event will the 10 | * Copyright owner be liable for any special, indirect or consequential damages or 11 | * lost profits even if the Copyright owner has been advised of the possibility of 12 | * their occurrence. 13 | * 14 | */ 15 | package org.mitre.xml.validate; 16 | 17 | import org.jdom2.Document; 18 | import org.jdom2.JDOMException; 19 | import org.jdom2.input.SAXBuilder; 20 | 21 | import java.net.URL; 22 | import java.net.URLConnection; 23 | import java.io.InputStream; 24 | import java.io.IOException; 25 | import java.io.BufferedInputStream; 26 | import java.io.PrintStream; 27 | import java.util.Locale; 28 | import java.util.zip.ZipInputStream; 29 | import java.util.zip.ZipEntry; 30 | 31 | /** 32 | * URL resource that implements building a JDOM Document 33 | * from a URL. 34 | * 35 | * @author Jason Mathews, MITRE Corp. 36 | * Date: Feb 13, 2009 7:08:07 PM 37 | */ 38 | public class UrlResource extends Resource { 39 | 40 | private final URL url; 41 | 42 | public UrlResource(PrintStream out, URL url, String schemaNamespace) { 43 | super(out, url.toString(), schemaNamespace); 44 | this.url = url; 45 | } 46 | 47 | public Document getDocument(SAXBuilder builder) throws JDOMException, IOException { 48 | if (doc == null) doc = builder.build(getInputStream(url), url.toExternalForm()); 49 | return doc; 50 | } 51 | 52 | public String getSource() { 53 | return url.toExternalForm(); 54 | } 55 | 56 | /** 57 | * This method gets the correct input stream for a URL. If the URL 58 | * is to a KMZ resource then the first KML entry inside the zip input stream 59 | * is returned in an inputStream. 60 | * 61 | * @param url The url to the XML resource 62 | * @return The InputStream used to validate and parse the xml resource 63 | * @throws java.io.IOException when an I/O error prevents a document 64 | * from being fully parsed. 65 | */ 66 | public static InputStream getInputStream(URL url) throws IOException { 67 | // Open the connection 68 | URLConnection conn = url.openConnection(); 69 | 70 | // Connect to get the response headers 71 | conn.connect(); 72 | 73 | if ("application/vnd.google-earth.kmz".equals(conn.getContentType()) || 74 | url.getFile().toLowerCase(Locale.ROOT).endsWith(".kmz")) { 75 | // kmz file requires special handling 76 | // NOTE: some files ending with .kmz are actually KML (XML) files 77 | // examples: 78 | // http://www.strandbewertung.de/strandbewertung.kmz => Content-Type: application/vnd.google-earth.kmz 79 | // http://hemendikhortik.zxq.net/Eslovenia_en.kmz => Content-Type: text/plain 80 | ZipInputStream zis = new ZipInputStream(conn.getInputStream()); 81 | ZipEntry entry; 82 | // Simply find first kml file in the archive 83 | // 84 | // Note that KML documentation loosely defines that it takes first root-level KML file 85 | // in KMZ archive as the main KML document but Google Earth (version 4.3 as of Dec-2008) 86 | // actually takes the first kml file regardless of name (e.g. doc.kml which is convention only) 87 | // and whether its in the root folder or subfolder. Otherwise would need to keep track 88 | // of the first KML found but continue if first KML file is not in the root level then 89 | // backtrack in stream to first KML if no root-level KML is found. 90 | while ((entry = zis.getNextEntry()) != null) { 91 | // find first KML file in archive 92 | if (entry.getName().toLowerCase(Locale.ROOT).endsWith(".kml")) { 93 | return zis; // start reading from stream 94 | } 95 | } 96 | throw new IOException("Failed to find KML content in KMZ file"); 97 | } 98 | 99 | // Else read the raw bytes. 100 | return new BufferedInputStream(conn.getInputStream()); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | XmlValidate 2 | =========== 3 | 4 | A quick & flexible open source XML validator capable of performing bulk validation of XML documents against XML Schemas as defined in the XML documents or forcing another schema target. 5 | 6 | *XmlValidate* validates individual XML documents by filename or URL 7 | or recursively searching directories with a list of target file 8 | extensions. First documents are checked as being well-formed XML. 9 | If parsing XML with non-validating parser fails then validation for that 10 | file stops. 11 | 12 | Here are three ways to validate XML documents using *XmlValidate*: 13 | 14 | 1. The *-map* option maps schema namespaces to given target schema locations. 15 | It rewrites XML with location of schema instance document then validates against 16 | target schema. If schema namespace is not found then it does not validate 17 | the document. This validates the document against the actual schema namespace 18 | defined in the document as opposed to the other approaches that rewrite 19 | the XML documents to any target schema. 20 | 21 | old: <kml xmlns="http://earth.google.com/kml/2.1"> 22 | 23 | new: <kml xmlns="http://earth.google.com/kml/2.1" 24 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 25 | xsi:schemaLocation="http://earth.google.com/kml/2.1 file:/C:/xml/kml21.xsd"> 26 | 27 | Note if root element is "kml" and no namespace is specified then KML 2.0 namespace is used to validate document. 28 | 29 | 2. Specifing a schema without a namespace implies noNamespaceSchemaLocation attribute should be added to all XML documents and validate against that schema. 30 | no namespace schema: 31 | 32 | <event xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 33 | xsi:noNamespaceSchemaLocation="C:/cot/schema/Event.xsd"> 34 | 35 | 3. And finally specify -ns and -schema options to provide a target namespace URI and schema location. All XML documents specified in search location(s) will be rewritten and the target schemaLocation will be used regardless of the default namespace of that document. So for example KML 2.1 documents can be validated against the 2.2 schema, and vice versa. 36 | 37 | old: <kml xmlns="http://earth.google.com/kml/2.1"> 38 | 39 | new: <kml xmlns="http://www.opengis.net/kml/2.2" 40 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 41 | xsi:schemaLocation="http://www.opengis.net/kml/2.2 file:/C:/xml/kml22.xsd"> 42 | 43 | Note that XML is reformatted so errors/warnings with line/column numbers are respect to 44 | the reformatted content not the original so context is printed at that line/column number 45 | after each error in order that errors can be tracked down and corrected in original 46 | XML document. If you want the reformatted XML document printed then use *-dump* mode. 47 | If the error is in the XML Schema not the instance document then the context will not be printed. 48 | 49 | Building with Gradle 50 | -------------------- 51 | 52 | Type: ./gradlew test install 53 | 54 | The first time you run this it will download and install gradle. Downloaded files (including the Gradle 55 | distribution itself) will be stored in the Gradle user home directory (typically "/.gradle"). 56 | Subsequent runs will be much faster. 57 | 58 | If [Gradle](http://www.gradle.org) is already installed locally then just run: 59 | 60 | ./gradle test install 61 | 62 | Usage 63 | ----- 64 | 65 | Usage: *xv* [options] [-map=file] | [-schema=file (-ns=uri)] <xml-document file, URL, or directory...> 66 | 67 | Examples 68 | -------- 69 | 70 | 1. To check all .kml files against target KML 2.2 schema regardless of default schema used: 71 | 72 | `xv -kml -schema=C:/pathToXsd/kml22.xsd -ns=http://www.opengis.net/kml/2.2 C:/pathToMyKmlFiles` 73 | 74 | 2. To check kml and kmz files against local schemas as defined in KML files: 75 | 76 | `xv -kmz -map=ns.map C:/pathToMyKmlFiles` 77 | 78 | 3. Validate by URL for KML and target schema and print KML content 79 | if any errors are found but limit size of each file printed to first 4K: 80 | 81 | `xv -dump -maxDump=4096 -ns=http://earth.google.com/kml/2.1 -schema=http://code.google.com/apis/kml/schema/kml21.xsd http://kml-samples.googlecode.com/svn/trunk/kml/kmz/simple/big.kmz` 82 | 83 | Note: *xv* command in examples above is a short-cut to the provided .bat command using java and XmlValidate.jar on the CLASSPATH or by using an equivalent shell script. 84 | See xv.bat, kml21.bat, and kml22.bat for example usage. 85 | 86 | License 87 | ------- 88 | 89 | Copyright 2009-2023 The MITRE Corporation 90 | 91 | Licensed under the Apache License, Version 2.0 (the "License"); 92 | you may not use this file except in compliance with the License. 93 | You may obtain a copy of the License at 94 | 95 | http://www.apache.org/licenses/LICENSE-2.0 96 | 97 | Unless required by applicable law or agreed to in writing, software 98 | distributed under the License is distributed on an "AS IS" BASIS, 99 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 100 | See the License for the specific language governing permissions and 101 | limitations under the License. 102 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | XmlValidate is a quick & flexible XML validator capable of performing 2 | bulk validation of XML documents against XML Schemas as defined 3 | in the XML documents or forcing another schema target. 4 | 5 | Setup 6 | ===== 7 | 8 | From the command-line run gradle test command to build the project 9 | and run the tests. 10 | > gradle test 11 | 12 | Several .bat files are provided to run XmlValidate with various 13 | pre-defined options. These are located in the 'bin' directory. 14 | 15 | To run these .bat files you must first run the following command: 16 | > gradle install 17 | 18 | This copies dependent .jar to build/libs folder which is used for the 19 | classpath in each of the .bat files (e.g. bin/xv.bat). 20 | 21 | To test installation of XmlValidate run the run.bat script 22 | at the top-level of the distribution. 23 | 24 | If the output matches the following then the jars, test data, 25 | schemas, and batch files are in the correct locations. 26 | 27 | == run.bat output == 28 | 29 | This test batch file shows several typical ways 30 | to use XmlValidate with the sample XML data 31 | located in data directory, schemas in schemas/, 32 | and wrapper .bat files in /bin. 33 | ========================================== 34 | 35 | Validate CoT XML document with non-namespace schema 36 | > bin\xv -schema=schemas\Event.xsd -v data\cot.xml 37 | 38 | Check: data\cot.xml 39 | *OK* 40 | 41 | Errors: 0 Warnings: 0 Files: 1 Time: 250 ms 42 | Valid files 1/1 (100%) 43 | 44 | ========================================== 45 | 46 | Validate all KML/KMZ documents against KML 2.1 Schema 47 | > bin\kml21 -kmz data 48 | 49 | Errors: 0 Warnings: 0 Files: 5 Time: 328 ms 50 | Valid files 3/3 (100%) 51 | 52 | Same as running the following: 53 | > bin\xv -kmz -ns=http://earth.google.com/kml/2.1 -schema=schemas\kml21.xsd data 54 | 55 | ========================================== 56 | 57 | Validate all GPX/KML/KMZ documents 58 | > bin\xv.bat -v -kmz -x=gpx data/xml data/kml data/kmz 59 | dir: data\xml 60 | 61 | Check: data\xml\mystic_basin_trail.gpx 62 | *OK* 63 | dir: data\kml 64 | 65 | Check: data\kml\data-ext-atom.kml 66 | assign Namespace http://www.w3.org/2005/Atom -> file:/C:/projects/xmlValidate/temp/XmlValidate/schemas/atom.xsd 67 | *OK* 68 | 69 | Check: data\kml\earth-google-com-kml-21.kml 70 | *OK* 71 | 72 | Check: data\kml\earth-google-com-kml-22.kml 73 | *OK* 74 | 75 | Check: data\kml\no-namespace.kml 76 | INFO: no root namespace 77 | *OK* 78 | 79 | Check: data\kml\nonkmlroot.kml 80 | *OK* 81 | 82 | Check: data\kml\placemark.kml 83 | *OK* 84 | 85 | Check: data\kml\tessellate-orig.kml 86 | http://www.opengis.net/kml/2.2 87 | ERROR: SAXParseException org.xml.sax.SAXParseException; lineNumber: 27; columnNumber: 13; cvc-complex-type.2.4.a: Invalid content was found starting with element 'tilt'. One of '{"http://www.opengis.net/kml/2.2":altitudeModeGroup, "http://www.opengis.net/kml/2.2":LookAtSimpleExtensionGroup, "http://www.opengis.net/kml/2.2":LookAtObjectExtensionGroup}' is expected. 88 | Line: 27, column: 13 89 | 27: ***62.04855796276328 90 | 91 | Check: data\kml\tessellate21.kml 92 | *OK* 93 | 94 | Check: data\kml\tessellate22.kml 95 | *OK* 96 | dir: data\kmz 97 | 98 | Check: data\kmz\big.kmz 99 | *OK* 100 | 101 | Check: data\kmz\nested.kmz 102 | *OK* 103 | 104 | Errors: 1 Warnings: 0 Files: 12 Time: 895 ms 105 | Valid files 11/12 (92%) 106 | 107 | 108 | Notice the tessellate-orig.kml example has the wrong namespace 109 | and fails to validate against the specified schema namespace. 110 | 111 | ========================================== 112 | 113 | 114 | Running 115 | ======= 116 | 117 | Next run XmlValidate on your own XML documents using appropriate 118 | .bat file (xv.bat, kml22.bat, etc.). 119 | 120 | Run xv.bat on your favorite XML files by filename, directory, or URL. 121 | 122 | 123 | Configuration 124 | ============= 125 | 126 | The file ns.map provides the namespace and locations of the target 127 | XML schemas intially populated with a set of common schemas 128 | (e.g. KML, GPX). You can add additional XML Schemas to the ns.map 129 | file as needed by URL or absolute file location. 130 | 131 | For example if you wanted to validate the web.xml file deployed in a Java web 132 | application WAR file assuming the web.xml file starts like this: 133 | 134 | 135 | 136 | ... 137 | 138 | Add this entry to your ns.map file to validate such files. 139 | http://java.sun.com/xml/ns/javaee=http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd 140 | 141 | If you want to make local copies of the XML Schemas then you can add them to 142 | your XmlValidate/schemas directory as reference them like this: 143 | http://java.sun.com/xml/ns/javaee=${XV_HOME}/schemas/web-app_2_5.xsd 144 | or add any directory of your choosing and reference with an absolute path: 145 | http://java.sun.com/xml/ns/javaee=C:/xml/schemas/web-app_2_5.xsd 146 | 147 | If you want to make a one-time mapping to XML Schema or override the mappings then use 148 | -schemaLocation command-line argument. 149 | Example usage: 150 | xv -schemaLocation=http://java.sun.com/xml/ns/javaee=C:/xml/schemas/web-app_2_5.xsd web.xml 151 | 152 | -- 153 | -------------------------------------------------------------------------------- /src/main/java/org/mitre/xml/validate/FileResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * FileResource.java 3 | * 4 | * (C) Copyright MITRE Corporation 2009 5 | * 6 | * The program is provided "as is" without any warranty express or implied, including 7 | * the warranty of non-infringement and the implied warranties of merchantibility and 8 | * fitness for a particular purpose. The Copyright owner will not be liable for any 9 | * damages suffered by you as a result of using the Program. In no event will the 10 | * Copyright owner be liable for any special, indirect or consequential damages or 11 | * lost profits even if the Copyright owner has been advised of the possibility of 12 | * their occurrence. 13 | * 14 | */ 15 | package org.mitre.xml.validate; 16 | 17 | import org.jdom2.Document; 18 | import org.jdom2.JDOMException; 19 | import org.jdom2.input.SAXBuilder; 20 | 21 | import java.io.DataInputStream; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.IOException; 25 | import java.io.PrintStream; 26 | import java.util.Locale; 27 | import java.util.zip.ZipException; 28 | import java.util.zip.ZipFile; 29 | import java.util.zip.ZipEntry; 30 | import java.util.Enumeration; 31 | import java.util.zip.ZipInputStream; 32 | 33 | /** 34 | * File resource that implements building a JDOM Document instance 35 | * from a file reference. 36 | * 37 | * @author Jason Mathews, MITRE Corp. 38 | * Date: Feb 13, 2009 7:17:23 PM 39 | */ 40 | public class FileResource extends Resource { 41 | 42 | private final File file; 43 | private boolean isKmzFile; 44 | 45 | public FileResource(PrintStream out, File file, String schemaNamespace) { 46 | super(out, file.toString(), schemaNamespace); 47 | this.file = file; 48 | } 49 | 50 | public Document getDocument(SAXBuilder builder) throws JDOMException, IOException { 51 | if (doc == null) doc = buildDocument(builder); 52 | return doc; 53 | } 54 | 55 | public String getSource() { 56 | return file.toString(); 57 | } 58 | 59 | public File getFile() { 60 | return file; 61 | } 62 | 63 | public boolean isKmzFile() { 64 | return isKmzFile; 65 | } 66 | 67 | private Document buildDocument(SAXBuilder builder) throws JDOMException, IOException { 68 | // if KMZ file has .kml extension then out of luck - it will fail to parse 69 | // KMZ files must have .kmz extension - case doesn't matter 70 | if (!file.getName().toLowerCase(Locale.ROOT).endsWith(".kmz")) { 71 | return builder.build(file); 72 | } 73 | // otherwise try finding KML in compressed KMZ file 74 | // NOTE: only the first "root" KML file is fetched. Supporting KML files will not be validated here. 75 | // If KmzMode is enabled then all KML entries inside KMZ file will be extracted using KmzExplorer class. 76 | try( 77 | ZipFile zf = new ZipFile(file) 78 | ) { 79 | // attempt #1: try to find the root kml file 80 | Enumeration e = zf.entries(); 81 | while (e.hasMoreElements()) { 82 | ZipEntry entry = e.nextElement(); 83 | // Simply find first kml file in the archive 84 | // 85 | // Note that KML documentation loosely defines that it takes first root-level KML file 86 | // in KMZ archive as the main KML document but Google Earth (version 4.3 as of Dec-2008) 87 | // actually takes the first kml file regardless of name (e.g. doc.kml which is convention only) 88 | // and whether its in the root folder or subfolder. Otherwise would need to keep track 89 | // of the first KML found but continue if first KML file is not in the root level then 90 | // backtrack in stream to first KML if no root-level KML is found. 91 | if (entry.getName().toLowerCase(Locale.ROOT).endsWith(".kml")) { 92 | isKmzFile = true; 93 | return builder.build(zf.getInputStream(entry), 94 | file.getAbsoluteFile().toURI().toString()); 95 | } 96 | } 97 | 98 | throw new IOException("Failed to find KML content in KMZ file"); 99 | } catch (ZipException ze) { 100 | // attempt #2 101 | // some KMZ files fail to open using ZipFile but work using ZipInputStream 102 | // bug was present in JRE 1.6.0_45 but appears to have been fixed in 1.7.0 103 | // URL: http://www.campinglimens.com/Camping_Limens.kmz 104 | // file had invalid timestamps in the zip entry header 105 | ZipInputStream zis = null; 106 | try { 107 | zis = new ZipInputStream(new FileInputStream(file)); 108 | ZipEntry entry; 109 | while ((entry = zis.getNextEntry()) != null) { 110 | if (entry.getName().toLowerCase(Locale.ROOT).endsWith(".kml")) { 111 | printFile(); 112 | String msg = ze.toString();// e.g. java.util.zip.ZipException: error in opening zip file 113 | out.println("WARN: ZipFile failed [retry using ZipInputStream]: " + msg); 114 | stats.add("WARN: " + msg); 115 | warnings++; 116 | isKmzFile = true; 117 | return builder.build(zis, 118 | file.getAbsoluteFile().toURI().toString()); 119 | } 120 | } 121 | } catch(IOException ioe) { 122 | // ignore ZipInputStream exceptions and throw original exception if next attempt also fails 123 | } 124 | if (zis != null) { 125 | try { 126 | zis.close(); 127 | } catch (IOException ioe) { 128 | // ignore 129 | } 130 | } 131 | 132 | // attempt #3 133 | // some .kmz files are really KML text files... verify header 134 | // examples: 135 | // http://www.strandbewertung.de/strandbewertung.kmz => Content-Type: application/vnd.google-earth.kmz 136 | // http://hemendikhortik.zxq.net/Eslovenia_en.kmz => Content-Type: text/plain 137 | try( 138 | FileInputStream fis = new FileInputStream(file); 139 | DataInputStream is = new DataInputStream(fis) 140 | ) { 141 | final short hdr = is.readShort(); 142 | // KMZ/ZIP header start with bytes: PK\0x3\0x4 143 | if (hdr != 0x504B) { 144 | // try as KML (XML) file 145 | Document doc = builder.build(file); 146 | final String msg = "WARN: " + ze; // e.g. java.util.zip.ZipException: error in opening zip file 147 | stats.add(msg); 148 | printFile(); 149 | out.println(msg); 150 | out.println("WARN: KMZ file is invalid/mislabeled. Retry as KML"); 151 | warnings++; 152 | return doc; 153 | } 154 | } catch(Exception e) { 155 | // ignore retry exception and allow ZipException to be rethrown 156 | } 157 | 158 | throw ze; // rethrow exception if all attempts fail 159 | } 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /data/xml/mystic_basin_trail.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Mystic River Basin Trails 7 | Both banks of the lower Mystic River have paved trails, allowing for a short and a long loop along the water. The short loop is a two mile trail with no road crossings. The long loop adds side-trips out to Draw Seven Park and the MBTA yard at Wellington Station, but crosses the six lanes of Route 28 twice. 8 | Dan Foster 9 | trails@topografix.com 10 | http://www.tufts.edu/mystic/amra/pamphlet.html 11 | Lower Mystic Basin Trails 12 | 13 | mystic river, medford, tufts, biking, trail, draw seven park, wellington, amelia earhart dam 14 | 15 | 16 | 13.106400 17 | 18 | 205A 19 | CSO 205A 20 | Concrete platform looking out onto the Mystic. 21 | While you take in the view, try not to think about the fact that you're standing on top of MWRA Wet Water Discharge Outflow #205A 22 | Scenic Area 23 | Overlook 24 | 25 | 26 | ASSEMBLYSQ 27 | ASSEMBLY SQUARE MALL 28 | Assembly Square Mall 29 | Shopping Center 30 | Shopping Mall 31 | 32 | 33 | BLESSING 34 | BLESSING OF THE BAY 35 | The Blessing of the Bay Boathouse, now run by the Somerville Boys and Girls Club. 36 | A dock with small boats for the children of Somerville. Check out the Mystic River mural at the intersection of Shore Drive and Rt 16! 37 | http://www.everydaydesign.com/ourtown/bay.html 38 | Boat-building on the Mystic River 39 | Boat Ramp 40 | Boat Launch 41 | 42 | 43 | 10.698480 44 | 45 | BLOCK 1 46 | Concrete platform looking out onto the Mystic 47 | Scenic Area 48 | Overlook 49 | 50 | 51 | CROSSWALK1 52 | CROSSWALK 53 | Crosswalk 54 | Dot 55 | Crosswalk 56 | 57 | 58 | CROSSWALK2 59 | Crosswalk 60 | Dot 61 | Crosswalk 62 | 63 | 64 | DRAW 7 65 | DRAW SEVEN BRIDGE 66 | Draw Seven Bridge 67 | Bridge 68 | Bridge 69 | 70 | 71 | DRAW7PK 72 | DRAW SEVEN PARK 73 | Draw Seven Park 74 | Park 75 | Park 76 | 77 | 78 | 10.942320 79 | 80 | EARHARTDAM 81 | AMELIA EARHART DAM 82 | Amelia Earhart Dam 83 | Dam 84 | Dam 85 | 86 | 87 | 6.370320 88 | 89 | FISH DOCK 90 | FISHING DOCK 91 | A wooden fishing dock along the Mystic River in the middle of Torbert McDonald Park. 92 | Anchor 93 | Dock 94 | 95 | 96 | LOOP 97 | STARTING POINT FOR LOOP TRAILS 98 | Starting point for the Mystic River loop trails. 99 | Trail Head 100 | Junction 101 | 102 | 103 | MEADOWGLEN 104 | MEADOW GLEN MALL 105 | Meadow Glen Mall 106 | http://www.meadowglen.com/ 107 | Meadow Glen Mall 108 | Shopping Center 109 | Shopping Mall 110 | 111 | 112 | 8.778240 113 | 114 | OBS TOWER 115 | OBSERVATION TOWER 116 | Observation Tower in Torbert McDonald Park. 117 | There are good views of the river from atop the wooden observation tower. 118 | Tall Tower 119 | Tower 120 | 121 | 122 | PARKING 123 | PARKING LOT 124 | Parking Lot 125 | Parking Area 126 | Parking 127 | 128 | 129 | RT 16 130 | LAWRENCE BRIDGE 131 | General Lawrence Bridge. Route 16 crosses the Mystic River. The bike path continues under the bridge on the east side of the river, but is currently torn up by construction near Hormel Stadium. 132 | Bridge 133 | Bridge 134 | 135 | 136 | RT 28 137 | WELLINGTON BRIDGE 138 | Wellington Bridge 139 | Route 28 crosses the Mystic River on this 6 lane bridge. Pedestrian walkways on both sides. Access to the Assembly Square mall is at the south end of the bridge. 140 | Bridge 141 | Bridge 142 | 143 | 144 | ST POLICE 145 | STATE POLICE 146 | State Police Barracks 147 | Building 148 | Building 149 | 150 | 151 | THE BEACH 152 | SOMERVILLE BEACH 153 | The "Somerville Beach" 154 | People actually used to swim here. Now only shopping carts do. 155 | Swimming Area 156 | Beach 157 | 158 | 159 | TUFTS PARK 160 | TUFTS PARK 161 | Tufts Park 162 | http://www.wallacefloyd.com/los/tufts/tufts.htm 163 | Tufts Park Redesign 164 | Park 165 | Park 166 | 167 | 168 | WELL YACHT 169 | WELLINGTON YACHT CLUB 170 | Mystic Wellington Yacht Club 171 | Boat Ramp 172 | Boat Launch 173 | 174 | 175 | WELLING PT 176 | Wellington Point 177 | The bike trail is unpaved beyond this point. A dirt road continues under the railroad bridge. Continue at your own risk... 178 | Danger Area 179 | Dead End 180 | 181 | 182 | WELLINGTON 183 | WELLINGTON 184 | Wellington 185 | http://www.mbta.com/schedmaps/subway/wellingtonstop.cfm 186 | Wellington MBTA Schedule 187 | RV Park 188 | Station 189 | 190 | 191 | YACHT CLUB 192 | WINTER HILL YACHT CLUB 193 | Winter Hill Yacht Club 194 | Boat Ramp 195 | Boat Launch 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /src/main/java/org/mitre/xml/validate/Resource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Resource.java 3 | * 4 | * (C) Copyright MITRE Corporation 2009 5 | * 6 | * The program is provided "as is" without any warranty express or implied, including 7 | * the warranty of non-infringement and the implied warranties of merchantibility and 8 | * fitness for a particular purpose. The Copyright owner will not be liable for any 9 | * damages suffered by you as a result of using the Program. In no event will the 10 | * Copyright owner be liable for any special, indirect or consequential damages or 11 | * lost profits even if the Copyright owner has been advised of the possibility of 12 | * their occurrence. 13 | * 14 | */ 15 | package org.mitre.xml.validate; 16 | 17 | import org.jdom2.Document; 18 | import org.jdom2.JDOMException; 19 | import org.jdom2.output.XMLOutputter; 20 | import org.jdom2.input.SAXBuilder; 21 | import org.xml.sax.ErrorHandler; 22 | import org.xml.sax.SAXException; 23 | import org.xml.sax.SAXParseException; 24 | 25 | import java.io.IOException; 26 | import java.io.LineNumberReader; 27 | import java.io.StringReader; 28 | import java.io.PrintStream; 29 | import java.util.HashSet; 30 | import java.util.Set; 31 | 32 | /** 33 | * Abstract Resource object used by XmlValidator 34 | * whose implementation may be a URL or a File. 35 | * 36 | * @author Jason Mathews, MITRE Corp. 37 | * Date: Feb 13, 2009 7:07:51 PM 38 | * 39 | * Changes: 40 | * 03/23/09 Suppress printing error context for XML Schema errors as opposed 41 | * to validation errors in the target XML source. 42 | */ 43 | public abstract class Resource implements ErrorHandler { 44 | 45 | protected Document doc; 46 | 47 | private String schemaNamespace; 48 | 49 | protected final String targetFile; 50 | 51 | private LineNumberReader lnr; 52 | 53 | private boolean schemaPrinted; 54 | 55 | private boolean summary; 56 | 57 | // used in validateFile/printFile to print file summary info once on errors or verbose mode 58 | private boolean printed; 59 | 60 | private String xmlContent; 61 | 62 | protected final PrintStream out; 63 | 64 | int warnings; 65 | 66 | int errors; 67 | 68 | protected final Set stats = new HashSet<>(); 69 | 70 | private int dumpLevel; 71 | private int dumpLimit; 72 | protected final boolean debug; 73 | private String defaultNamespace; 74 | 75 | public Resource(PrintStream out, String target, String schemaNamespace) { 76 | this.out = out; 77 | this.targetFile = target; 78 | this.schemaNamespace = schemaNamespace; 79 | debug = Boolean.getBoolean("debug"); 80 | } 81 | 82 | public abstract String getSource(); 83 | 84 | public int getErrors() { 85 | return errors; 86 | } 87 | 88 | public int getWarnings() { 89 | return warnings; 90 | } 91 | 92 | public void printFile() { 93 | if (!printed) { 94 | if (targetFile != null) out.println("\nCheck: " + targetFile); 95 | printed = true; 96 | } 97 | // dump XML for dump Level == 1 (on error condition) 98 | if (dumpLevel == 1) 99 | dumpContent(); 100 | } 101 | 102 | public void dumpContent() { 103 | if (dumpLevel != 0 && xmlContent != null) { 104 | String outContent = xmlContent; 105 | if (dumpLimit > 0 && xmlContent.length() > dumpLimit) 106 | outContent = xmlContent.substring(0, dumpLimit) + "..."; // dump partial output 107 | out.println(outContent); 108 | out.println(); 109 | dumpLevel = 0; // don't dump again 110 | } 111 | } 112 | 113 | public abstract Document getDocument(SAXBuilder builder) throws JDOMException, IOException; 114 | 115 | public Set getStats() { 116 | return stats; 117 | } 118 | 119 | private void handleException(String s, SAXParseException exception) { 120 | if (summary) { 121 | /* 122 | cvc-attribute.3: The value '6742738' of attribute 'id' on element 'Placemark' is not valid with respect to its type, 'ID'. 123 | cvc-complex-type.2.4.a: Invalid content was found starting with element 'LatLonAltBox'. One of '{"http://www.opengis.net/kml/2.2":RegionSimpleExtensionGroup, "http://www.opengis.net/kml/2.2":RegionObjectExtensionGroup}' is expected. 124 | cvc-complex-type.2.4.d: Invalid content was found starting with element 'Style'. No child element is expected at this point. 125 | cvc-complex-type.3.2.2: Attribute 'maxLength' is not allowed to appear in element 'Snippet'. 126 | cvc-datatype-valid.1.2.1: '#ff0000ff' is not a valid value for 'hexBinary'. 127 | cvc-enumeration-valid: Value 'relative' is not facet-valid with respect to enumeration '[clampToGround, relativeToGround, absolute]'. It must be a value from the enumeration. 128 | cvc-id.2: There are multiple occurrences of ID value 'placemarkAlgeria'. 129 | cvc-length-valid: Value '000000' with length = '3' is not facet-valid with respect to length '4' for type 'color'. 130 | cvc-maxInclusive-valid: Value '270.0' is not facet-valid with respect to maxInclusive '1.8E2' for type 'angle180Type'. 131 | cvc-type.3.1.2: Element 'description' is a simple type, so it must have no element information item [children]. 132 | */ 133 | String message = exception.getMessage(); 134 | int ind = message.indexOf(':'); 135 | if (ind > 0) message = message.substring(0,ind); 136 | stats.add(s + ": " + message); 137 | return; 138 | } 139 | printFile(); 140 | if (!schemaPrinted && schemaNamespace != null) { 141 | out.println(schemaNamespace); 142 | schemaPrinted = true; 143 | } 144 | if (debug) exception.printStackTrace(); 145 | int lineNumber = exception.getLineNumber(); 146 | out.print(s + ": SAXParseException " + exception 147 | + "\nLine: " + lineNumber 148 | + ", column: " + exception.getColumnNumber()); 149 | String pubId = exception.getPublicId(); 150 | if (pubId != null) out.println(", publicId=" + pubId); 151 | String sysId = exception.getSystemId(); 152 | if (sysId != null) out.println(", systemId=" + sysId); 153 | out.println(); 154 | // if systemId not null then assume error is in XML Schema not XML source 155 | // so don't try to show error context in XML source. 156 | // TODO: can systemId be non-null and have error in XML source ?? 157 | if (lnr != null && lineNumber != -1 && sysId == null) { 158 | try { 159 | String line = null; 160 | // line numbers show be in increasing order so should never have to backtrack 161 | if (lnr.getLineNumber() > lineNumber) { 162 | lnr.reset(); 163 | if (debug) System.err.println("DEBUG: reset line number: " + lnr.getLineNumber()); 164 | } 165 | while (lnr.getLineNumber() < lineNumber && (line = lnr.readLine()) != null) { 166 | // skip lines until we reach target line number 167 | } 168 | if (line != null && line.length() != 0) { 169 | int col = exception.getColumnNumber() - 1; 170 | //out.println("col=" + col + " ll="+line.length()); 171 | if (col > 0 && col <= line.length()) { 172 | if (col > 80) 173 | line = "..." + line.substring(col - 50, col) + "***" + line.substring(col); 174 | else 175 | line = line.substring(0, col) + "***" + line.substring(col); 176 | } // else out.format("linelen: %d col: %d%n", line.length(), col); 177 | line = line.trim(); 178 | if (line.length() > 80) 179 | line = line.substring(0, 78) + "..."; 180 | out.format("%d: %s%n", lineNumber, line); 181 | } 182 | } catch (IOException e) { 183 | if (debug) e.printStackTrace(); 184 | // otherwise ignore 185 | } 186 | } 187 | } 188 | 189 | public void warning(SAXParseException exception) throws SAXException { 190 | handleException("WARN", exception); 191 | warnings++; 192 | } 193 | 194 | public void error(SAXParseException exception) throws SAXException { 195 | handleException("ERROR", exception); 196 | errors++; 197 | } 198 | 199 | public void fatalError(SAXParseException exception) throws SAXException { 200 | handleException("FATAL", exception); 201 | errors++; 202 | } 203 | 204 | public String getXmlContent() { 205 | if (xmlContent == null) { 206 | XMLOutputter xo = new XMLOutputter(); 207 | xo.setFormat(org.jdom2.output.Format.getPrettyFormat()); 208 | 209 | // TODO: non-UTF8 encoding is overriden with UTF-8 type 210 | 211 | xmlContent = xo.outputString(doc); 212 | lnr = new LineNumberReader(new StringReader(xmlContent)); 213 | } 214 | return xmlContent; 215 | } 216 | 217 | public String getDefaultNamespace() { 218 | return defaultNamespace; 219 | } 220 | 221 | public void setSchemaNamespace(String schemaNamespace) { 222 | this.schemaNamespace = schemaNamespace; 223 | } 224 | 225 | public void setDumpLevel(int dumpLevel) { 226 | this.dumpLevel = dumpLevel; 227 | } 228 | 229 | public void setDumpLimit(int dumpLimit) { 230 | this.dumpLimit = dumpLimit; 231 | } 232 | 233 | public void setSummary(boolean summary) { 234 | this.summary = summary; 235 | } 236 | 237 | public void setDefaultNamespace(String defaultNamespace) { 238 | this.defaultNamespace = defaultNamespace; 239 | } 240 | 241 | public void close() { 242 | if (lnr != null) 243 | try { 244 | lnr.close(); 245 | } catch (IOException e) { 246 | // ignore 247 | } 248 | } 249 | 250 | /* 251 | public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { 252 | //out.println("entity=" + publicId + " " + systemId); 253 | return null; 254 | } 255 | */ 256 | 257 | public boolean isPrinted() { 258 | return printed; 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /schemas/gpx10.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /schemas/kml22gx.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 65 | 67 | 69 | 72 | 74 | 75 | 77 | 78 | 79 | 80 | 82 | 83 | 84 | 86 | 88 | 89 | 91 | 93 | 95 | 97 | 99 | 100 | 103 | 104 | 105 | 107 | 109 | 111 | 113 | 114 | 115 | 116 | 117 | 118 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 157 | 158 | 159 | 160 | 161 | 163 | 164 | 165 | 166 | 167 | 168 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 195 | 197 | 199 | 200 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 253 | 254 | 255 | 256 | 257 | 258 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 275 | 276 | 277 | 278 | 279 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 325 | 326 | 327 | 328 | 329 | 330 | -------------------------------------------------------------------------------- /schemas/Event.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 18 | Event Definition 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | The "type" attribute is a composite of components delimited by the semi-colon 36 | character. The first component of this composite attribute is defined below. 37 | Future versions of this schema will define other components which we expect 38 | will aid in machine filtering. Despite the exclusion of definitions 39 | for additional components in this version of the schema, users of 40 | this schema should expect and design an optional trailing field 41 | delimited by the semi-colon character. This field can be ignored. 42 | 43 | component1;optional field 44 | 45 | The first component (component1) is a hierarchically organized hint about type. 46 | The intention is that this hierarchy be flexible and extensible and 47 | facilitate simple filtering, translation and display. To 48 | facilitate filtering, the hierarchy needs to present key 49 | fields in an easily parsed and logical order. To facilitate 50 | this, this component is a composite of fields separated by the "-" punctuation 51 | character, so a valid type would be: x-x-X-X-x. Using a 52 | punctuation for field separation allows arbitrary expansion of the 53 | type space, e.g., a-fzp-mlk-gm-... 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | The access field is intended to indicates who has access to this 66 | event. (e.g. unrestricted, nato, army, coalition...) 67 | It is currently defined as a string, and is optional in V2.0. 68 | Future version of the event schema will provide formal 69 | definition of this field. 70 | 71 | 72 | 73 | 74 | 75 | 76 | format - digit-character-character as defined below 77 | 78 | The QoS attribute will determine the preferential treatment events 79 | receive as they proceed through the kill chain. The field has 80 | several distinct but related components. 81 | 82 | A "priority" value indicates queuing and processing order for 83 | competing events. At a processing bottleneck (e.g., bandwidth 84 | limited link) high priority events will be processed before lower 85 | priority events. Priority determines queuing order at a 86 | bottleneck. 87 | 88 | 9 - highest (most significant) priority 89 | 0 - lowest (least significant) priority 90 | 91 | A "overtaking" value indicates how two events for the same uid are 92 | reconciled when they "catch up" to one another. The more recent 93 | event (by timestamp) may supersede the older event (deleting the 94 | old event) when it catches it, or it may follow the old event so 95 | that event order is preserved, or it may be routed independently 96 | of previous events. 97 | 98 | r - replace - new event replaces (deletes) old event 99 | f - follow - new event must follow previous events 100 | i - independent - new event processed independently of old events 101 | 102 | An "assurance" value indicates how much effort must be placed in 103 | delivering this particular event. Events from sources that 104 | continually send updates (blue force tracks) or that are sent for 105 | information purposes only require a lower level of delivery 106 | effort. Events that are singletons (sent only once) and are 107 | critical require guaranteed delivery. 108 | 109 | g - guaranteed delivery (message never dropped even if delivered late) 110 | d - deadline (message dropped only after "stale" time) 111 | c - congestion - message dropped when link congestion encountered 112 | 113 | Thus, a valid QoS field looks like: 114 | 115 | qos="1-r-c" 116 | 117 | Note that different events with the same UID may have differing 118 | QoS values. This enables a graceful degradation in the presence 119 | of congestion. For example, a blue force tracker may output a 120 | sequence of events with like 121 | ... qos="1-r-c" ... frequent, low priority updates 122 | ... qos="1-r-c" ... 123 | ... qos="1-r-c" ... 124 | ... qos="5-r-d" ... occasional "push" priority update 125 | ... qos="1-r-c" ... 126 | ... qos="1-r-c" ... 127 | ... qos="9-r-g" ... "Mayday" position report 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | The opex field is intended to indicate that the event is part of a 141 | live operation, an exercise, or a simulation. For backward compatibility, absence 142 | of the opex indicates "no statement", which will be interpreted in 143 | an installation specific manner. 144 | 145 | opex="o-<name>" or "e-<nickname>" or "s-<nickname>", 146 | where "-<name>" is optional. That is, it is permissible to 147 | specify only "o", "e", or "s" for the opex value. 148 | 149 | o = operations 150 | e = exercise 151 | s = simulation 152 | 153 | 154 | 155 | 156 | 157 | 158 | The "uid" attribute is a globally unique name for this specific piece of information. 159 | Several "events" may be associated with one UID, but in that case, the latest (ordered by timestamp), 160 | overwrites all previous events for that UID. 161 | 162 | 163 | 164 | 165 | 166 | 167 | The CoT XML schema includes three time values: 168 | time, start, and stale. "time" is a time stamp placed on the event 169 | when generated. start and stale define an interval in time for which 170 | the event is valid. Example: For the scenario where we have intel 171 | reports about a meeting of terrorist operatives later in the day: An 172 | event might be generated at noon (time) to describe a ground based 173 | target which is valid from 1300 (start) until 1330 (stale). All time 174 | fields are required. In version 1.1 of the CoT schema, the time and stale 175 | attributes together defined and interval of time for which the event was 176 | valid. In V2.0, time indicates the "birth" of an event and the start and stale pair 177 | define the validity interval. 178 | 179 | The "time" attribute is a time stamp indicating when an event was generated. 180 | The format of time, start, and stale are in standard date format (ISO 8601): 181 | CCYY-MM-DDThh:mm:ss.ssZ (e.g., 2002-10-05T17:01:14.00Z), where the presence of 182 | fractional seconds (including the delimeter) is optional. Also, there is no constraint 183 | on the number of digits to use for fractional seconds. The following are all valid: 184 | 2002-10-05T18:00:23Z, 2002-10-05T18:00:23.12Z, 2002-10-05T18:00:23.123456Z 185 | 186 | 187 | 188 | 189 | 190 | 191 | format - DTG 192 | 193 | The "start" attribute defines the starting time of the event's validity 194 | interval. The start and stale fields together define an interval in time. 195 | It has the same format as time and stale. 196 | 197 | 198 | 199 | 200 | 201 | 202 | The "stale" attribute defines the ending time of the event's validity 203 | interval. The start and stale fields together define an interval in time. 204 | It has the same format as time and start. 205 | 206 | 207 | 208 | 209 | 210 | 211 | format = character-character 212 | 213 | The "how" attribute gives a hint about how the coordinates were 214 | generated. It is used specifically to relay a hint about the 215 | types of errors that may be expected in the data and to weight the 216 | data in systems that fuse multiple inputs. For example, 217 | coordinates transcribed by humans may have digit transposition, 218 | missing or repeated digits, estimated error bounds, etc. As such, 219 | they may require special attention as they propagate through the 220 | kill chain (e.g., they may require an additional review). 221 | Similarly, machine generated coordinates derived solely from 222 | magnetic sources may be subject to known anomalies in certain 223 | geographical areas, etc. 224 | 225 | h - human entered or modified (someone typed the coordinates) 226 | e - estimated (a swag by the user) 227 | c - calculated (user probably calculated value by hand) 228 | t - transcribed (from voice, paper, ...) 229 | p - cut and paste from another window 230 | m - machine generated 231 | i - mensurated (from imagery) 232 | g - derived from GPS receiver 233 | m - magnetic - derived from magnetic sources 234 | s - simulated - out of a simulation 235 | f - fused - corroborated from multiple sources 236 | c - configured - out of a configuration file 237 | p - predicted - prediction of future (e.g., a from a tracker) 238 | r - relayed - imported from another system (gateway) 239 | 240 | As with other compound fields, the elements of the how field 241 | will be delimited by the field separator character "-". E.g, 242 | A coordinate mensurated from imagery would have a how field of "m-i". 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | format = XML schema defined outside of this document 257 | 258 | Detail entities... 259 | 260 | The "detail" entity is intended to carry information that is 261 | specific to smaller communities of producers and consumers and 262 | require more intimate knowledge of the operating domain. For 263 | example, mensurated "target" events may come from dramatically 264 | different sources and need to propagate dramatically different 265 | "detail" information. A close-air-support mission will augment 266 | target details with initial point and callsign details to 267 | facilitate coordination of weapon delivery. In contrast, a 268 | mission planning system may augment planned targets with target 269 | catalog information and weapon fuzing requirements. 270 | 271 | Because the "details" portion of the event are of interest only to 272 | a subset of subscribers, that entity may be mentioned by reference 273 | when the event is communicated. This reduces the congestion when 274 | events are transmitted over bandwidth limited links and also 275 | prevents the retransmission of static data elements. 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | Latitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. -33.350000). Range -90 -> +90. 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | Longitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. 44.383333). Range -180 -> +180. 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | HAE acronym for Height above Ellipsoid based on WGS-84 ellipsoid (measured in meters). 312 | 313 | 314 | 315 | 316 | 317 | Circular Error around point defined by lat and lon fields in meters. Although 318 | named ce, this field is intended to define a circular area around the event point, not 319 | necessarily an error (e.g. Describing a reservation area is not an 320 | "error"). If it is appropriate for the "ce" field to represent 321 | an error value (e.g. event describes laser designated target), the 322 | value will represent the one sigma point for a zero mean 323 | normal (Guassian) distribution. 324 | 325 | 326 | 327 | 328 | 329 | 330 | Linear Error in meters associated with the HAE field. Although named le, this 331 | field is intended to define a height range about the event point, not 332 | necessarily an error. This field, along with the ce field allow for the 333 | definition of a cylindrical volume about the point. If it is appropriate 334 | for the "le" field to represent an error (e.g. event describes laser 335 | designated target), the value will represent the one sigma point for 336 | a zero mean normal (Guassian) distribution. 337 | 338 | 339 | 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | XmlValidate 7 | 44 | 45 | 46 |
47 |

XmlValidate

48 |
49 |
50 | 51 |

Introduction

52 |

53 | XmlValidate is a quick & flexible XML validator capable of performing bulk 54 | validation of XML documents against XML Schemas 55 | as defined in the XML documents or forcing another schema target. 56 |

57 |
58 |

59 | XmlValidate validates individual XML documents by filename or URL 60 | or recursively searching directories with a list of target file 61 | extensions.  First documents are checked as being well-formed XML. 62 |  If parsing XML with non-validating parser fails then validation for that 63 | file stops. 64 |

65 |
66 |

67 | Here are three ways to validate XML documents using XmlValidate: 68 |

69 |
70 | 71 |
    72 |
  1. 73 |

    74 | The -map option maps schema namespaces to given target schema locations. 75 | It rewrites XML with location of schema instance document then validates against 76 | target schema.  If schema namespace is not found then it does not validate 77 | the document.  This validates the document against the actual schema namespace 78 | defined in the document as opposed to the other approaches that rewrite 79 | the XML documents to any target schema. 80 |

    81 |
     82 |   old: <kml xmlns="http://earth.google.com/kml/2.1">
     83 | 
     84 |   new: <kml xmlns="http://earth.google.com/kml/2.1"
     85 | 		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     86 | 		xsi:schemaLocation="http://earth.google.com/kml/2.1 file:/C:/xml/kml21.xsd">
     87 | 
    88 |

    Note if root element is "kml" and no namespace is specified then KML 2.0 namespace is used to validate document.

    89 |
  2. 90 | 91 |
  3. 92 |

    93 | Specifing a schema without a namespace implies noNamespaceSchemaLocation 94 | attribute should be added to all XML documents and validate against that schema. 95 |

    96 |
     97 |  no namespace schema:
     98 | 
     99 |      <event xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    100 |       xsi:noNamespaceSchemaLocation="C:/cot/schema/Event.xsd">
    101 | 
    102 |
  4. 103 | 104 |
  5. 105 |

    106 | And finally specify -ns and -schema options to provide a target namespace URI 107 | and schema location.  All XML documents specified in search location(s) 108 | will be rewritten and the target schemaLocation will be used regardless 109 | of the default namespace of that document.  So for example KML 2.1 documents 110 | can be validated against the 2.2 schema, and vice versa. 111 |

    112 |
    113 |   old: <kml xmlns="http://earth.google.com/kml/2.1">
    114 | 
    115 |   new: <kml xmlns="http://www.opengis.net/kml/2.2"
    116 | 		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    117 | 		xsi:schemaLocation="http://www.opengis.net/kml/2.2 file:/C:/xml/kml22.xsd">
    118 | 
    119 |
  6. 120 |
121 | 122 |

123 | Note that XML is reformatted so errors/warnings with line/column numbers are respect to 124 | the reformatted content not the original so context is printed at that line/column number 125 | after each error in order that errors can be tracked down and corrected in original 126 | XML document.  If you want the reformatted XML document printed then use -dump mode. 127 | If the error is in the XML Schema not the instance document then the context will not be printed. 128 |

129 | 130 |

Contents

131 |

This distribution contains the following files: 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 |
README.htmlThis documentation file
ns.mapNamespace mapping file associated with provided schemas used with -map option
build.gradleGradle build file
146 |

147 | 148 |

Installation

149 |

150 | This standalone Java application requires a Java Runtime Environment (JRE) installation of version 1.6 or later. 151 |

152 |

153 |
154 | Type: ./gradlew clean test install 155 |
156 | Downloaded files (including the Gradle distribution itself) will be stored in the Gradle user home directory (typically "/.gradle"). 157 |

158 |

159 |
160 | XmlValidate is pre-loaded with a number of common XML schemas (KML, GPX). 161 | To install this application, copy the xmlValidate folder along with the batch files 162 | [ bin/kml21.bat + bin/kml22.bat + bin/xv.bat ].  Next edit ns.map file to add new XML schemas to validate 163 | other XML documents. XML Schemas can be added by URL, absolute path, or add to schemas folder and prefix schema with 164 | ${XV_HOME}. 165 |

166 | 167 |

Usage

168 |

169 |

170 | Usage: XmlValidate [options] [-map=file] | [-schema=file (-ns=uri)] <xml-document file, URL, or directory...> 171 |
172 |

173 |

174 | Options: 175 | 176 | 177 | 178 | 181 | 182 | 186 | 187 | 188 | 191 | 192 | 193 | 197 | 198 | 199 | 208 | 209 | 210 | 212 | 213 | 214 | 216 | 217 | 218 | 221 | 222 | 223 | 226 | 227 | 230 | 231 | 234 | 235 | 236 | 237 | 240 | 241 | 242 | 244 | 245 | 246 | 247 | 248 | 249 |
-map=<schema-property-file> Schema map properties: namespace to file/URL mappings.

179 | Note if root element is "kml" and no namespace is specified then KML 2.0 namespace is used. 180 |

-schema=<path-to-xml-schema> Set target schema location (file path or URL).

183 | If validating many XML documents recommend make local copies of XML Schemas and refer to the local 184 | file name rather than having to fetch Schema by URL for each document. 185 |

-schemaLocation=<namespace=location> Add explicit namespace with target schema location (file path or URL).

189 | This will appear in the xsi:schemaLocation element if the target namespace is referenced in the XML document. 190 |

-ns=<schemaLocation-namespace> Set namespace defined in schemaLocation attribute (e.g. http://earth.google.com/kml/2.1)

194 | Without setting this the target schema is assumed to have no namespace and noNamespaceSchemaLocation 195 | attribute is declared in XML instances. 196 |

-dump[=n] 200 | Print reformatted XML documents based on dump level:

201 |  0: no output [default],
202 |  1: print KML on errors only,
203 |  2: print all inputs

204 | If number not specified with -dump argument then 1 is assumed otherwise 0 205 | if -dump argument is not used.
206 | Note the line and column numbers in errors are with respect to these formatted XML documents. 207 |

-maxdump=nSet max length (in bytes) of XML output used for each document in dump. 211 |
-K KML mode for extra KML validation. 215 |
-Z KMZ mode checks and validates all kml files inside KMZ files. 219 | Default mode only checks the first kml file. 220 |
-kml Validate .kml files only (default=xml)

This overrides and replaces 224 | the default XML target with KML when searching for files in directories. 225 |

-kmz Validate .kml and .kmz files only (default=xml)

This overrides and replaces 228 | the default XML target with KML amnd KMZ when searching for files in directories. 229 |

-x=ExtensionList Add additional file extensions to list (default=xml)
232 | extensions separated by ':' (e.g. -x=gpx:x3d:svg) 233 |
-SEnable summary mode to only show the final total counts (default=false).
238 | This is helpful when validating large collection of files where output would be huge. 239 |
Enable verbose mode (default=false). 243 | -v[=true]
-debugEnable debug mode to print exception stack traces (default=false).
250 | 251 | Examples: 252 |

253 |
    254 |
  1. 255 | To check all .kml files against target KML 2.2 schema regardless of default schema used: 256 |
    257 | xv -kml -schema=C:/pathToXsd/kml22.xsd -ns=http://www.opengis.net/kml/2.2  C:/pathToMyKmlFiles 258 |
    259 |
  2. 260 |
  3. 261 | To check all CoT .xml files against CoT Schema: 262 |
    263 | xv -schema=C:/pathToXsd/event.xsd C:/pathToData/cot.xml 264 |
    265 |
  4. 266 |
  5. 267 | To check kml and kmz files against local schemas as defined in KML files: 268 |
    269 | xv -map=ns.map C:/pathToMyKmlFiles 270 |
    271 |
  6. 272 |
  7. 273 | Validate by URL for KML and target schema and print KML content
    274 | if any errors are found but limit size of each file printed to first 4K: 275 |
    276 | xv -dump -maxDump=4096 -ns=http://earth.google.com/kml/2.1 277 |  -schema=http://code.google.com/apis/kml/schema/kml21.xsd 278 |  http://kml-samples.googlecode.com/svn/trunk/kml/kmz/simple/big.kmz 279 |
    280 |
  8. 281 |
  9. 282 | Validate by XML document with explicit schema location
    283 |
    284 | xv -schemaLocation=http://myExtension=ext.xsd example.xml 285 |
    286 |
  10. 287 |
288 |
289 | Note: xv command in examples above is a short-cut to the executable 290 | command using java and XmlValidate.jar on the CLASSPATH or by using the equivalent batch file/shell script. 291 | See xv.bat, kml21.bat, and kml22.bat for example usage. 292 |
293 | 294 |

Release History

295 |

296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 313 | 314 | 315 | 316 | 317 | 318 | 322 | 323 | 324 | 325 | 326 | 327 | 331 | 332 | 333 | 334 | 335 | 336 | 343 | 344 | 345 | 346 | 347 | 348 | 352 | 353 | 354 | 355 | 356 | 357 | 365 | 366 | 367 | 368 | 369 | 370 | 378 | 379 | 380 | 381 | 382 | 383 | 391 | 392 | 393 | 394 | 395 | 396 | 401 | 402 | 403 |
VersionRelease dateDescription
1.0.207/01/14
    307 |
  • Added KmzMode to allow validation of all .kml files inside KMZ files
  • 308 |
  • Add -schemaLocation argument to add individual namespace-to-schema mappings
  • 309 |
  • Update Xerces to 2.11.0
  • 310 |
  • Update JDOM to 2.0.6
  • 311 |
312 |
1.0.111/14/13
    319 |
  • Migrate JDOM from 1.1.3 to 2.0.5
  • 320 |
321 |
1.0.004/27/12
    328 |
  • Public version with minor cleanup and gradle build
  • 329 |
330 |
0.4.203/23/11
    337 |
  • Added summary mode (-S) to suppress printing most details per file
    338 | and dump at end the summary with counts for each error/warning
    339 | including counts for given root element and default namespace. 340 |
  • 341 |
342 |
0.4.108/23/10
    349 |
  • Added assignment of namespace locations to non-root elements in -map mode
  • 350 |
351 |
0.4.003/23/09
    358 |
  • Suppress printing error context for XML Schema errors as opposed 359 | to validation errors in the target XML source.
  • 360 |
  • Added -debug argument
  • 361 |
  • Load all validation targets into list processing after all options are set
  • 362 |
  • If target file does not exist then try to fetch as a URL.
  • 363 |
364 |
0.3.002/13/09
    371 |
  • Added additional namespace locations in schemaLocation if locations defined in map
  • 372 |
  • Added -kml, -kmz and -x options to look for files other than .xml
  • 373 |
  • Added support for KMZ files
  • 374 |
  • Added support to validate URLs
  • 375 |
  • Created README documentation
  • 376 |
377 |
0.2.002/01/09
    384 |
  • Added support for Schema namespaces
  • 385 |
  • Added context in output for errors/warnings
  • 386 |
  • Added -map option
  • 387 |
  • Upgrade JDOM to 1.1
  • 388 |
  • Upgrade Xerces to 2.9.1
  • 389 |
390 |
0.1.004/17/08
    397 |
  • Initial Beta release
  • 398 |
  • Validates target XML documents against target nonSchemaLocation schemas (e.g. CoT)
  • 399 |
400 |
404 |

405 |
406 |
407 |
Author: Jason Mathews
408 | 409 |
410 |
411 |
412 | 413 | 414 | -------------------------------------------------------------------------------- /schemas/kml.xsd: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 394 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | -------------------------------------------------------------------------------- /schemas/atom.xsd: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | The "atom:link" element defines a reference from an 264 | entry or feed to a Web resource. This specification 265 | assigns no 266 | meaning to the content (if any) of this 267 | element. 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | atom:source is used to preserve metadata of a feed 294 | when 295 | an entry is copied from a feed to another feed. 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | The "atom:title" element is a Text construct that 326 | conveys a human- readable title for an entry or feed. 327 | atomTitle = 328 | element atom:title { atomTextConstruct }. 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | The "atom:updated" element is a Date construct 337 | indicating the most recent instant in time when an entry 338 | or feed was 339 | modified in a way the publisher considers 340 | significant. Therefore, not 341 | all modifications 342 | necessarily result in a changed atom:updated value. 343 | atomUpdated = element atom:updated { atomDateConstruct 344 | }. Publishers 345 | MAY change the value of this element over 346 | time. 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 445 | 446 | 447 | -------------------------------------------------------------------------------- /schemas/gpx11.xsd: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | GPX schema version 1.1 - For more information on GPX and this schema, visit http://www.topografix.com/gpx.asp 11 | 12 | GPX uses the following conventions: all coordinates are relative to the WGS84 datum. All measurements are in metric units. 13 | 14 | 15 | 16 | 17 | 18 | 19 | GPX is the root element in the XML file. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | GPX documents contain a metadata header, followed by waypoints, routes, and tracks. You can add your own elements 28 | to the extensions section of the GPX document. 29 | 30 | 31 | 32 | 33 | 34 | 35 | Metadata about the file. 36 | 37 | 38 | 39 | 40 | 41 | 42 | A list of waypoints. 43 | 44 | 45 | 46 | 47 | 48 | 49 | A list of routes. 50 | 51 | 52 | 53 | 54 | 55 | 56 | A list of tracks. 57 | 58 | 59 | 60 | 61 | 62 | 63 | You can add extend GPX by adding your own elements from another schema here. 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | You must include the version number in your GPX document. 73 | 74 | 75 | 76 | 77 | 78 | 79 | You must include the name or URL of the software that created your GPX document. This allows others to 80 | inform the creator of a GPX instance document that fails to validate. 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Information about the GPX file, author, and copyright restrictions goes in the metadata section. Providing rich, 90 | meaningful information about your GPX files allows others to search for and use your GPS data. 91 | 92 | 93 | 94 | 95 | 96 | 97 | The name of the GPX file. 98 | 99 | 100 | 101 | 102 | 103 | 104 | A description of the contents of the GPX file. 105 | 106 | 107 | 108 | 109 | 110 | 111 | The person or organization who created the GPX file. 112 | 113 | 114 | 115 | 116 | 117 | 118 | Copyright and license information governing use of the file. 119 | 120 | 121 | 122 | 123 | 124 | 125 | URLs associated with the location described in the file. 126 | 127 | 128 | 129 | 130 | 131 | 132 | The creation date of the file. 133 | 134 | 135 | 136 | 137 | 138 | 139 | Keywords associated with the file. Search engines or databases can use this information to classify the data. 140 | 141 | 142 | 143 | 144 | 145 | 146 | Minimum and maximum coordinates which describe the extent of the coordinates in the file. 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | You can add extend GPX by adding your own elements from another schema here. 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | wpt represents a waypoint, point of interest, or named feature on a map. 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Elevation (in meters) of the point. 173 | 174 | 175 | 176 | 177 | 178 | 179 | Creation/modification timestamp for element. Date and time in are in Univeral Coordinated Time (UTC), not local time! Conforms to ISO 8601 specification for date/time representation. Fractional seconds are allowed for millisecond timing in tracklogs. 180 | 181 | 182 | 183 | 184 | 185 | 186 | Magnetic variation (in degrees) at the point 187 | 188 | 189 | 190 | 191 | 192 | 193 | Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message. 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | The GPS name of the waypoint. This field will be transferred to and from the GPS. GPX does not place restrictions on the length of this field or the characters contained in it. It is up to the receiving application to validate the field before sending it to the GPS. 203 | 204 | 205 | 206 | 207 | 208 | 209 | GPS waypoint comment. Sent to GPS as comment. 210 | 211 | 212 | 213 | 214 | 215 | 216 | A text description of the element. Holds additional information about the element intended for the user, not the GPS. 217 | 218 | 219 | 220 | 221 | 222 | 223 | Source of data. Included to give user some idea of reliability and accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g. 224 | 225 | 226 | 227 | 228 | 229 | 230 | Link to additional information about the waypoint. 231 | 232 | 233 | 234 | 235 | 236 | 237 | Text of GPS symbol name. For interchange with other programs, use the exact spelling of the symbol as displayed on the GPS. If the GPS abbreviates words, spell them out. 238 | 239 | 240 | 241 | 242 | 243 | 244 | Type (classification) of the waypoint. 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | Type of GPX fix. 254 | 255 | 256 | 257 | 258 | 259 | 260 | Number of satellites used to calculate the GPX fix. 261 | 262 | 263 | 264 | 265 | 266 | 267 | Horizontal dilution of precision. 268 | 269 | 270 | 271 | 272 | 273 | 274 | Vertical dilution of precision. 275 | 276 | 277 | 278 | 279 | 280 | 281 | Position dilution of precision. 282 | 283 | 284 | 285 | 286 | 287 | 288 | Number of seconds since last DGPS update. 289 | 290 | 291 | 292 | 293 | 294 | 295 | ID of DGPS station used in differential correction. 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | You can add extend GPX by adding your own elements from another schema here. 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | The latitude of the point. Decimal degrees, WGS84 datum. 313 | 314 | 315 | 316 | 317 | 318 | 319 | The latitude of the point. Decimal degrees, WGS84 datum. 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination. 329 | 330 | 331 | 332 | 333 | 334 | 335 | GPS name of route. 336 | 337 | 338 | 339 | 340 | 341 | 342 | GPS comment for route. 343 | 344 | 345 | 346 | 347 | 348 | 349 | Text description of route for user. Not sent to GPS. 350 | 351 | 352 | 353 | 354 | 355 | 356 | Source of data. Included to give user some idea of reliability and accuracy of data. 357 | 358 | 359 | 360 | 361 | 362 | 363 | Links to external information about the route. 364 | 365 | 366 | 367 | 368 | 369 | 370 | GPS route number. 371 | 372 | 373 | 374 | 375 | 376 | 377 | Type (classification) of route. 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | You can add extend GPX by adding your own elements from another schema here. 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | A list of route points. 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | trk represents a track - an ordered list of points describing a path. 404 | 405 | 406 | 407 | 408 | 409 | 410 | GPS name of track. 411 | 412 | 413 | 414 | 415 | 416 | 417 | GPS comment for track. 418 | 419 | 420 | 421 | 422 | 423 | 424 | User description of track. 425 | 426 | 427 | 428 | 429 | 430 | 431 | Source of data. Included to give user some idea of reliability and accuracy of data. 432 | 433 | 434 | 435 | 436 | 437 | 438 | Links to external information about track. 439 | 440 | 441 | 442 | 443 | 444 | 445 | GPS track number. 446 | 447 | 448 | 449 | 450 | 451 | 452 | Type (classification) of track. 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | You can add extend GPX by adding your own elements from another schema here. 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | You can add extend GPX by adding your own elements from another schema here. 479 | 480 | 481 | 482 | 483 | 484 | 485 | You can add extend GPX by adding your own elements from another schema here. 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. 496 | 497 | 498 | 499 | 500 | 501 | 502 | A Track Point holds the coordinates, elevation, timestamp, and metadata for a single point in a track. 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | You can add extend GPX by adding your own elements from another schema here. 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | Information about the copyright holder and any license governing use of this file. By linking to an appropriate license, 521 | you may place your data into the public domain or grant additional usage rights. 522 | 523 | 524 | 525 | 526 | 527 | 528 | Year of copyright. 529 | 530 | 531 | 532 | 533 | 534 | 535 | Link to external file containing license text. 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | Copyright holder (TopoSoft, Inc.) 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | A link to an external resource (Web page, digital photo, video clip, etc) with additional information. 553 | 554 | 555 | 556 | 557 | 558 | 559 | Text of hyperlink. 560 | 561 | 562 | 563 | 564 | 565 | 566 | Mime type of content (image/jpeg) 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | URL of hyperlink. 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | An email address. Broken into two parts (id and domain) to help prevent email harvesting. 584 | 585 | 586 | 587 | 588 | 589 | id half of email address (billgates2004) 590 | 591 | 592 | 593 | 594 | 595 | 596 | domain half of email address (hotmail.com) 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | A person or organization. 606 | 607 | 608 | 609 | 610 | 611 | 612 | Name of person or organization. 613 | 614 | 615 | 616 | 617 | 618 | 619 | Email address. 620 | 621 | 622 | 623 | 624 | 625 | 626 | Link to Web site or other external information about person. 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | A geographic point with optional elevation and time. Available for use by other schemas. 637 | 638 | 639 | 640 | 641 | 642 | 643 | The elevation (in meters) of the point. 644 | 645 | 646 | 647 | 648 | 649 | 650 | The time that the point was recorded. 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | The latitude of the point. Decimal degrees, WGS84 datum. 659 | 660 | 661 | 662 | 663 | 664 | 665 | The latitude of the point. Decimal degrees, WGS84 datum. 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | An ordered sequence of points. (for polygons or polylines, e.g.) 675 | 676 | 677 | 678 | 679 | 680 | 681 | Ordered list of geographic points. 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | Two lat/lon pairs defining the extent of an element. 692 | 693 | 694 | 695 | 696 | 697 | The minimum latitude. 698 | 699 | 700 | 701 | 702 | 703 | 704 | The minimum longitude. 705 | 706 | 707 | 708 | 709 | 710 | 711 | The maximum latitude. 712 | 713 | 714 | 715 | 716 | 717 | 718 | The maximum longitude. 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | The latitude of the point. Decimal degrees, WGS84 datum. 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | The longitude of the point. Decimal degrees, WGS84 datum. 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | Used for bearing, heading, course. Units are decimal degrees, true (not magnetic). 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | Type of GPS fix. none means GPS had no fix. To signify "the fix info is unknown, leave out fixType entirely. pps = military signal used 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | Represents a differential GPS station. 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | --------------------------------------------------------------------------------